Development

Changeset 10540

You must first sign up to be able to contribute.

Changeset 10540

Show
Ignore:
Timestamp:
07/31/08 15:22:53 (4 months ago)
Author:
francois
Message:

sfPropelFinderPlugin Implemented DbFinder::toArray(), DbFinder::__toString() and DbFinder::toHtml()

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • plugins/sfPropelFinderPlugin/README

    r10344 r10540  
    7070}}} 
    7171 
     72''Tip'': When developing with the finder, you may prefer to have an array or string representation of the results rather than an array of objects. The finder objects provides three methods (`toArray()`, `__toString()` and `toHtml()`) that internally execute a `find()` and return something that you can output in your response. 
     73 
    7274=== Adding WHERE clause === 
    7375 
     
    178180Compare it to the code required to get these `Comment` objects without `sfPropelFinder`, and you will understand all the benefits the `relatedTo()` method provide. 
    179181 
    180 Tip: Alternatively, a finder can be initialized from an array of Propel object. The resulting SQL query contains a 'IN ()' clause, so use this possibility with caution. 
     182''Tip'': Alternatively, a finder can be initialized from an array of Propel object. The resulting SQL query contains a 'IN ()' clause, so use this possibility with caution. 
    181183 
    182184{{{ 
     
    591593 
    592594 * Allow i18n hydration of related objects (#3897) 
     595 * Allow `between` as a `where()` operator for simplicity 
     596 * Add a method returning a description of the conditions 
     597 * Add support for `withColumn()` in array/text output methods 
     598 * Bypass hydration in array/text output methods 
    593599 * Handle self-referencing relationships (e.g. parent_id), especially in with() 
    594600 * Handle multiple references to the same table (c.f. getFooRelatedByBarId()) 
    595601 * Put as a parent class in the PeerBuilder so that every Peer class can be a finder 
    596602 * Merge with sfPropelImpersonatorPlugin! 
    597  * Add a `__toString()` method which returns a var_export() of the results, or a description of the conditions if not yet executed 
    598603 * Implement iterator interface? That way, the query is only executed upon a foreach or an array access... And the finder can be seen as a collection 
    599604 * Column finder, which provides an easy interface to Creole (and PDO) for retrieval of columns instead of objects? 
     
    601606== Changelog == 
    602607 
    603 === 2008-07-17 | Trunk === 
    604  
     608=== 2008-07-31 | Trunk === 
     609 
     610 * francois: Implemented `DbFinder::toArray()`, `DbFinder::__toString()` and `DbFinder::toHtml()` 
    605611 * francois: Implemented `sfDoctrineFinder::findBy()`, `findOneBy()`, `findPk()`, and initialized `where()` 
    606612 * francois: Added preliminary support for table aliases (`from('Article a')`) in Doctrine and Propel finders 
  • plugins/sfPropelFinderPlugin/lib/DbFinder.php

    r10344 r10540  
    196196    return array($class, $alias); 
    197197  } 
     198   
     199  // Finder Outputters 
     200   
     201  /** 
     202   * Array outputter 
     203   * Executes the finder and returns an array of results 
     204   * Each result being an associative array 
     205   * TODO: Bypass hydration for better performance 
     206   * 
     207   * @param $limit Integer Optional number of results to return 
     208   * 
     209   * @return Array the list of results as arrays 
     210   */ 
     211  public function toArray($limit = null) 
     212  { 
     213    $objects = $this->find($limit); 
     214    $res = array(); 
     215    foreach($objects as $object) 
     216    { 
     217      $res []= $object->toArray(); 
     218    } 
     219     
     220    return $res; 
     221  } 
     222 
     223  /** 
     224   * String outputter 
     225   * Executes the finder and returns a string (incidentally, YAML compliant) 
     226   * TODO: Bypass hydration for better performance 
     227   * 
     228   * @param $limit Integer Optional number of results to return 
     229   * 
     230   * @return String the list of results as YAML 
     231   */ 
     232  public function __toString($limit = null) 
     233  { 
     234    $objects = $this->find($limit); 
     235    $res = ''; 
     236    $i = 0; 
     237    foreach($objects as $object) 
     238    { 
     239      $res .= sprintf("%s_%d:\n", get_class($object), $i); 
     240      foreach ($object->toArray() as $key => $value) 
     241      { 
     242        $res .= sprintf("  %-10s %s\n", $key . ':', $value); 
     243      } 
     244      $i++; 
     245    } 
     246     
     247    return $res; 
     248  } 
     249   
     250  /** 
     251   * HTML outputter 
     252   * Executes the finder and returns a HTML table 
     253   * TODO: Bypass hydration for better performance 
     254   * 
     255   * @param $limit Integer Optional number of results to return 
     256   * 
     257   * @return String the list of results as an HTML table 
     258   */ 
     259  public function toHtml($limit = null) 
     260  { 
     261    $objects = $this->find($limit); 
     262    $res = "<table class=\"DbFinder\">\n"; 
     263    $isFirstLine = true; 
     264    foreach($objects as $object) 
     265    { 
     266      if($isFirstLine) 
     267      { 
     268        $res .= "  <tr>\n"; 
     269        foreach ($object->toArray() as $key => $value) 
     270        { 
     271          $res .= sprintf("    <th>%s</th>\n", $key); 
     272        } 
     273        $res .= "  </tr>\n"; 
     274      } 
     275      $res .= "  <tr>\n"; 
     276      foreach ($object->toArray() as $value) 
     277      { 
     278        $res .= sprintf("    <td>%s</td>\n", $value); 
     279      } 
     280      $res .= "  </tr>\n"; 
     281      $isFirstLine = false; 
     282    } 
     283    $res .= "</table>\n"; 
     284     
     285    return $res; 
     286  } 
    198287} 
  • plugins/sfPropelFinderPlugin/test/unit/DbFinderTest.php

    r10344 r10540  
    6161ArticlePeer::doDeleteAll(); 
    6262 
    63 $t = new lime_test(4, new lime_output_color()); 
     63$t = new lime_test(7, new lime_output_color()); 
    6464 
    6565$t->diag('from()'); 
     
    8282$t->isa_ok($finder, 'sfPropelFinder', 'from() called with a Propel class name returns a sfPropelFinder'); 
    8383$t->ok($article instanceof BaseObject, 'A DbFinder initialized from a Propel class returns BaseObject objects'); 
     84 
     85$finderAsArray = DbFinder::from('Article')->toArray(); 
     86$t->is_deeply($finderAsArray, array(array('Id' => 1, 'Title' => 'foo', 'CategoryId' => null)), 'toArray() executes the finder and returns an array with column phpNames as keys'); 
     87 
     88$finderAsString = (string) DbFinder::from('Article'); 
     89$expected = <<<FOO 
     90Article_0: 
     91  Id:        1 
     92  Title:     foo 
     93  CategoryId:  
     94 
     95FOO; 
     96$t->is($finderAsString, $expected, '__toString() executes the finder and returns a string with column phpNames as keys'); 
     97 
     98$finderAsHtml = DbFinder::from('Article')->toHtml(); 
     99$expected = <<<FOO 
     100<table class="DbFinder"> 
     101  <tr> 
     102    <th>Id</th> 
     103    <th>Title</th> 
     104    <th>CategoryId</th> 
     105  </tr> 
     106  <tr> 
     107    <td>1</td> 
     108    <td>foo</td> 
     109    <td></td> 
     110  </tr> 
     111</table> 
     112 
     113FOO; 
     114$t->is($finderAsHtml, $expected, 'toHTML() executes the finder and returns a string with an HTML table with column phpNames as column headers'); 
     115 
  • plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderRelationsTest.php

    r10342 r10540  
    297297$article1->setCategory($category1); 
    298298$article1->save(); 
    299 $sql = 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM article, category WHERE article.CATEGORY_ID=category.ID LIMIT 1'; 
     299$sql = 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM article, category WHERE article.CATEGORY_ID=category.ID LIMIT 1'; 
    300300$finder = sfPropelFinder::from('Article')->join('Category')->with('Category'); 
    301301$article = $finder->findOne(); 
     
    328328$finder = sfPropelFinder::from('Comment')->with('Article')->with('Author'); 
    329329$comment = $finder->findOne(); 
    330 $sql = 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, author.ID, author.NAME FROM comment, article, author WHERE comment.ARTICLE_ID=article.ID AND comment.AUTHOR_ID=author.ID LIMIT 1'; 
     330$sql = 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.TITLE, article.CATEGORY_ID, author.ID, author.NAME FROM comment, article, author WHERE comment.ARTICLE_ID=article.ID AND comment.AUTHOR_ID=author.ID LIMIT 1'; 
    331331$t->is($finder->getLatestQuery(), $sql, 'you can call with() several times to hydrate more than one related object'); 
    332332$t->is($comment->getContent(), 'foo', 'you can call with() several times to hydrate more than one related object'); 
     
    337337$finder = sfPropelFinder::from('Comment')->with('Article')->with('Category'); 
    338338$comment = $finder->findOne(); 
    339 $t->is($finder->getLatestQuery(), 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM comment, article, category WHERE comment.ARTICLE_ID=article.ID AND article.CATEGORY_ID=category.ID LIMIT 1', 'with() can even hydrate related objects via a related object'); 
     339$t->is($finder->getLatestQuery(), 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM comment, article, category WHERE comment.ARTICLE_ID=article.ID AND article.CATEGORY_ID=category.ID LIMIT 1', 'with() can even hydrate related objects via a related object'); 
    340340 
    341341$finder = sfPropelFinder::from('Comment')->with('Article', 'Category'); 
    342342$comment = $finder->findOne(); 
    343 $t->is($finder->getLatestQuery(), 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM comment, article, category WHERE comment.ARTICLE_ID=article.ID AND article.CATEGORY_ID=category.ID LIMIT 1', 'with() accepts several arguments, so you don\'t need to call it several times'); 
     343$t->is($finder->getLatestQuery(), 'SELECT comment.ID, comment.CONTENT, comment.ARTICLE_ID, comment.AUTHOR_ID, article.ID, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM comment, article, category WHERE comment.ARTICLE_ID=article.ID AND article.CATEGORY_ID=category.ID LIMIT 1', 'with() accepts several arguments, so you don\'t need to call it several times'); 
    344344 
    345345$t->diag('withI18n()'); 
     
    359359$article = $finder->findOne(); 
    360360$query = $finder->getLatestQuery(); 
    361 $t->is($query, 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'withI18n() hydrates the related I18n object with a culture taken from the user object'); 
     361$t->is($query, 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'withI18n() hydrates the related I18n object with a culture taken from the user object'); 
    362362$t->is($article->getContent(), 'english content', 'withI18n() considers the current user culture for hydration'); 
    363363$t->is(Propel::getConnection()->getLastExecutedQuery(), $query, 'withI18n() hydrates the i18n object so that no further query is necessary'); 
     
    367367$article = $finder->findOne(); 
    368368 
    369 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'fr\' AND article.ID=article_i18n.ID LIMIT 1', 'withI18n() hydrates the related I18n object with a culture taken from the user object'); 
     369$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'fr\' AND article.ID=article_i18n.ID LIMIT 1', 'withI18n() hydrates the related I18n object with a culture taken from the user object'); 
    370370$t->is($article->getContent(), 'contenu français', 'withI18n() considers the current user culture for hydration'); 
    371371 
     
    379379$finder = sfPropelFinder::from('Article')->with('I18n'); 
    380380$article = $finder->findOne(); 
    381 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'with(\'I18n\') is a synonym for withI18n()'); 
     381$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'with(\'I18n\') is a synonym for withI18n()'); 
    382382$finder = sfPropelFinder::from('Article')->with('i18n'); 
    383383$article = $finder->findOne(); 
    384 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'with(\'i18n\') is a synonym for withI18n()'); 
     384$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, article_i18n.CONTENT, article_i18n.ID, article_i18n.CULTURE FROM article, article_i18n WHERE article_i18n.CULTURE=\'en\' AND article.ID=article_i18n.ID LIMIT 1', 'with(\'i18n\') is a synonym for withI18n()'); 
    385385 
    386386$t->diag('withColumn()'); 
     
    466466  orderBy('NbComments'); 
    467467$article = $finder->findOne(); 
    468 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, COUNT(comment.ID) AS \'NbComments\' FROM article, comment WHERE article.ID=comment.ARTICLE_ID GROUP BY article.ID ORDER BY NbComments ASC LIMIT 1', 'Columns added with withColumn() can be used for sorting'); 
     468$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, COUNT(comment.ID) AS \'NbComments\' FROM article, comment WHERE article.ID=comment.ARTICLE_ID GROUP BY article.ID ORDER BY NbComments ASC LIMIT 1', 'Columns added with withColumn() can be used for sorting'); 
  • plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderTest.php

    r10344 r10540  
    227227 
    228228$article = $finder->with('Category')->findPk($article2->getId()); 
    229 $t->cmp_ok(strpos($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM article, category'), '===', 0, 'findPk() is compatible with with()'); 
     229$t->cmp_ok(strpos($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID, category.ID, category.NAME FROM article, category'), '===', 0, 'findPk() is compatible with with()'); 
    230230 
    231231ArticlePeer::doDeleteAll(); 
     
    464464$t->diag('_and() and _or()'); 
    465465 
    466 $columns    = "article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID"; 
     466$columns    = "article.ID, article.TITLE, article.CATEGORY_ID"; 
    467467$baseSelect = "SELECT $columns FROM article WHERE "; 
    468468 
     
    543543$t->diag('combine()'); 
    544544 
    545 $columns    = "article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID"; 
     545$columns    = "article.ID, article.TITLE, article.CATEGORY_ID"; 
    546546$baseSelect = "SELECT $columns FROM article WHERE "; 
    547547 
     
    788788try 
    789789{ 
    790   sfPropelFinder::from('Comment')->joinArticle()->where('Article_Title', 'updated title')->set(array('Version' => 3)); 
     790  sfPropelFinder::from('Comment')->joinArticle()->where('Article_Title', 'updated title')->set(array('Title' => 3)); 
    791791  $t->fail('set() throws an exception when called on a finder with join()'); 
    792792} 
     
    801801$t->isa_ok($finder->getCriteria(), 'Criteria', 'getCriteria() returns the criteria as composed by the finder'); 
    802802$finder->findOne(); 
    803 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID FROM article WHERE article.TITLE=\'foo\' LIMIT 1', 'getLatestQuery() returns the latest SQL query'); 
     803$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID FROM article WHERE article.TITLE=\'foo\' LIMIT 1', 'getLatestQuery() returns the latest SQL query'); 
    804804$finder = sfPropelFinder::from('Article')->add(ArticlePeer::TITLE, 'bar'); 
    805805$finder->findOne(); 
    806 $t->is($finder->getLatestQuery(), 'SELECT article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID FROM article WHERE article.TITLE=\'bar\' LIMIT 1', 'you can call Criteria methods directly on the finder object to modify its Criteria'); 
     806$t->is($finder->getLatestQuery(), 'SELECT article.ID, article.TITLE, article.CATEGORY_ID FROM article WHERE article.TITLE=\'bar\' LIMIT 1', 'you can call Criteria methods directly on the finder object to modify its Criteria');