= 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.