I have been doing a fair amount of research and cannot to find an answer to this seemingly popular question.
I have a domain model that contains some properties-let's say firstName
and lastName
-but in my database I store them as fname
and lname
.
According to the rules of good PoEAA, the model should have no knowledge of how it is stored, if at all. So my question is, where does the mapping of these fields go?
Looking through the source of the existing classes that implement the Zend\Stdlib\Hydrator\AbstractHyrdrator
interface I don't see any of them that offer mapping functionality.
Has anybody seen a clean solution for this that doesn't pollute the model?
UPDATE: Better Simpler Solution
It's been awhile since I asked this question but here would be a very simple solution to map columns to the object without much overhead. Using the built-in naming strategy capabilities of ZF2 the desired affect can be achieved.
<?php
use Zend\Stdlib\Hydrator\NamingStrategy\UnderscoreNamingStrategy;
use Zend\Stdlib\Hydrator\ObjectProperty;
class Person {
public $fname;
public $lastName;
}
class MyNamingStrategy extends UnderscoreNamingStrategy {
protected $map = [
'fname' => 'first_name'
];
public function hydrate($name) {
$map = array_flip($this->map);
if(isset($map[$name])) {
return $map[$name];
}
return lcfirst(parent::hydrate($name));
}
public function extract($name) {
$map = $this->map;
if(isset($map[$name])) {
return $map[$name];
}
return parent::extract($name);
}
}
$p = new Person();
$h = new ObjectProperty();
$h->setNamingStrategy(new MyNamingStrategy());
$h->hydrate([
'first_name' => 'john',
'last_name' => 'Doe'
],$p);
var_dump($p);
var_dump($h->extract($p));
Outputs:
object(Person)[4]
public 'fname' => string 'john' (length=4)
public 'lastName' => string 'Doe' (length=3)
array (size=2)
'first_name' => string 'john' (length=4)
'last_name' => string 'Doe' (length=3)
Using an ORM
I would use any ORM, that allows you to configure the mappings outside of the model classes.
Personally, i like doctrine. I use to map the fields with the database by means of the docbloc annotations since it is easier, but I agree that the information about how the data is stored should not be inside the model. Luckily you have the XML and YAML options for data mapping.
For instance, if you have this Entity en your model:
You can configure this mapping in XML
So, the mappings are in configuration files, so the model itself is not aware of how it is persisted.
You have the DoctrineORMModule module to easily integrate Doctrine into ZF2:
If you don't want to use an ORM
You can create the mappings in the config files. Having that you use the table gateway pattern, after that, you can inject that config to the Table class. I will give you an example adapting the example of the Album module from the ZF2 skeleton application (you can adapt it to your real scenario, i think this is easy than if i have to study your system)
You create the mappings in the module.config.php file. You map the classname to a table, and every field on the class, to a column name
Then, when you configure the service in the Module.php, you send that information to the classes that need them:
Then, you just need to adapt your AlbumTable class, so it receives and uses that mappings.
And the same everywhere a column name was harcoded.
I think you can easily adapt this to your system.