Propel is not hard anymore
The two most common criticisms I hear about about Propel are the difficulty to learn the Criteria object, and the amount of code required to do a custom Join. That, and the fact that Propel is slow--but Propel 1.3 will just leave every other ORM behind, so speed is not a good reason to ignore Propel, especially now.
The abilities of Propel are just amazing, but the API is far too Java-inspired for our hectic programming speed. Rapid Application Developers need simple APIs that allow them to go fast in the majority of the cases. That's the philosophy of the sfPropelFinderPlugin, that I already introduced in a past post. This symfony plugin (which doesn't depend on symfony - you can use it with Propel alone, provided you load the Propel classes by hand) recently got better.
No more Criterions
sfPropelFinder encapsulates Criteria calls, so you never need to manipulate the complex Propel syntax. Instead, the plugin proposes a syntax reminiscent of SQL to retrieve Propel objects:
where('Title', 'foo')->
_and('PublishedAt', '<', time())->
_or('Title', 'like', 'bar%')->
find();
If you already tried to do AND and OR queries with Criterion objects, you know how the above can be long and complicated to write. Here, the Propel finder does all the dirty job for you. Another relief is the use of the CamelCase version of the properties names, which is consistent with the Propel object getters. You no longer need to type infamous strings looking like ArticlePeer::PUBLISHED_AT; PublishedAt will do the trick.
Easy joins
Another recent improvement of the finder plugin is its ability to deal with related objects in joins and hydrating. The idea is that you define relationships in the schema, with foreign keys and references, but Propel keeps asking you to repeat them each time you want to join two objects in a Criteria addJoin(). Since you don't like to repeat yourself, sfPropelFinder will quietly check the Propel TableMap to explicit a join if you write:
join('Author')->
where('Author_Name', '<>', 'Joe')->
find();
Wait, there is more. The finder can understand complex joins between several tables. Imagine that an Author has a Status. If you want to get all Posts for the Authors with a given Status, just chain join() calls. You get the speed of ActiveRecord-like syntax with the robustness of Propel code behind.
join('Author')->join('Status')->
where('Status_Name', 'polite')->
find();
Reduce queries, but don't increase code in return
Lastly, if you rely on Propel's generated doSelectJoinXXX() methods to reduce query count, you are probably often frustrated that the method you need is never among the generated ones. And if you ever tried writing such a method yourself, dealing with composite resultsets and complex hydrating, you probably upgraded your database for more raw power instead of pulling your hair off.
Fortunately, sfPropelFinder offers a convenient with() method allowing you to list the objects you want to be hydrated together with the main object. The following code issues only one database query:
with('Author', 'Status', 'Category')->
orderBy('PublishedAt', 'desc')->
find(10);
foreach($postsToRead as $post)
{
echo $post->getTitle(),
$post->getCategory()->getName(), // Post's Category is already hydrated: no query
$post->getAuthor()->getName(), // Post's Author is already hydrated: no query
$post->getAuthor()->getStatus()->getName(); // Author's Status is already hydrated: no query
}
Conclusion
I hope you find this syntax easier to use than Propel's native methods. The sfPropelFinder plugin gets better and better every day thanks to the contributions of several developers, and is already a good alternative to Peer classes and Criteria calls. This should give you time to deal with the more important stuff.
Comments(35)