Development

Changeset 11031

You must first sign up to be able to contribute.

Changeset 11031

Show
Ignore:
Timestamp:
08/21/08 23:56:53 (3 months ago)
Author:
francois
Message:

DbFinderPlugin Implemented sfDoctrineFinder::join()

Files:

Legend:

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

    r10845 r11031  
    573573--------- 
    574574 
    575 ### 2008-08-13 | Trunk 
    576  
     575### 2008-08-21 | Trunk 
     576 
     577* francois: Implemented `sfDoctrineFinder::join()` 
    577578* francois: Added `getQueryObject()` to the list of default methods 
    578 * francois: Implemented `sfDoctrine::orderBy()` 
     579* francois: Implemented `sfDoctrineFinder::orderBy()` 
    579580* francois: Moved magic `__call()` to the parent `sfModelFinder` class 
    580581* francois: Implemented `sfDoctrineFinder::relatedTo()` (and fixed a bug in the `sfPropelFinder::relatedTo()` implementation) 
  • plugins/DbFinderPlugin/lib/sfDoctrineFinder.php

    r10901 r11031  
    4141  public function setClass($class, $alias = '') 
    4242  { 
    43     $this->addAlias($class, $alias); 
     43    if($alias) 
     44    { 
     45      $this->addAlias($class, $alias); 
     46    } 
    4447    $this->class = $class; 
    4548    $this->alias = $alias; 
     
    7073  } 
    7174   
    72   public function getQuery() 
    73   { 
    74     return $this->buildQuery(); 
    75   } 
    76    
    77   public function buildquery() 
    78   { 
     75  public function buildQuery() 
     76  { 
     77    // Temporarily disabling the the subquery algorithm (enabled again in cleanup()). 
     78    // Read more at http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#dql-doctrine-query-language:limit-and-offset-clauses:the-limit-subquery-algorithm 
     79    $this->object->getTable()->setAttribute(Doctrine::ATTR_QUERY_LIMIT, Doctrine::LIMIT_ROWS); 
     80 
     81    // Add columns 
     82    $this->query->select($this->getAlias($this->class).'.*'); 
     83    // TODO: add with() classes columns 
     84 
     85    // Add conditions 
    7986    if($this->queryPattern) 
    8087    { 
     
    94101  public function getQueryObject() 
    95102  { 
    96     return $this->getQuery(); 
     103    return $this->buildQuery(); 
    97104  } 
    98105   
     
    135142   * @param mixed $connection Optional connection object 
    136143   * 
    137    * @return sfPropelFinder a finder object 
     144   * @return sfDoctrineFinder a finder object 
    138145   * @throws Exception If the data is neither a classname nor an array 
    139146   */ 
     
    148155      return self::fromCollection($from); 
    149156    } 
    150     throw new Exception('sfPropelFinder::from() only accepts a model object classname or an array of model objects'); 
     157    throw new Exception('sfDoctrineFinder::from() only accepts a model object classname or an array of model objects'); 
    151158  } 
    152159   
     
    157164   * @param string $class Model classname on which the search will be done 
    158165   * 
    159    * @return sfPropelFinder a finder object 
     166   * @return sfDoctrineFinder a finder object 
    160167   */ 
    161168  public static function fromArray($array, $class, $pkName) 
     
    332339  public function count($distinct = false) 
    333340  { 
    334     $res = $this->getQuery()->count(); 
     341    $res = $this->buildQuery()->count(); 
    335342    $this->cleanup(); 
    336343     
     
    351358      $this->query->limit($limit); 
    352359    } 
    353     $res = $this->getQuery()->execute(); 
     360    $res = $this->buildQuery()->execute(); 
    354361    $this->cleanup(); 
    355362     
     
    511518    if($forceIndividualDeletes) 
    512519    { 
    513       $objects = $this->getQuery()->delete()->execute(); 
     520      $objects = $this->buildQuery()->delete()->execute(); 
    514521      $nbDeleted = 0; 
    515522      foreach($objects as $object) 
     
    521528    else 
    522529    { 
    523       if (!$this->getQuery()->contains('where')) 
     530      if (!$this->buildQuery()->contains('where')) 
    524531      { 
    525532        // Empty queries don't return the number of deleted rows 
     
    571578  protected function cleanup() 
    572579  { 
     580    // Re-enabling the the subquery algorithm. 
     581    $this->object->getTable()->setAttribute(Doctrine::ATTR_QUERY_LIMIT, Doctrine::LIMIT_RECORDS); 
     582     
    573583    if($this->reinit) 
    574584    { 
     
    10211031      case 3: 
    10221032        // $articleFinder->join('Article.CategoryId', 'Category.Id', 'RIGHT JOIN') 
     1033        // This is mostly for compatibility with Propel 
     1034        $relation = $this->findRelationFromColumns($args[0], $args[1]); 
    10231035        $operator = trim(str_replace('join', '', strtolower($args[2]))); 
     1036        $relatedClass = $relation->getTable()->getClassnameToReturn(); 
     1037        $alias = ''; 
    10241038        break; 
    10251039    } 
    10261040    $method = $operator . 'Join'; 
    10271041    $startClass = $this->getAlias($relation->offsetGet('localTable')->getClassnameToReturn()); 
    1028     if($isTrueAlias) 
    1029     { 
    1030       $this->addAlias($startClass.'.'.$relation->getAlias(), $alias); 
     1042    $relationClass = $relation->getTable()->getClassnameToReturn(); 
     1043    $this->query->$method($startClass.'.'.$relation->getAlias().' '.$alias); 
     1044     
     1045    if($relationClass == $relatedClass) 
     1046    { 
     1047      $this->addAlias($relationClass, $alias); 
    10311048    } 
    10321049    else 
    10331050    { 
    1034       $this->addAlias($relation->getClass(), $startClass.'.'.$relation->getAlias()); 
     1051      // $relatedClass is in fact the relation name, not the foreign class name 
     1052      $this->addAlias($relatedClass, $alias); 
    10351053    } 
    10361054     
     
    11011119  } 
    11021120   
     1121  public function findRelationFromColumns($col1, $col2) 
     1122  { 
     1123    list($leftClass, $leftColumn, $leftAlias) = $this->getColName($col1, $class = null, $detail = true, $autoAddJoin = false); 
     1124    list($rightClass, $rightColumn, $rightAlias) = $this->getColName($col2, $class = null, $detail = true, $autoAddJoin = false); 
     1125     
     1126    foreach($this->relatedTables as $table) 
     1127    { 
     1128      foreach ($table->getRelations() as $key => $relation) 
     1129      { 
     1130        if ($relation->getClass() == $rightClass && $relation->getForeign() == $rightColumn &&  
     1131            $relation->offsetGet('localTable')->getClassnameToReturn() == $leftClass && $relation->getLocal() == $leftColumn) 
     1132        { 
     1133          $this->relatedTables[]= Doctrine::getTable($rightClass); 
     1134          $this->relations[$rightClass] = $relation; 
     1135           
     1136          return $relation; 
     1137        } 
     1138        if ($relation->getClass() == $leftClass && $relation->getForeign() == $leftColumn &&  
     1139            $relation->offsetGet('localTable')->getClassnameToReturn() == $rightClass && $relation->getLocal() == $rightColumn) 
     1140        { 
     1141          $this->relatedTables[]= Doctrine::getTable($leftClass); 
     1142          $this->relations[$leftClass] = $relation; 
     1143           
     1144          return $relation; 
     1145        } 
     1146 
     1147      } 
     1148    } 
     1149     
     1150    throw new Exception(sprintf('Cannot determine relation between %s and %s', $col1, $col2)); 
     1151  } 
     1152   
    11031153  /** 
    11041154   * Behavior-like supplementary getter for supplementary columns added by way of withColumn() 
     
    11461196  } 
    11471197   
    1148   protected function getColName($phpName, $class = null, $autoAddJoin = true) 
     1198  protected function getColName($phpName, $class = null, $detail = false, $autoAddJoin = true) 
    11491199  { 
    11501200    if(strpos($phpName, '.') !== false) 
     
    11651215      if(!$class) 
    11661216      { 
    1167         // TODO: guess class 
    11681217        $class = $this->getClass(); 
    11691218      } 
     
    11891238    } 
    11901239     
    1191     return $alias . '.' . self::underscore($phpName); 
     1240    $colName = $alias . '.' . self::underscore($phpName); 
     1241     
     1242    return $detail ? array($class, self::underscore($phpName), $alias) : $alias . '.' . self::underscore($phpName); 
     1243  } 
     1244   
     1245  public function debug() 
     1246  { 
     1247    echo "** Debugging Doctrine Query\n"; 
     1248    $this->limit(1); 
     1249    echo "   " . $this->getQueryObject()->getDQL()."\n"; 
     1250    $this->findOne(); 
     1251    echo "   " . $this->getLatestQuery()."\n"; 
    11921252  } 
    11931253} 
  • plugins/DbFinderPlugin/lib/sfModelFinder.php

    r10901 r11031  
    218218  { 
    219219    // If the connection is a PDO instance, PHP throws an exception when serializing a finder object 
    220     // So we must ply well with it 
     220    // So we must play well with it 
    221221    $attributes = get_object_vars($this); 
    222222    unset($attributes['connection']); 
  • plugins/DbFinderPlugin/lib/sfPropelFinder.php

    r10901 r11031  
    13171317        break; 
    13181318    } 
     1319    $operator = trim(str_replace('JOIN', '', strtoupper($operator))) . ' JOIN'; 
    13191320    $this->criteria->addJoin($column1, $column2, $operator); 
    13201321     
  • plugins/DbFinderPlugin/test/unit/sfDoctrineFinderInternalsTest.php

    r10901 r11031  
    6666class myFinder extends sfDoctrineFinder 
    6767{ 
    68   public function getColName($phpName, $class = null, $autoAddJoin = false) 
     68  public function getColName($phpName, $class = null, $detail = false, $autoAddJoin = false) 
    6969  { 
    70     return parent::getColName($phpName, $class, $autoAddJoin); 
     70    return parent::getColName($phpName, $class, $detail, $autoAddJoin); 
    7171  } 
    7272} 
  • plugins/DbFinderPlugin/test/unit/sfDoctrineFinderRelationsTest.php

    r10901 r11031  
    120120$databaseManager->initialize(); 
    121121 
    122 $t = new lime_test(15, new lime_output_color()); 
     122$t = new lime_test(34, new lime_output_color()); 
    123123 
    124124$t->diag('findRelation()'); 
     
    219219$t->is($article->getTitle(), 'bbbbb', 'join() allows to join to another table (one-to-many)'); 
    220220 
     221$nbArticles = sfDoctrineFinder::from('DArticle')->join('Category')->where('Category.Name', 'cat1')->count(); 
     222$t->is($nbArticles, 2, 'join() accepts relation names instead of related class names'); 
     223$nbArticles = sfDoctrineFinder::from('DArticle')->join('DCategory a')->where('a.Name', 'cat1')->count(); 
     224$t->is($nbArticles, 2, 'join() accepts class aliases'); 
     225$nbArticles = sfDoctrineFinder::from('DArticle')->join('Category a')->where('a.Name', 'cat1')->count(); 
     226$t->is($nbArticles, 2, 'join() accepts relation aliases'); 
     227 
     228$finder = sfDoctrineFinder::from('DArticle')->join('DCategory'); 
     229$finder->count(); 
     230$t->ok(stripos($finder->getLatestQuery(), 'inner join') !== false, 'join($table) defaults to an inner join'); 
     231$finder = sfDoctrineFinder::from('DArticle')->join('DCategory', 'left join'); 
     232$finder->count(); 
     233$t->ok(stripos($finder->getLatestQuery(), 'left join') !== false, 'join($table, $type) accepts a join type as second parameter (like "left join")'); 
     234$finder = sfDoctrineFinder::from('DArticle')->join('DCategory', Criteria::LEFT_JOIN); 
     235$finder->count(); 
     236$t->ok(stripos($finder->getLatestQuery(), 'left join') !== false, 'join($table, $type) accepts a join type as second parameter (like "Criteria::LEFT_JOIN")'); 
     237$finder = sfDoctrineFinder::from('DArticle')->join('DCategory', 'left'); 
     238$finder->count(); 
     239$t->ok(stripos($finder->getLatestQuery(), 'left join') !== false, 'join($table, $type) accepts a join type as second parameter (like "left")'); 
     240 
     241$finder = sfDoctrineFinder::from('DArticle')->join('DArticle.CategoryId', 'DCategory.Id', 'inner')->where('Category.Name', 'cat1'); 
     242$t->is($nbArticles, 2, 'join($start, $end, $type) allows to join based on the two members of the relationship'); 
     243sfDoctrineFinder::from('DArticle')->join('DCategory.Id', 'DArticle.CategoryId', 'inner')->where('Category.Name', 'cat1'); 
     244$t->is($nbArticles, 2, 'join($end, $start, $type) allows to join based on the two members of the relationship'); 
     245 
     246Doctrine_Query::create()->delete()->from('DArticle')->execute(); 
     247Doctrine_Query::create()->delete()->from('DComment')->execute(); 
     248Doctrine_Query::create()->delete()->from('DAuthor')->execute(); 
     249$article1 = new DArticle(); 
     250$article1->setTitle('aaaaa'); 
     251$article1->setCategory($category1); 
     252$article1->save(); 
     253$author1 = new DAuthor(); 
     254$author1->setName('John'); 
     255$author1->save(); 
     256$comment = new DComment(); 
     257$comment->setContent('foo'); 
     258$comment->setArticleId($article1->getId()); 
     259$comment->setAuthor($author1); 
     260$comment->save(); 
     261$article = sfDoctrineFinder::from('DArticle')->join('DComment')->join('DAuthor')->where('DAuthor.Name', 'John')->findOne(); 
     262$t->is($article->getTitle(), 'aaaaa', 'you can chain several join() statements'); 
     263$article = sfDoctrineFinder::from('DArticle')->join('DComment')->where('DAuthor.Name', 'John')->findOne(); 
     264$t->is($article->getTitle(), 'aaaaa', 'join() can be omitted if column names are explicit'); 
     265$article = sfDoctrineFinder::from('DArticle')->joinDComment()->joinDAuthor()->where('DAuthor.Name', 'John')->findOne(); 
     266$t->is($article->getTitle(), 'aaaaa', 'joinXXX() does a join according to the XXX column name'); 
     267 
     268$comment = sfDoctrineFinder::from('DComment')->join('DArticle')->join('DAuthor')->where('DAuthor.Name', 'John')->findOne(); 
     269$t->is($comment->getContent(), 'foo', 'you can add several join() statements'); 
     270$t->is($comment->getArticle()->getTitle(), 'aaaaa', 'you can add several join() statements'); 
     271$t->is($comment->getAuthor()->getName(), 'John', 'you can add several join() statements'); 
     272 
     273$t->diag('leftJoin(), rightJoin(), innerJoin()'); 
     274 
     275$finder = sfDoctrineFinder::from('DArticle')->leftJoin('DComment'); 
     276$t->is($finder->getQueryObject()->getDQL(), 'SELECT d.* FROM DArticle d LEFT JOIN d.DComment d1', 'leftJoin($table) ends up in a left join'); 
     277//$finder = sfDoctrineFinder::from('DArticle')->innerJoin('DComment'); 
     278$t->skip('rightJoin($table) ends up in a right join'); 
     279$finder = sfDoctrineFinder::from('DArticle')->innerJoin('DComment'); 
     280$t->is($finder->getQueryObject()->getDQL(), 'SELECT d.* FROM DArticle d INNER JOIN d.DComment d1', 'innerJoin($table) ends up in an inner join'); 
     281 
     282$finder = sfDoctrineFinder::from('DArticle')->leftJoin('DArticle.Id', 'DComment.ArticleId'); 
     283$t->is($finder->getQueryObject()->getDQL(), 'SELECT d.* FROM DArticle d LEFT JOIN d.DComment ', 'leftJoin($start, $end) creates left join'); 
     284 
     285$t->diag('with()'); 
     286 
     287Doctrine_Query::create()->delete()->from('DArticle')->execute(); 
     288Doctrine_Query::create()->delete()->from('DCategory')->execute(); 
     289$category1 = new DCategory(); 
     290$category1->setName('cat1'); 
     291$category1->save(); 
     292$article1 = new DArticle(); 
     293$article1->setTitle('aaaaa'); 
     294$article1->setCategory($category1); 
     295$article1->save(); 
     296$finder = sfDoctrineFinder::from('DArticle'); 
     297$article = $finder->findOne(); 
     298$sql = $finder->getLatestQuery(); 
     299$category = $article->getCategory(); 
     300//$t->isnt($finder->getLatestQuery(), $sql, 'Calling a getter on a related object issues a new query'); 
  • plugins/DbFinderPlugin/test/unit/sfDoctrineFinderTest.php

    r10845 r11031  
    7878 
    7979$finder = sfDoctrineFinder::from('DArticle')->where('Title', 'foo'); 
    80 $t->isa_ok($finder->getQuery(), 'Doctrine_Query', 'getQuery() returns the query object as composed by the finder'); 
     80$t->isa_ok($finder->getQueryObject(), 'Doctrine_Query', 'getQueryObject() returns the query object as composed by the finder'); 
    8181$finder->findOne(); 
    8282$t->is($finder->getLatestQuery(), 'SELECT d.id AS d__id, d.title AS d__title, d.category_id AS d__category_id FROM d_article d WHERE d.title = \'foo\' LIMIT 1', 'getLatestQuery() returns the latest SQL query'); 
  • plugins/DbFinderPlugin/test/unit/sfPropelFinderRelationsTest.php

    r10812 r11031  
    7777$databaseManager->initialize(); 
    7878 
    79 $t = new lime_test(83, new lime_output_color()); 
     79$t = new lime_test(85, new lime_output_color()); 
    8080 
    8181$t->diag('findRelation()'); 
     
    167167$joins = $finder->getCriteria()->getJoins(); 
    168168$join = array_pop($joins); 
    169 $t->is($join->getJoinType(), 'LEFT JOIN', 'join($table, $type) creates a typed join'); 
     169$t->is($join->getJoinType(), 'LEFT JOIN', 'join($table, $type) creates a typed join (with $type like Criteria::LEFT_JOIN)'); 
     170 
     171$finder = sfPropelFinder::from('Article')->join('Comment', 'left join'); 
     172$joins = $finder->getCriteria()->getJoins(); 
     173$join = array_pop($joins); 
     174$t->is($join->getJoinType(), 'LEFT JOIN', 'join($table, $type) creates a typed join (with $type like "left join")'); 
     175 
     176$finder = sfPropelFinder::from('Article')->join('Comment', 'left'); 
     177$joins = $finder->getCriteria()->getJoins(); 
     178$join = array_pop($joins); 
     179$t->is($join->getJoinType(), 'LEFT JOIN', 'join($table, $type) creates a typed join (with $type like "left")'); 
     180 
    170181$t->is($join->getLeftColumnName(), 'ID', 'join($table, $type) guesses the left column name'); 
    171182$t->is($join->getLeftTableName(), 'article', 'join($table, $type) guesses the left table name'); 
  • plugins/DbFinderPlugin/test/unit/sfPropelFinderTest.php

    r10845 r11031  
    6969 
    7070$finder = sfPropelFinder::from('Article')->where('Title', 'foo'); 
    71 $t->isa_ok($finder->getCriteria(), 'Criteria', 'getCriteria() returns the criteria as composed by the finder'); 
     71$t->isa_ok($finder->getQueryObject(), 'Criteria', 'getQueryObject() returns the criteria as composed by the finder'); 
    7272$finder->findOne(); 
    7373$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');