Changeset 8117
- Timestamp:
- 03/27/08 17:48:20 (7 months ago)
- Files:
-
- plugins/sfPropelFinderPlugin/README (modified) (4 diffs)
- plugins/sfPropelFinderPlugin/lib/sfPropelFinder.php (modified) (8 diffs)
- plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderTest.php (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/sfPropelFinderPlugin/README
r8107 r8117 75 75 // Finding all Articles where published_at less than time() 76 76 $articles = $articleFinder->wherePublishedAt('<', time())->find(); 77 // The whereXXX method accepts simple or composed column names 78 $articles = $articleFinder->whereArticle_PublishedAt('<', time())->find(); 77 79 }}} 78 80 … … 117 119 The syntax should remind you of `sfFinder` and `sfTestBrowser`. 118 120 121 === Joins === 122 123 {{{ 124 #!php 125 <?php 126 $article1 = new Article(); 127 $article1->setTitle('Hello, world!'); 128 $article1->setCategory($category1); 129 $article1->save(); 130 $author1 = new Author(); 131 $author1->setName('John'); 132 $author1->save(); 133 $comment = new Comment(); 134 $comment->setContent('You rock!'); 135 $comment->setArticle($article1); 136 $comment->setAuthor($author1); 137 $comment->save(); 138 // Add a join statement 139 // No need to tell the finder which columns to use for the join, just the related Class 140 // After all, the columns of the FK are already defined in the schema 141 $article = sfPropelFinder::from('Article')-> 142 joinComment()-> 143 whereComment_Content('foo')-> 144 findOne(); 145 // You can chain joins if you want to make it more complex 146 $article = sfPropelFinder::from('Article')-> 147 joinComment()-> 148 joinAuthor()-> 149 whereAuthor_Name('You rock!')-> 150 findOne(); 151 }}} 152 119 153 === Writing your own business logic into a finder === 120 154 … … 144 178 == TODO == 145 179 146 * Handle Joins180 * Allow hydrating of related objects (doSelectJoinXXX equivalent) 147 181 * Add more magic! 148 182 * Merge with sfPropelImpersonatorPlugin? … … 152 186 === 2008-03-27 | Trunk === 153 187 188 * francois: Added `sfPropelFinder::joinXXX()` method 189 * francois: Added `sfPropelFinder::join()` method 190 * francois: added complete `whereClassName_ColumnName()` syntax 154 191 * francois: Added `sfPropelFinder::count()` method 155 192 plugins/sfPropelFinderPlugin/lib/sfPropelFinder.php
r8107 r8117 13 13 { 14 14 protected $peerClass = null; 15 protected $mapBuilder = null;16 15 protected $databaseMap = null; 17 protected $tableMap = null;18 protected $columnMaps = null;19 16 protected $criteria = null; 17 protected $relations = null; 20 18 21 19 public function getPeerClass() … … 26 24 public function setPeerClass($peerClass) 27 25 { 26 $this->relations[]= $peerClass; 28 27 return $this->peerClass = $peerClass; 29 }30 31 public function getMapBuilder()32 {33 return $this->mapBuilder;34 }35 36 public function setMapBuilder($mapBuilder)37 {38 return $this->mapBuilder = $mapBuilder;39 28 } 40 29 … … 56 45 $mapBuilder = call_user_func(array($this->peerClass, 'getMapBuilder')); 57 46 $mapBuilder->doBuild(); 58 $this->mapBuilder = $mapBuilder; 59 $this->databaseMap = $this->getMapBuilder()->getDatabaseMap(); 60 $tableMaps = $this->databaseMap->getTables(); 61 $this->tableMap = array_pop($tableMaps); 62 $this->columnMaps = $this->tableMap->getColumns(); 47 $this->databaseMap = $mapBuilder->getDatabaseMap(); 63 48 } 64 49 … … 85 70 86 71 return $ret; 87 88 72 } 89 73 … … 158 142 } 159 143 144 public function join($column1, $column2, $operator = null) 145 { 146 $this->criteria->addJoin($column1, $column2, $operator); 147 148 return $this; 149 } 150 160 151 public function __call($name, $arguments) 161 152 { … … 163 154 if(strpos($name, 'where') === 0) 164 155 { 165 $column = $this->getColName(substr($name, 5)); 156 $columnName = substr($name, 5); 157 if(strpos($columnName, '_') !== false) 158 { 159 list($class, $columnName) = split('_', $columnName); 160 $column = $this->getColName($columnName, $class.'Peer'); 161 } 162 else 163 { 164 $column = $this->getColName($columnName); 165 } 166 166 $comparison = Criteria::EQUAL; 167 167 switch (count($arguments)) … … 185 185 throw new Exception('{sfPropelFinder} whereXXX can only be called with one or two arguments'); 186 186 } 187 $this->where($column, $value, $comparison);187 return $this->where($column, $value, $comparison); 188 188 } 189 189 … … 197 197 $order = Criteria::ASC; 198 198 } 199 $this->orderBy($column, $order); 200 } 201 202 return $this; 203 } 204 205 protected function getColName($phpName) 206 { 199 return $this->orderBy($column, $order); 200 } 201 202 // join 203 if(strpos($name, 'join') === 0) 204 { 205 $relatedClass = substr($name, 4); 206 list($column1, $column2) = $this->getRelation($relatedClass); 207 $this->relations[]= $relatedClass.'Peer'; 208 $operator = array_shift($arguments); 209 if(!$operator) 210 { 211 $operator = null; 212 } 213 return $this->join($column1, $column2, $operator); 214 } 215 216 return $this; 217 } 218 219 public function getRelation($phpName) 220 { 221 foreach($this->relations as $peerClass) 222 { 223 // try to find many to one or one to one relationship 224 if($relation = $this->findRelation($phpName, $peerClass)) 225 { 226 return $relation; 227 } 228 // try to find one to many relationship 229 if($relation = $this->findRelation(str_replace('Peer', '', $peerClass), $phpName.'Peer')) 230 { 231 return $relation; 232 } 233 } 234 throw new Exception(sprintf('{sfPropelFinder} %s has no %s related table', $this->peerClass, $phpName)); 235 } 236 237 protected function findRelation($phpName, $peerClass) 238 { 239 foreach ($this->getColumnsForPeerClass($peerClass) as $c) 240 { 241 if ($c->isForeignKey()) 242 { 243 if(sfInflector::camelize($c->getRelatedTableName()) == $phpName) 244 { 245 return array( 246 constant($peerClass.'::'.$c->getColumnName()), 247 $c->getRelatedName() 248 ); 249 } 250 } 251 } 252 253 return false; 254 } 255 256 protected function getColumnsForPeerClass($peerClass) 257 { 258 // try to find one to many relationship 259 $mapBuilderClass = str_replace('Peer', 'MapBuilder', $peerClass); 260 $tableName = strtolower(str_replace('Peer', '', $peerClass)); 261 if(class_exists($mapBuilderClass)) 262 { 263 $mapBuilder = new $mapBuilderClass(); 264 $mapBuilder->doBuild(); 265 return $this->databaseMap->getTable($tableName)->getColumns(); 266 } 267 return false; 268 } 269 270 protected function getColName($phpName, $peerClass = null) 271 { 272 if(!$peerClass) 273 { 274 $peerClass = $this->peerClass; 275 } 207 276 try 208 277 { 209 $column = call_user_func(array($ this->peerClass, 'translateFieldName'), $phpName, BasePeer::TYPE_PHPNAME, BasePeer::TYPE_COLNAME);278 $column = call_user_func(array($peerClass, 'translateFieldName'), $phpName, BasePeer::TYPE_PHPNAME, BasePeer::TYPE_COLNAME); 210 279 return $column; 211 280 } 212 281 catch (PropelException $e) 213 282 { 214 throw new Exception(sprintf('{sfPropelFinder} %s has no %s column', $ this->peerClass, $phpName));283 throw new Exception(sprintf('{sfPropelFinder} %s has no %s column', $peerClass, $phpName)); 215 284 } 216 285 } plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderTest.php
r8108 r8117 9 9 */ 10 10 11 /* 12 You need a model built with a running database to run these tests. 13 The tests expect a model similar to this one: 14 15 propel: 16 article: 17 id: ~ 18 title: varchar(255) 19 category_id: ~ 20 category: 21 id: ~ 22 name: varchar(255) 23 comment: 24 id: ~ 25 content: varchar(255) 26 article_id: ~ 27 author_id: ~ 28 author: 29 id: ~ 30 name: varchar(255) 31 32 Beware that the tables for these models will be emptied by the tests, so use a test database connection. 33 */ 34 11 35 // Autofind the first available app environment 12 36 $sf_root_dir = realpath(dirname(__FILE__).'/../../../../'); … … 39 63 ArticlePeer::doDeleteAll(); 40 64 41 $t = new lime_test( 42, new lime_output_color());65 $t = new lime_test(53, new lime_output_color()); 42 66 43 67 $t->diag('find()'); … … 202 226 203 227 $article = sfPropelFinder::from('Article')->whereTitle('abc')->findOne(); 204 $t->is($article->getId(), $article1->getId(), 'whereXXX() adds a WHERE condition on the XXX column'); 228 $t->is($article->getId(), $article1->getId(), 'whereXXX() accepts a simple column name like whereColumnName()'); 229 $article = sfPropelFinder::from('Article')->whereArticle_Title('abc')->findOne(); 230 $t->is($article->getId(), $article1->getId(), 'whereXXX() accepts a complete column name like whereClassName_ColumnName()'); 205 231 $article = sfPropelFinder::from('Article')->whereTitle('def')->findOne(); 206 232 $t->is($article->getId(), $article2->getId(), 'whereXXX() adds a WHERE condition on the XXX column'); … … 212 238 $t->is(count($articles), 3, 'whereXXX() accepts a text comparator and is permissive on syntax'); 213 239 240 214 241 $t->diag('orderBy() magic'); 215 242 try … … 272 299 $article = sfPropelFinder::from('Article')->orderByTitle('desc')->findOne(); 273 300 $t->is($article->getTitle(), 'ccccc', 'orderByXXX() orders by column and takes an order as argment'); 301 302 $t->diag('join() magic'); 303 304 list($column1, $column2) = sfPropelFinder::from('Article')->getRelation('Category'); 305 $t->is($column1, ArticlePeer::CATEGORY_ID, 'getRelation() guesses the two parts of a relation properly for many-to-one relationships'); 306 $t->is($column2, CategoryPeer::ID, 'getRelation() guesses the two parts of a relation properly for many-to-one relationships'); 307 list($column1, $column2) = sfPropelFinder::from('Article')->getRelation('Comment'); 308 $t->is($column1, CommentPeer::ARTICLE_ID, 'getRelation() guesses the two parts of a relation properly for one-to-many relationships'); 309 $t->is($column2, ArticlePeer::ID, 'getRelation() guesses the two parts of a relation properly for one-to-many relationships'); 310 ArticlePeer::doDeleteAll(); 311 CategoryPeer::doDeleteAll(); 312 $category1 = new Category(); 313 $category1->setName('cat1'); 314 $category1->save(); 315 $category2 = new Category(); 316 $category2->setName('cat2'); 317 $category2->save(); 318 $article1 = new Article(); 319 $article1->setTitle('aaaaa'); 320 $article1->setCategory($category1); 321 $article1->save(); 322 $article2 = new Article(); 323 $article2->setTitle('bbbbb'); 324 $article2->setCategory($category1); 325 $article2->save(); 326 $article3 = new Article(); 327 $article3->setTitle('ccccc'); 328 $article3->setCategory($category2); 329 $article3->save(); 330 $nbArticles = sfPropelFinder::from('Article')->joinCategory()->where(CategoryPeer::NAME, 'cat1')->count(); 331 $t->is($nbArticles, 2, 'joinXXX() allows to join to another table (many-to-one)'); 332 $nbArticles = sfPropelFinder::from('Article')->joinCategory()->where(CategoryPeer::NAME, 'cat2')->count(); 333 $t->is($nbArticles, 1, 'joinXXX() allows to join to another table (many-to-one)'); 334 $article = sfPropelFinder::from('Article')->joinCategory()->where(CategoryPeer::NAME, 'cat2')->findOne(); 335 $t->is($article->getTitle(), 'ccccc', 'joinXXX() allows to join to another table (many-to-one)'); 336 ArticlePeer::doDeleteAll(); 337 CommentPeer::doDeleteAll(); 338 $article1 = new Article(); 339 $article1->setTitle('aaaaa'); 340 $article1->setCategory($category1); 341 $article1->save(); 342 $article2 = new Article(); 343 $article2->setTitle('bbbbb'); 344 $article2->setCategory($category1); 345 $article2->save(); 346 $comment = new Comment(); 347 $comment->setContent('foo'); 348 $comment->setArticle($article2); 349 $comment->save(); 350 $nbArticles = sfPropelFinder::from('Article')->joinComment()->where(CommentPeer::CONTENT, 'foo')->count(); 351 $t->is($nbArticles, 1, 'joinXXX() allows to join to another table (one-to-many)'); 352 $article = sfPropelFinder::from('Article')->joinComment()->where(CommentPeer::CONTENT, 'foo')->findOne(); 353 $t->is($article->getTitle(), 'bbbbb', 'joinXXX() allows to join to another table (one-to-many)'); 354 355 ArticlePeer::doDeleteAll(); 356 CommentPeer::doDeleteAll(); 357 AuthorPeer::doDeleteAll(); 358 $article1 = new Article(); 359 $article1->setTitle('aaaaa'); 360 $article1->setCategory($category1); 361 $article1->save(); 362 $author1 = new Author(); 363 $author1->setName('John'); 364 $author1->save(); 365 $comment = new Comment(); 366 $comment->setContent('foo'); 367 $comment->setArticle($article1); 368 $comment->setAuthor($author1); 369 $comment->save(); 370 $article = sfPropelFinder::from('Article')->joinComment()->joinAuthor()->where(AuthorPeer::NAME, 'John')->findOne(); 371 $t->is($article->getTitle(), 'aaaaa', 'you can chan several joinXXX() statements');