Changeset 10166
- Timestamp:
- 07/07/08 15:19:42 (5 months ago)
- Files:
-
- plugins/sfPropelFinderPlugin/README (modified) (4 diffs)
- plugins/sfPropelFinderPlugin/lib/sfPropelFinder.php (modified) (5 diffs)
- plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderTest.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/sfPropelFinderPlugin/README
r10123 r10166 123 123 }}} 124 124 125 === C ombining methods ===125 === Chaining methods === 126 126 127 127 The methods of the `sfPropelFinder` object return the current finder object, so you can chain them together in a single call, and finish by any of the `find()` methods to launch the query. … … 267 267 }}} 268 268 269 === Complex logic === 270 271 {{{ 272 #!php 273 <?php 274 // _and() and _or() only allow simple logical operations on a single condition 275 // For more complex logic, you have to use combine() 276 // It expects an array of named conditions to be combined, and an operator 277 // Use the fourth argument of where() to name a condition 278 $article = sfPropelFinder::from('Article')-> 279 where('Title', '=', 'Foo', 'cond1')-> // creates a condition named 'cond1' 280 where('Title', '=', 'Bar', 'cond2')-> // creates a condition named 'cond2' 281 combine(array('cond1', 'cond2'), 'or')-> // combine 'cond1' and 'cond2' with a logical OR 282 findOne(); 283 // SELECT article.* FROM article WHERE (article.TITLE = 'foo' OR article.TITLE = 'bar'); 284 285 // combine accepts more than two conditions at a time 286 $articles = sfPropelFinder::from('Article')-> 287 where('Title', '=', 'Foo', 'cond1')-> 288 where('Title', '=', 'Bar', 'cond2')-> 289 where('Title', '=', 'FooBar', 'cond3')-> 290 combine(array('cond1', 'cond2', 'cond3'), 'or')-> 291 find(); 292 // SELECT article.* FROM article WHERE (article.TITLE = 'foo' OR article.TITLE = 'bar') OR article.TITLE = 'FooBar'; 293 294 // combine() itself can return a named condition to be combined later 295 // So it allows for any level of logical complexity 296 $articles = sfPropelFinder::from('Article')-> 297 where('Title', '=', 'Foo', 'cond1')-> 298 where('Title', '=', 'Bar', 'cond2')-> 299 combine(array('cond1', 'cond2'), 'or', 'TitleFooBar')-> 300 where('PublishedAt', '<=', $end, 'cond3')-> 301 where('PublishedAt', '>=', $begin, 'cond4')-> 302 combine(array('cond2', 'cond3'), 'and', 'PublishedInBounds')-> 303 combine(array('TitleFooBar', 'PublishedInBounds'), 'or')-> 304 find(); 305 // SELECT article.* FROM article WHERE ( 306 // (article.TITLE = 'foo' OR article.TITLE = 'bar') 307 // OR 308 // (article.PUBLISHED_AT <= $end AND article.PUBLISHED_AT >= $begin) 309 // ); 310 }}} 311 269 312 === Minimizing queries === 270 313 … … 535 578 == TODO / Ideas == 536 579 580 * Allow i18n hydration of related objects (#3897) 581 * Handle self-referencing relationships (e.g. parent_id), especially in with() 582 * Handle multiple references to the same table (c.f. getFooRelatedByBarId()) 537 583 * Put as a parent class in the PeerBuilder so that every Peer class can be a finder 538 584 * Merge with sfPropelImpersonatorPlugin! 539 * Handle complex queries with And and Or540 585 * Add a `__toString()` method which returns a var_export() of the results, or a description of the conditions if not yet executed 541 586 * 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 … … 544 589 == Changelog == 545 590 546 === 2008-07-04 | Trunk === 547 591 === 2008-07-07 | Trunk === 592 593 * francois: Added `sfPropelFinder::combine()` method to handle complex queries with And and Or 548 594 * francois: Added support for `with()` in `findPk()` (and documented the method) 549 595 * francois: Added the ability to do left, right, and inner joins in a simple way plugins/sfPropelFinderPlugin/lib/sfPropelFinder.php
r10132 r10166 712 712 * $articleFinder->where('Title', 'like', '%foo') 713 713 * => $c->add(ArticlePeer::TITLE, '%foo', Criteria::LIKE) 714 * $articleFinder->where('Title', 'like', '%foo', 'FooTitle') 715 * => $FooTitle = $c->getNewCriterion(ArticlePeer::TITLE, '%foo', Criteria::LIKE) 714 716 * 715 717 * @param string $columnName PHPName of the column bearing the condition 716 * @param array $arguments Optional array of arguments 718 * @param string $valueOrOperator Value if 2 arguments, operator otherwise 719 * @param string $value Value if 3 arguments (optional) 720 * @param string $namedCondition If condition is to be stored for later combination (see combine()) 717 721 * 718 722 * @return sfPropelFinder the current finder object 719 723 */ 720 public function where($columnName, $arguments = array()) 721 { 724 public function where() 725 { 726 $arguments = func_get_args(); 727 $columnName = array_shift($arguments); 722 728 $column = $this->getColName($columnName); 723 if(!is_array($arguments)) 724 { 725 $arguments = func_get_args(); 726 array_shift($arguments); 727 } 729 if(isset($arguments[2])) 730 { 731 $namedCondition = $arguments[2]; 732 unset($arguments[2]); 733 } 734 else 735 { 736 $namedCondition = null; 737 } 728 738 list($value, $comparison) = sfPropelFinderUtils::getValueAndComparisonFromArguments($arguments); 729 730 $this->addCondition('and', $column, $value, $comparison ); 739 $this->addCondition('And', $column, $value, $comparison, $namedCondition); 731 740 732 741 return $this; … … 736 745 * Finder Fluid Interface for Criteria::addAnd() 737 746 * Infers $column, $value, $comparison from $columnName and some optional arguments 738 * Examples: 739 * $articleFinder->_and('CommentId', 3) 740 * => $c->addAnd(ArticlePeer::COMMENT_ID, 3) 741 * 742 * @param string $columnName PHPName of the column bearing the condition 743 * @param array $arguments Optional array of arguments 744 * 745 * @return sfPropelFinder the current finder object 746 */ 747 public function _and($columnName, $arguments = array()) 748 { 747 * 748 * @see where() 749 */ 750 public function _and() 751 { 752 $arguments = func_get_args(); 753 $columnName = array_shift($arguments); 749 754 $column = $this->getColName($columnName); 750 if(!is_array($arguments))751 {752 $arguments = func_get_args();753 array_shift($arguments);754 }755 755 list($value, $comparison) = sfPropelFinderUtils::getValueAndComparisonFromArguments($arguments); 756 757 $this->addCondition('and', $column, $value, $comparison); 756 $this->addCondition('And', $column, $value, $comparison); 758 757 759 758 return $this; … … 766 765 * $articleFinder->_or('CommentId', 3) 767 766 * => $c->addOr(ArticlePeer::COMMENT_ID, 3) 767 * $articleFinder->_or('Title', 'like', '%foo') 768 * => $c->addOr(ArticlePeer::TITLE, '%foo', Criteria::LIKE) 768 769 * 769 770 * @param string $columnName PHPName of the column bearing the condition 770 * @param array $arguments Optional array of arguments 771 * @param string $valueOrOperator Value if 2 arguments, operator otherwise 772 * @param string $value Value if 3 arguments (optional) 771 773 * 772 774 * @return sfPropelFinder the current finder object 773 775 */ 774 public function _or($columnName, $arguments = array()) 775 { 776 public function _or() 777 { 778 $arguments = func_get_args(); 779 $columnName = array_shift($arguments); 776 780 $column = $this->getColName($columnName); 777 if(!is_array($arguments))778 {779 $arguments = func_get_args();780 array_shift($arguments);781 }782 781 list($value, $comparison) = sfPropelFinderUtils::getValueAndComparisonFromArguments($arguments); 783 $this->addCondition('or', $column, $value, $comparison); 784 785 return $this; 786 } 787 788 /** 789 * Conditions have to be stocked before being really used 790 * cf. sfPropelFinder::buildCriteria() 791 */ 792 protected function addCondition($cond, $column, $value, $comparison) 782 $this->addCondition('Or', $column, $value, $comparison); 783 784 return $this; 785 } 786 787 /** 788 * Conditions have to be stored before being really used 789 * 790 * @see sfPropelFinder::buildCriteria() 791 */ 792 protected function addCondition($cond, $column, $value, $comparison, $namedCondition = null) 793 793 { 794 794 $criterion = $this->criteria->getNewCriterion($column, $value, $comparison); 795 $criterion->func = "add".$cond; 796 $this->criterions []= $criterion; 797 } 798 795 if($namedCondition) 796 { 797 $this->namedCriterions[$namedCondition] = $criterion; 798 } 799 else 800 { 801 $criterion->func = "add".$cond; 802 $this->criterions []= $criterion; 803 } 804 } 805 806 /** 807 * Combine named conditions into the main criteria or into a new named condition 808 * Named conditions are to be defined in where() 809 * 810 * @param Array $conditions list of named conditions already set by way of where() 811 * @param string $operator Combine operator ('and' or 'or') 812 * @param string $namedCondition If combined condition is to be stored for later combination (see combine()) 813 * 814 * @see where() 815 */ 816 public function combine($conditions, $operator = 'and', $namedCondition = null) 817 { 818 $addMethod = 'add'.ucfirst(strtolower(trim($operator))); 819 if(!is_Array($conditions)) 820 { 821 $conditions = array($conditions); 822 } 823 foreach($conditions as $condition) 824 { 825 if(!isset($criterion)) 826 { 827 $criterion = $this->namedCriterions[$condition]; 828 } 829 else 830 { 831 $criterion->$addMethod($this->namedCriterions[$condition]); 832 } 833 } 834 if($namedCondition) 835 { 836 $this->namedCriterions[$namedCondition] = $criterion; 837 } 838 else 839 { 840 $criterion->func = "addAnd"; 841 $this->criterions []= $criterion; 842 } 843 844 return $this; 845 } 846 799 847 /** 800 848 * We want that the Finder fuild Interface works like: … … 1093 1141 if(strpos($name, 'where') === 0) 1094 1142 { 1095 return $this->where(substr($name, 5), $arguments); 1143 array_unshift($arguments, substr($name, 5)); 1144 return call_user_func_array(array($this, 'where'), $arguments); 1096 1145 } 1097 1146 if(strpos($name, 'orderBy') === 0) … … 1111 1160 if(strpos($name, '_and') === 0) 1112 1161 { 1113 return $this->_and(substr($name, 4), $arguments); 1162 array_unshift($arguments, substr($name, 4)); 1163 return call_user_func_array(array($this, '_and'), $arguments); 1114 1164 } 1115 1165 if(strpos($name, 'and') === 0) 1116 1166 { 1117 return $this->_and(substr($name, 3), $arguments); 1167 array_unshift($arguments, substr($name, 3)); 1168 return call_user_func_array(array($this, '_and'), $arguments); 1169 1118 1170 } 1119 1171 if(strpos($name, '_or') === 0) 1120 1172 { 1121 return $this->_or(substr($name, 3), $arguments); 1173 array_unshift($arguments, substr($name, 3)); 1174 return call_user_func_array(array($this, '_or'), $arguments); 1175 1122 1176 } 1123 1177 if(strpos($name, 'or') === 0) 1124 1178 { 1125 return $this->_or(substr($name, 2), $arguments); 1179 array_unshift($arguments, substr($name, 2)); 1180 return call_user_func_array(array($this, '_or'), $arguments); 1126 1181 } 1127 1182 if(strpos($name, 'findBy') === 0) plugins/sfPropelFinderPlugin/test/unit/sfPropelFinderTest.php
r10123 r10166 65 65 ArticlePeer::doDeleteAll(); 66 66 67 $t = new lime_test(1 05, new lime_output_color());67 $t = new lime_test(113, new lime_output_color()); 68 68 69 69 $t->diag('find()'); … … 439 439 try 440 440 { 441 $article = sfPropelFinder::from('Article')->whereTitle('abc', 'def', 'ghi' );442 $t->fail('whereXXX() throws an exception when called with more than t woparameters');441 $article = sfPropelFinder::from('Article')->whereTitle('abc', 'def', 'ghi', 'jkl'); 442 $t->fail('whereXXX() throws an exception when called with more than three parameters'); 443 443 } 444 444 catch (Exception $e) 445 445 { 446 $t->pass('whereXXX() throws an exception when called with more than t woparameters');446 $t->pass('whereXXX() throws an exception when called with more than three parameters'); 447 447 } 448 448 … … 461 461 $baseSelect = "SELECT $columns FROM article WHERE "; 462 462 463 $finder = sfPropelFinder::from('Article')->whereTitle('foo')->_orTitle('bar'); 463 $finder = sfPropelFinder::from('Article')-> 464 where('Title', 'foo')-> 465 _or('Title', 'bar'); 464 466 $finder->find(); 465 467 $t->is( … … 469 471 ); 470 472 471 $finder = sfPropelFinder::from('Article')->whereTitle('foo')->_orCategoryId(1); 473 $finder = sfPropelFinder::from('Article')-> 474 where('Title', 'foo')-> 475 _or('CategoryId', 1); 472 476 $finder->find(); 473 477 $t->is( … … 477 481 ); 478 482 479 $finder = sfPropelFinder::from('Article')->whereTitle('foo')->_andTitle('bar'); 483 $finder = sfPropelFinder::from('Article')-> 484 where('Title', 'foo')-> 485 _and('Title', 'bar'); 480 486 $finder->find(); 481 487 $t->is( … … 485 491 ); 486 492 487 $finder = sfPropelFinder::from('Article')->whereTitle('foo')->_andCategoryId(1); 493 $finder = sfPropelFinder::from('Article')-> 494 where('Title', 'foo')-> 495 _and('CategoryId', 1); 488 496 $finder->find(); 489 497 $t->is( … … 493 501 ); 494 502 495 $finder = sfPropelFinder::from('Article')->whereCategoryId(1)->_andTitle('foo')->_orTitle('bar'); 503 $finder = sfPropelFinder::from('Article')-> 504 where('CategoryId', 1)-> 505 _and('Title', 'foo')-> 506 _or('Title', 'bar'); 496 507 $finder->find(); 497 508 $t->is( … … 523 534 '_or() works on a multiple jointure' 524 535 ); 536 537 $t->diag('combine()'); 538 539 $columns = "article.ID, article.VERSION, article.TITLE, article.CATEGORY_ID"; 540 $baseSelect = "SELECT $columns FROM article WHERE "; 541 542 $finder = sfPropelFinder::from('Article')-> 543 where('Title', '=', 'foo', 'cond1')-> 544 where('Title', '=', 'bar'); 545 $finder->find(); 546 $t->is( 547 $finder->getLatestQuery(), 548 $baseSelect . "article.TITLE='bar'", 549 'where() called with a named condition does not affect the SQL until it is combined' 550 ); 551 552 $finder = sfPropelFinder::from('Article')-> 553 where('Title', '=', 'foo', 'cond1')-> 554 where('Title', '=', 'bar', 'cond2')-> 555 combine(array('cond1', 'cond2'), 'or'); 556 $finder->find(); 557 $t->is( 558 $finder->getLatestQuery(), 559 $baseSelect . "(article.TITLE='foo' OR article.TITLE='bar')", 560 'combine() combines conditions into the main criteria' 561 ); 562 563 $finder = sfPropelFinder::from('Article')-> 564 where('Title', '=', 'foo', 'cond1')-> 565 where('Title', '=', 'bar', 'cond2')-> 566 combine(array('cond1', 'cond2'), 'and'); 567 $finder->find(); 568 $t->is( 569 $finder->getLatestQuery(), 570 $baseSelect . "(article.TITLE='foo' AND article.TITLE='bar')", 571 'combine() combines conditions into the main criteria' 572 ); 573 574 $finder = sfPropelFinder::from('Article')-> 575 where('Title', '=', 'foo', 'cond1')-> 576 where('Title', '=', 'bar', 'cond2')-> 577 where('Title', '=', 'foobar')-> 578 combine(array('cond1', 'cond2'), 'or'); 579 $finder->find(); 580 $t->is( 581 $finder->getLatestQuery(), 582 $baseSelect . "(article.TITLE='foobar' AND (article.TITLE='foo' OR article.TITLE='bar'))", 583 'combine() clauses live well with the usual conditions' 584 ); 585 586 $finder = sfPropelFinder::from('Article')-> 587 where('Title', '=', 'foo', 'cond1')-> 588 where('Title', '=', 'bar', 'cond2')-> 589 combine(array('cond1', 'cond2'), 'or')-> 590 where('Title', '=', 'foobar'); 591 $finder->find(); 592 $t->is( 593 $finder->getLatestQuery(), 594 $baseSelect . "((article.TITLE='foo' OR article.TITLE='bar') AND article.TITLE='foobar')", 595 'combine() clauses live well with the usual conditions and appear ordered as they were called' 596 ); 597 598 $finder = sfPropelFinder::from('Article')-> 599 where('Title', '=', 'foo', 'cond1')-> 600 where('Title', '=', 'bar', 'cond2')-> 601 where('Title', '=', 'foobar', 'cond3')-> 602 combine(array('cond1', 'cond2'), 'or', 'cond4')-> 603 combine(array('cond4', 'cond3'), 'and'); 604 $finder->find(); 605 $t->is( 606 $finder->getLatestQuery(), 607 $baseSelect . "((article.TITLE='foo' OR article.TITLE='bar') AND article.TITLE='foobar')", 608 'combine() can return a named condition' 609 ); 610 611 $finder = sfPropelFinder::from('Article')-> 612 where('Title', '=', 'foo', 'cond1')-> 613 where('Title', '=', 'bar', 'cond2')-> 614 where('Title', '=', 'foobar', 'cond3')-> 615 where('Title', '=', 'boofar', 'cond4')-> 616 combine(array('cond1', 'cond2'), 'or', 'cond6')-> 617 combine(array('cond3', 'cond4'), 'or', 'cond7')-> 618 combine(array('cond6', 'cond7'), 'and'); 619 $finder->find(); 620 $t->is( 621 $finder->getLatestQuery(), 622 $baseSelect . "((article.TITLE='foo' OR article.TITLE='bar') AND (article.TITLE='foobar' OR article.TITLE='boofar'))", 623 'combine() allows for imbricated conditions' 624 ); 625 626 $finder = sfPropelFinder::from('Article')-> 627 where('Title', '=', 'foo', 'cond1')-> 628 where('Title', '=', 'bar', 'cond2')-> 629 where('Title', '=', 'foobar', 'cond3')-> 630 combine(array('cond1', 'cond2', 'cond3'), 'or'); 631 $finder->find(); 632 $t->is( 633 $finder->getLatestQuery(), 634 $baseSelect . "((article.TITLE='foo' OR article.TITLE='bar') OR article.TITLE='foobar')", 635 'combine() can combine more than two conditions' 636 ); 637 525 638 526 639 $t->diag('relatedTo()');