Wednesday, November 11, 2009

What's going on with php object-relational mappers

Every once in a while, in a post, I say:
The Domain Model should not depend on anything else; it is the core of an application. Classes should not extend or implement anything extraneous. I do not want User extends Doctrine_Record. I want User.
Sorry to stress you, but this is one of the points of DDD and the one that gives advantages even applied in other architectures. The persistence problem can be solved by generic object-relational mappers which will act as the bridge between entities and the database used for persistence. But where do we find a generic Orm?

In php, no real generic Orms existed until 2009, since Zend_Db, Doctrine 1, Propel etc. are all implementations of the Active Record (or similar data gateway) pattern, requiring for example all your User and Post classes to subclass a base record. The only way to obtain a persistence-agnostic model was manual implementation of all the mapper classes, which translate between database rows and object graphs. When you are managing more than a few different entity classes the problem become quickly intractable.
The Data Mapper pattern describes exactly a generic Orm, but it is an even more general concept in the sense that the mapping is not limited to a relational database like MySql or Sql Server. You can write a Data Mapper to store your objects in plain text files or document-oriented databases if you want.

In the last summer, I encountered two in-development solutions to solve the persistence agnosticism problem: Doctrine 2 and Zend_Entity. They are implementations of the Data Mapper pattern, with reference to the Jpa specification and a similar Api. I learned that the Java guys had implemented a real Data Mapper years ago: Hibernate. Jpa is only a specification extracted as a subset of Hibernate, and it is an additional layer abstraction that decouples your mapping code (annotations or xml files) from the particular Orm.
Anyway, I contributed to the lazy loading capabilities of Doctrine 2 with php code and to Zend_Entity with some small patches before its discontinuance. I am currently waiting for a stable version of Doctrine 2 to integrate it in NakedPhp, only because I am not worrying about persistence for now. It is the power of the Data Mapper approach that decouples my work from a specific storage such as a relational database.
Fast forward to today, and Doctrine 2 is in alpha for being thoroughly tested. Zend_Entity has been dropped instead, in favor of Doctrine 2 integration in the Zend Framework. It is not useful to maintain two different code bases, with the same Api transposed from Jpa, which do the same persistence-related dirty work and developed by the same people. It's just a waste of the contributor's time.

Thus, Doctrine 2 is going to become the first production-ready Orm for php and to be favored with seamless integration in both Zend Framework and Symfony. If you have not yet tried it, you may want to give it a shot.
If you feel like helping with the integration, which involves Zend_Tool components for generation and Zend_Application resources, join the zf-doctrine mailing list. The integration also comprehends Doctrine 1 since Doctrine 2 requires php 5.3 and its adoption by hosting companies will be gradual.
The adoption of the 2.x branch, when ready, would give your design the freedom from the database you want. Doctrine 2 is for php the greatest thing since sliced bread.

8 comments:

Unknown said...

Thanks for the kudos :)

It should be noted, however, that ActiveRecord is far from useless. It can work very well for many simple applications where the domain model does not require any reuse and is pretty simple anyway. ActiveRecord works for many applications. Just not when you want a reusable, easily testable and persistence-independant domain model.

Needless to say I prefer data mappers but it just has to be said that there is no "one true way" for object persistence. Just many different options.

While we're at it, we do have plans for an object-document mapping approach with a very similar API to the Doctrine 2 ORM, the same different mapping options (annotations, xml, yaml, ...) etc.

If you or anyone else is interested in contributing, let us (the Doctrine guys) know.

Giorgio said...

I have experienced many Active Record applications where, sooner or later, classes started to incorporate logic that should be tested. :)
I am not much experienced with document-oriented database but it's in my interest to continue contributing to Doctrine 2 in the future.

Sudheer said...

Fantastic explanation, Giorgio.

I am really looking forward for mainstream PHP 5.3 and Doctrine 2.0 adoption. I am not worried about server infrastructure since I host my applications on own servers. But I would like to use Zend Framework and few libraries that aren't fully tested with PHP 5.3 yet.

On my watch list the top items are
1. Zend Framework 2.0
2. PEAR 2.0
3. Doctrine 2.0

Giorgio said...

Very web 2.0 list :)
However, Doctrine 2 and Pear 2 are in alpha, while ZF 2 does not exist yet.

rvdavid said...

Noted Giorgio. Thanks for posting. I'm downloading Doctrine 2.0 now - great to hear that Doctrine 2 integration is at hand with zf.

Adam said...

Have you looked at Torpor PHP? It's new project that seems to share similar concepts. Author describes this project in last PHP Abstract Podcast.

Giorgio said...

I looked at Torpor, but it seems that it does not implement a DataMapper pattern but dynamic Active Records and a lot of magic.

Unknown said...

In php, no real generic Orms existed until 2009

Actually, after quick research I've found two PHP projects implementing data mapper pattern (at least naming this pattern):
phpDataMapper
Rapid Data Mapper

Additionally I'm not sure about frameworks incorporating theirs own ORM layers, maybe there are some using Data Mapper as well? The only one I spotted is Data Mapper plugin for CodeIgniter.

Haven't checked if they're good or not, just wanted to mention those for completeness.

ShareThis