Guest contribution: PHP AutoMapper

When developing a MVC web application you usually get to the point where you get two equivalent models. On one hand you have the view model, usually an object containing all well-formatted data to show on your web page. And on the other hand you have a model from your data service or repository, containing the data as it is available in your databank. These two models are not identical, but usually very similar.

One example could be a simple blog post: While the title, author and text of your post is identical in both models, a well-formatted date and time differs from the UNIX timestamp or DateTime object, you get from the databank. You might also want to show comma separated tags in one line, while the databank service returns you an array of strings. As a common result you'll have to spend a lot of time and lines of code to map one object to the other, although many if not most properties are not only identical, but usually have the same property name, so you end up writing code like:

$blogpostModel->Title = $blogpostDTO->Title;

Many MVC frameworks simply work around this issue by using one shared model in the databank and the MVC application, but this is a rather dirty approach, since you will get undesired dependencies between two layers, that should be decoupled for obvious reasons. First, you may want to replace your current databank service by a new implementation in the future, most likely because the databank design has changed, e.g. column or table names are different. You would not want to make your MVC application depending on the databank model. Secondly you don't want your databank service to be depending on your MVC application, because every time you change your view model during a re-design, you will have to either change the databank or the service in the middle. Latter will be a real problem if you use the same service for different applications like your CMS which also shows posts, but maybe with a different view model, than your web page.

So if you want to keep both layers independent and maintain a clean architecture of your system, you will end up mapping classes with almost identical properties. In the .NET world there is a nice little library called AutoMapper which allows you to map two objects to each other by following certain conventions and the possibility of adding mapping rules, type converters and value resolvers. Unfortunately there is no such library for PHP for one obvious reason: PHP is not type safe. While type hinting for function arguments is supported lately (at least for arrays, classes and interfaces), the return types however cannot be defined. So how is a PHP based AutoMapper supposed to reflect the correct property types in order to guarantee a safe mapping? You may analyze the source class by reflecting their properties' types, but what about the target class? It is not instanciated and has no values. One rather ugly way could be to initialize all target properties with default values allowing the reflector to analyze their types, but this sounds like a big hack and will waste memory for objects that might be null in the source model.

However there is a solution available lately which comes up with this problem in a rather odd way: It parses the PHPDoc elements for every property. If you are used to document your classes anyway, this is a convention that you can easily meet without further effort. However if not, it is not a big deal to decorate your target properties with each one line of phpDoc code like /** @var DateTime */ or /** @var CommentModel */, to allow the PHP based AutoMapper a successful reflection of the desired property type. Pretty easy huh?

The open source solution PHP AutoMapper gets the job done. It can map your models automaticially by copying all properties with matching type and name automaticially from the source class to the target model. For properties with different names you can specify mapping rules and for different types you are able to provide your own type converters. And if you want to combine several source properties to one target property, you can specify a value resolver to do the dirty work for you. The usage is pretty simple:

//create a mapper instance
$mapper = new \Adminomatic\AutoMapper\Mapper();
//map their property to mine
$mapper->CreateMap('DestinationClass::MyProperty', 'SourceClass::DifferentlyNamedProperty');
//map their property to mine using the given type converter
$mapper->CreateMapUsingConverter('DestinationClass::MyConvertedProperty', 'SourceClass::DifferentlyNamedProperty', new \Adminomatic\AutoMapper\ImplodeConverter());
//map multiple source properties to my single property
$mapper->CreateMapUsingResolver('DestinationClass::MyCombinedProperty', new \CustomResolver());
//map my source object to my destination class
$myDestinationObject = $mapper->Map(new \DestinationClass(), $sourceObject);

You can find more usage examples, an interface documentation and all conventions as well as the free source code under the MIT licence at http://automapper.nylle.de. As far as I know, this is the only available solution for now, so check it out and give it a try if you are tired of mapping your models manually.

Comments (0)

Leave a comment, if you want to!
Marked fields (*) are mandatory.

Will not be published
By ticking this checkbox you agree to the storage of your data by this website. In order to be able to display comments this website stores the specified name, e-mail address, the specified website, the comment text as well as the time stamp. If you wish, you can have your comments deleted later. For detailed information, see my privacy policy.