The best PHP ORM libraries, Doctrine and Propel. Last year I compared them to each other, and now it’s time to get a fresh look at how they have advanced in about a year – Is Doctrine still the better of the two?
This time, I’ll also look at the features of each in more depth.
Features
As mentioned in the earlier post, both Doctrine and Propel have quite similar basic feature set: They support all the usual CRUD operations you would expect, from creating new records to updating old ones.
Both can generate the model class PHP code for you, Propel based on XML and Doctrine based on YAML. Both support generating their respective markup from an existing database, though not to 100% accuracy – some more DB-specific and specialized things may not get cloned into the markup.
Advanced features
Both libraries support storing tree structures in the database using the nested set model. Doctrine’s nested set implementation supports storing multiple trees in the same table instead of just one.
Both also support validation of the data in the models and relations between models.
They also support single table inheritance, although in Doctrine this is known as concrete inheritance. Doctrine supports two other inheritance models: Simple, where all classes have the same columns, and column aggregation, which stores an additional type value in the table, allowing automatic instanciation of the correct model type when querying.
And here ends the shared features. All of the following things are features that only Doctrine has.
Behaviors: Doctrine supports applying various “behaviors” to your models, for example a Timestampable model automatically gets two columns: created_at and updated_at, which get a time when a row is first created and when it’s updated respectively.
Searching: Doctrine has a custom fulltext search engine.
Data fixtures and migrations. Caching, events, pagination, command line interface… you might say that Doctrine beats Propel hands down when it comes to more advanced features.
Ease of use
Documentation
The first thing is of course the documentation. Without decent documentation it’ll be difficult to use any library. Last year, Propel’s documentation was one of the main problems with it – and it still hasn’t gotten any better.
On the opposing side, the Doctrine team has been constantly improving their already superior documentation, and they are even working on a paperback Doctrine book. Documentation is a clear win for Doctrine.
Using the libraries
The first task you will have with both of the libraries is creating the model classes. Doctrine allows you to write simple YAML markup, or straight PHP code if you prefer it that way. If you use YAML, Doctrine has some methods that you can call in your own code, or you can download a command-line interface for building your models.
Propel’s approach to creating models requires you to write XML. To build your models from XML, you also need Phing. Personally I find XML more complex to write by hand than YAML, and requiring additional libraries is a bit of a hassle, unless you already use Phing for something else such as build automation.
Database operations
Basic CRUD operations are quite similar in both. However, there’s a big difference in the way more precise queries are done.
Propel uses a criteria/peer approach:
$c = new Criteria(); $c->add(ExamplePeer::ID, 20); //SELECT all "Example" models which have 20 as their ID and join all foreign tables. $items = ExamplePeer::doSelectJoinFoobar($c); |
Doctrine’s approach is to use Doctrine_Query and a custom SQL dialect, DQL:
$items = Doctrine_Query::create() ->from('Example e') ->leftJoin('e.Foobar') ->where('e.id = ?', 20) ->execute(); |
I think Doctrine’s approach lends itself better to the purprose. The code is also easier to read, as it flows more naturally. Propel’s version does take a bit less code.
Setting values on model classes is also a bit different: Doctrine uses magic properties, while Propel generates methods for setting and getting values. This gives Propel code the advantage of autocompletion in more IDE’s – as far as I know, only the latest versions of NetBeans can autocomplete Doctrine’s magic properties, thanks to their support of the @property PHPDoc annotation.
Conclusion
No matter how you look at it, Doctrine is better. Better docs, better features, and the community is active. Propel has gone forwards, but Doctrine has been going forwards at a much faster pace.