# 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] <?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] <?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] <?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] <?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] <?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] <?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] <?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] <?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] <?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] <?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] <?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] <?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.