PHP: 5-layer model

I have a question about how to write my application correctly.

I would like to follow the / DAO / mapper / entity service model, and I think I fully understand it, but I found out that some of the things I want to do may run into the general concept of this model.

I have these database tables: Product table and it's related table - manufacturers

I have a simple ProductDbMapper that retrieves product data from a database and returns it as a Product object, so I can use it like this:

echo $productEntity->getName(); $productEntity->setPrice(29.9); 

I think it would be great to use something like this:

 echo $productEntity->getManufacturer()->getName(); 

The getManufacturer () method will simply request another service / DAO for the manufacturer by identifier. I know the correct way to get the product manufacturer:

 $product = $productService->getProduct(5); $manufacturer = $manufacturerService->getManufacturerByProduct($product); 

But I think the β€œfree” solution is much simpler - easy to understand and fun to use. This is actually quite natural. I tried to implement this by callbacks. I passed a callback that calls the manufacturer service for the Product object in my ProductMapper.

The problem is that it looks like I'm trying to follow a five-layer model, and at the same time I'm trying to avoid it. So my question is: does this seem like a good solution? Does this make sense? How could I achieve the same (magic) better?

+4
source share
3 answers

I have been doing some research for several days, and I have come to the conclusion that the best way to achieve what I want is to stop trying to code it myself and just learn to use the existing ORM. Because all I tried to do was create my own ORM. And I know this is a bad idea. I will adhere to Doctrine 2.

+3
source

If you want to adhere to the Data Mapper template, you can either download the product from the database with all its dependencies (manufacturer, fund, tax), or use lazy loading. The first option is not good practice. But to use lazy loading, you will need an additional layer obtained through a virtual proxy.

Why? Because otherwise, you will need to put some database code inside your entity, and the whole idea of ​​these layers will be untied.

So what is a virtual proxy?

According to Martin Fowler (2003):

A virtual proxy is an object that looks like an object that should be in a field, but actually contains nothing. Only when one of its methods is called does it load the correct object from the database.

Example

The interface defines the methods that will be implemented by real entities and virtual proxies:

 // The interface interface ManufacturerInterface { public function getName(); } 

This is an entity; you are probably also extending some general model class:

 // The concrete Manufacturer class class Manufacturer implements ManufacturerInterface { private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } 

And this is a proxy:

 // The proxy class ManufacturerProxy implements ManufacturerInterface { private $dao; private $manufacturer; private $manufacturerId; public function __construct($dao, $manufacturerId) { $this->dao = $dao; // set manufacturer to NULL to indicate we haven't loaded yet $this->manufacturer = null; } public function getName() { if ($this->manufacturer === null) { $this->lazyLoad(); } return $this->manufacturer->getName(); } private function lazyLoad() { $this->manufacturer = $this->dao->getById($this->manufacturerId); } } 

The proxy will be used by the Data Mapper when creating instances of other classes with some relationships with the manufacturer, such as Product. Thus, when creating a product instance, the fields are filled, and the producer field receives an instance of ManufacturerProxy instead of the manufacturer.

The implementation of the Data Mapper will be different, so I will give a simple example:

 class ProductMapper { private $dao; private $manufacturerDao; // ....... public function find($id) { // call the DAO to fetch the product from database (or other source) // returns an associative array $product = $this->dao->find($id); // instantiate the class with the associative array $obj = new Product($product); // create the virtual proxy $obj->manufacturer = new ManufacturerProxy($this->manufacturerDao, $product['manufacturer_id']); return $obj; } } 

As I said, the above example is very simple. I turned on the DAO when you use it, but authors like Martin Fowler set the task of processing SQL queries or any other underlying technology for the Data Mapper. But there are authors like Nock (2004) who use both the Data Mapper and the Data Accessor.

With the more sophisticated Data Mapper, you can only have files in a language such as XML or YAML, similar to Doctrine or Hibernate.

Just to finish, the service:

 class ProductService { private $productMapper; /** * Execute some service * @param {int} $productId The id of the product */ public function someService($producId) { // get the product from the database // in this case the mapper is handling the DAO // maybe the data mapper shouldn't be aware of the DAO $product = $this->productMapper->find($productId); // now the manufacturer has been loaded from the database $manufacturerName = $product->manufacturer->getName(); } } 

Perhaps you could make the DAO a call to the Data Mapper to create entities, and then use the DAO in the Service. This is actually simpler because you do not need to repeat the methods twice, but it is up to you.

Alternative

If you do not want to implement a virtual proxy server and want to freely own the interface, you can go to the Active Record template. There are some libraries that can do this work, such as PHP-ActiveRecord and Paris . Or, if you want to do it yourself, you can look here and here . Martin Fowler's book is also a good start.

References

FOWLER, Martin. Enterprise application architecture templates . Addison-Wesley, 2003. NOCK, CLIFTON. Data access patterns: interacting with databases in object-oriented applications . Addison-Wesley 2004.

+9
source

Do not get me wrong, I do not want to be a critic. Why don't you join these two tables and then add only one class? So you will have $this->manufacturer_name = $row['name'] . And for other series of manufacturers.

+1
source

All Articles