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:
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; public function someService($producId) {
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.