Doctrine proposal: Entity and ValueObject - The Ossigeno Blog - Powered by Ossigeno 3.0_rc1

Posted by giorgio
On Jun 18, 2009 9:58:56 AM
Doctrine is growing and the 2.x branch will support persistence ignorance for domain classes. But to start doing some Domain-Driven Design more metadata is needed.
Doctrine is a powerful Orm written in php, the default one in Symfony and it is often integrated with Zend Framework in many applications. Strength of Doctrine resided in letting you write a model of your models and relationships in yaml or php, while totally database independent, even in the aspect of building queries and writing data fixtures.
From the Doctrine 2.x branch, that requires Php 5.3 (that is now on RC), the pattern UnitOfWork is correctly implemented and also model classes don't extend a base one (it was Doctrine_Record). Persistence ignorance is the concept of having the domain classes (the User, PhoneNumber, Group, and so on, ones) not depending on framework or database abstraction layer components.

DDD to the resque
This concept is the core of Domain-Driven Design, an approach to build very complex enterprise applications: the persistence ignorance allows you to test very complex logic on the domain object (like an User with ten methods that computes data basing on his internal fields) without touching the database. It is the persistence layer that is dependent on the domain objects, and has to find a way to saving them anywhere (DataMapper and Repository patterns). Orms persist these objects in a relational database and can be a component of a Repository. Doctrine 2.0 could be a DataMapper.
DDD is hard: difficult to learn and to implement in an application, but basic concepts can help a developer allowing him to build a low coupled object graph and I think Doctrine should support some DDD patterns. This can attract php developers to Doctrine, and not only who uses an Orm to lessen his work, but also who wants to develop clean applications and Test-Driven Development, or who has internalized SOLID principles and is in the mood of writing cohesive and decoupled code.
Php lacks a DataMapper implementation that has the following of Doctrine and the features it offers.

My proposal
What I'd like to include in Doctrine are something which in the 1.x branch would be Doctrine_Template subclasses, also known as behaviors (the actAs option of yaml modelling). This template could be named Entity, ValueObject and Aggregate, in a DDD fashion. They would influence the behavior of data persistence and retrievel, for example let's say that Group actAs an Entity and PhoneNumber actAs a ValueObject; given that user has some relations to them, its array representation could be:
User [
    name => Giorgio,
    PhoneNumbers => [
        [0] => [ value => 5551234],
        [1] => [ value => 5557890],
    Group => 23     // group id
Thinking of php environment (web pages but also cli), marking with high-level concepts the models with these behaviors (and also options if needed) will given the introspection to:
  • generate forms for editing on the fly where ValueObjects are edited in place (for instance with input elements with name like Phonenumbers[0][value]), while Entities are represented with single and multiple selects, since the former have no identity and can be interchanged, while the latter have many data that cannot be included every time and a strong identity (as a user you insert your phonenumber but choose the group to belong to). This would not be the job of Doctrine but it can be accomplished with Zend_Form and other framework that works on the html side.
  • these forms would validate a POST request basing on the doctrine model, thus keeping the validation rules in one place (the domain) and not building javascript and php validation rules which mirror the domain ones.
  • Aggregate elements could have default hydration rules to include all children elements. More precisely, elements which are roots of aggregates: that means they are like the User of this example. You certainly want a Repository for User instances but not for searching single PhoneNumbers, that have only a value field.
  • Aggregates can also simplify relations jungle, since it is not necessary for PhoneNumber to know which user owns them. The User aggregate is taking care on which user PhoneNumbers are.
These are only examples of what can be done with standard metadata behaviors in Doctrine. As far as I know in Symfony forms can be generated so there is already an approach that could be followed. In my cms, Ossigeno, I have implemented scaffolding using templates like these to label my domain classes.
I can work on 2.x branch and I'm proposing these additions to make a bit of DDD possible in Php without losing the capabilities of a general Orm layer (and have to write a custom one). Evaluate this chance.