Doctrine vs. Propel

Tags:

An updated version of this post is available: Doctrine vs. Propel 2009 update

The two most well known ORM frameworks for PHP right now are probably Propel and Doctrine.

A lot of people are probably wondering which one should they choose for their project, just like I was. I’ve used Propel for a while, and now I decided to give Doctrine a shot.

Is Doctrine better, or will Propel propel you faster?

Features

Both frameworks sport very similar features. Starting from generating models, they can both generate the classes from your database or from markup. Doctrine also supports defining the model classes in straight PHP.

Either supports various DB operations, from selects to deletes, and can fetch related rows based on foreign keys. Propel is somewhat limited in some JOIN scenarios, though, such as joining the same table twice. Doctrine supports this and otherwise a wider array of JOINs than Propel.

They also support various database engines.

We can say that both frameworks are almost equal when it comes to features. Doctrine has some advanced features like table inheritance that isn’t in Propel, though.

Usability

Starting from the beginning, the installation/configuration:

Propel needs tons of configuration – Doctrine barely a line or two of PHP code.

To get Propel up and running, you have to write config files for the DB, and if you’re using schema files, you will also have to set up the build process with phing.

Doctrine on the other hand is very easy to get running: With model generation from the DB, you only need a PHP script which connects it to a DB and calls Doctrine::generateModelsFromDb and you’re done. You may need to define table relations in PHP, though, but it’s relatively simple. With schema files, you can define it all in the markup.

Database operations

In Propel, operations are done using the actual model classes and the model’s peer classes. If you want to perform more specific SELECTs or such, you will also need to use the Criteria class:

$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 uses mostly the Doctrine_* classes and DQL for performing database ops.
For example, the above in Doctrine…

$items = Doctrine_Query::create()
       ->from('Example e')
       ->leftJoin('e.Foobar')
       ->where('e.id = ?', 20)
       ->execute();

I’m probably the last person you’d expect to praise this kind of fluent style, but I have to admit that it’s much nicer than Propel’s method. Especially more complicated WHERE-clauses can be very tedious to write in Propel Criterias. You may think that DQL is a bit pointless, but I’ve found out that it actually is a quite nice way of making various operations more intuitive to write, compared to having to type multiple method calls for example.

Creating new rows is pretty much the same in both:

//Propel style
$row = new Example();
$row->setName('Hello');
$row->setOther('World');
$row->save();
 
//Doctrine style
$row = new Example()
$row->name = 'Hello';
$row->other = 'World';
$row->save();

The style Propel uses has a small advantage. Doctrine doesn’t store the variables in the model classes, so you won’t get any autocompletion at all for them. This can be annoying if you don’t remember the name of a column in your DB.

Conclusion

I sadly don’t have any performance figures for these two, but from what I’ve heard, they are about as equally fast, so that should not be a criteria in favoring either.

Currently, it seems that Doctrine would be the way to go. It has some minor issues, such as the autocompletion for columns, and that it will not singularize table names for models when generating from the DB, but that is easy to fix with a small change to the code. I also heard that the singularization thing will be fixed in a future release.

Does Propel really have any advantages? I really can’t think of any. It’s annoying to set up and poorly documented. Other than that, it is not very far from Doctrine feature-wise. It does have some issues in joining multiple tables, but the team is working on it.

At this time, I would definitely go with Doctrine. It is much nicer to live with, and the community around it seems much more active, so if you need help, it’s easier to get. Not to mention that the manual is actually full of useful information, unlike Propel’s.

More on Doctrine:
Understanding Doctrine’s NestedSet feature
Optimizing Zend Framework and Doctrine applications