sfPropelFinder plugin
The sfPropelFinder is a symfony plugin that provides an easy API for finding Propel objects - that is, easier than the Peer methods and the Criteria stuff.
Overview
The idea behind this plugin is to write queries to retrieve Propel objects, but fast. Think of sfPropelFinder as "jQuery for Propel". It also aims at putting the things in the right order, meaning that writing a find() query will feel natural for those familiar with SQL.
<?php
// With Peer and Criteria
$c = new Criteria()
$c->add(ArticlePeer::TITLE, '%world', Criteria::LIKE);
$c->add(ArticlePeer::IS_PUBLISHED, true);
$c->addAscendingOrderByColumn(ArticlePeer::CREATED_AT);
$articles = ArticlePeer::doSelect($c);
// with sfPropelFinder
$articles = sfPropelFinder::from('Article')->whereTitle('like', '%world')->whereIsPublished(true)->orderByCreatedAt()->find();
sfPropelFinder uses the same fluid interface as the sfFinder, so you won't be lost.
You can also implement your own business logic to encapsulate complex queries, so that your queries look like real language:
<?php
$finder = new ArticleFinder();
$articles = $finder->recent()->withComments()->notAnonymous()->wellRated()->find();
Installation
Install the plugin
[sh]
php symfony plugin-install http://plugins.symfony-project.com/sfPropelFinderPlugin
Clear the cache
[sh]
php symfony cc
Usage
Finding objects
<?php
// Finding all Articles
$articles = sfPropelFinder::from('Article')->find();
// Finding 3 Articles
$articles = sfPropelFinder::from('Article')->find(3);
// Finding a single Article
$article = sfPropelFinder::from('Article')->findOne();
Adding WHERE clause
<?php
$articleFinder = sfPropelFinder::from('Article');
// Finding all Articles where title = 'foo'
$articles = $articleFinder->whereTitle('foo')->find();
// Finding all Articles where title like 'foo%'
$articles = $articleFinder->whereTitle('like', 'foo%')->find();
// Finding all Articles where published_at less than time()
$articles = $articleFinder->wherePublishedAt('<', time())->find();
// The whereXXX method accepts simple or composed column names
$articles = $articleFinder->whereArticle_PublishedAt('<', time())->find();
Ordering results
<?php
$articleFinder = sfPropelFinder::from('Article');
// Finding all Articles ordered by created_at ('asc')
$articles = $articleFinder->orderByCreatedAt()->find();
// Finding all Articles ordered by created_at desc
$articles = $articleFinder->orderByCreatedAt('desc')->find();
Counting objects
<?php
// Counting all Articles
$nbArticles = sfPropelFinder::from('Article')->count();
Combining methods
The methods of the sfPropelFinder object return the current finder object, so you can chain them together in a single call, and finish by a find() to launch the query.
<?php
// everything chained together
$articles = sfPropelFinder::from('Article')->whereTitle('like', '%world')->whereIsPublished(true)->orderByCreatedAt()->find();
// You can write it in several lines, too
$articles = sfPropelFinder::from('Article')->
whereTitle('like', '%world')->
whereIsPublished(true)->
orderByCreatedAt()->
find();
The syntax should remind you of sfFinder and sfTestBrowser.
Joins
<?php
$article1 = new Article();
$article1->setTitle('Hello, world!');
$article1->save();
$comment = new Comment();
$comment->setContent('You rock!');
$comment->setArticle($article1);
$comment->save();
// Add a join statement
// No need to tell the finder which columns to use for the join, just the related Class
// After all, the columns of the FK are already defined in the schema
$article = sfPropelFinder::from('Article')->
joinComment()->
whereComment_Content('You rock!')->
findOne();
// You can chain joins if you want to make it more complex
$article2 = new Article();
$article2->setTitle('Hello gain, world!');
$article2->save();
$author1 = new Author();
$author1->setName('John');
$author1->save();
$comment = new Comment();
$comment->setContent('You rock!');
$comment->setArticle($article2);
$comment->setAuthor($author1);
$comment->save();
$article = sfPropelFinder::from('Article')->
joinComment()->
joinAuthor()->
whereAuthor_Name('John')->
findOne();
Deleting objects
<?php
// Deleting all Articles
$nbArticles = sfPropelFinder::from('Article')->delete();
// Deleting a selection of Articles
$nbArticles = sfPropelFinder::from('Article')->whereTitle('like', 'foo%')->delete();
Writing your own business logic into a finder
You can create a new finder for your objects, with custom methods. The only prerequisites are to extend sfPropelFinder and to define a protected $peerClass property. Then, the object has access to a protected $criteria property, which is a Propel Criteria that can be augmented in the usual way. Don't forget to return the current object ($this) in the new methods.
For instance, to add a recent() method to an article finder:
<?php
class ArticleFinder extends sfPropelFinder
{
protected $peerClass = 'ArticlePeer';
public function recent()
{
$this->criteria->add(
ArticlePeer::CREATED_AT,
time() - sfConfig::get('app_recent_days', 5) * 24 * 60 * 60,
Criteria::GREATER_THAN
);
return $this;
}
}
Hacking the finder
If the finder doesn't (yet) provide the method to build the query you need, you can still call Criteria methods on the finder objects, and they will be applied to the finder's internal Criteria object.
<?php
$articles = sfPropelFinder::from('Article')->
whereTitle('like', 'foo%')->
addOr(ArticlePeer::TITLE, 'bar%', Criteria::LIKE)-> // that's a Criteria method
findOne();
If you're not sure about what query is issued by the finder, you can always check the SQL code after executing a termination method (find(), findOne(), findPk(), count(), delete()) by calling the getLatestQuery() method.
<?php
$finder = sfPropelFinder::from('Article')->whereTitle('foo');
$finder->findOne();
$query = $finder->getLatestQuery();
// 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID FROM article WHERE article.TITLE=\'foo\' LIMIT 1'
TODO
- Allow hydrating of related objects (doSelectJoinXXX equivalent)
- Add And
- Add Or
- Put as a parent class in the PeerBuilder so that every Peer class can be a finder
- Merge with sfPropelImpersonatorPlugin!
Changelog
2008-03-28 | 0.2.0 Beta
- francois: Added support for Criteria methods (no more limit to what you can do with a finder!)
- francois: Added
sfPropelFinder::getLatestQuery() method
- francois: Added
sfPropelFinder::delete() method
- francois: Added
sfPropelFinder::joinXXX() method
- francois: Added
sfPropelFinder::join() method
- francois: Added complete
whereClassName_ColumnName() syntax
- francois: Added
sfPropelFinder::count() method
2008-03-27 | 0.1.0 Alpha
- francois: Initial public release.