Changeset 1571


Ignore:
Timestamp:
21.02.2010 15:30:02 (7 months ago)
Author:
francois
Message:

[1.5][nested set] Slight getChildren() refactoring:

  • Added internal cache for children
  • Renamed getNumberOfChildren() to countChildren()
  • Added addNestedSetChild() to allow population of internal cache

(refs #854)

Location:
branches/1.5
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • branches/1.5/docs/behavior/nested_set.txt

    r1497 r1571  
    7373echo $s2->getLevel();    // 1 
    7474echo $s2->hasChildren(); // true 
    75 echo $s2->getNumberOfChildren(); // 1 
     75echo $s2->countChildren(); // 1 
    7676echo $s2->hasSiblings(); // true 
    7777}}} 
     
    290290bool  hasNextSibling() 
    291291bool  hasChildren() 
    292 int   getNumberOfChildren() 
     292int   countChildren() 
    293293int   getNumberOfDescendants() 
    294294 
  • branches/1.5/generator/lib/behavior/nestedset/NestedSetBehaviorObjectBuilderModifier.php

    r1513 r1571  
    7878 */ 
    7979protected \$nestedSetQueries = array(); 
     80 
     81/** 
     82 * Internal cache for children nodes 
     83 * @var        null|PropelObjectCollection 
     84 */ 
     85protected \$nestedSetChildren = null; 
    8086"; 
    8187        } 
     
    102108$peerClassname::shiftRLValues(-2, \$this->getRightValue() + 1, null" . ($this->behavior->useScope() ? ", \$this->getScopeValue()" : "") . ", \$con); 
    103109"; 
     110        } 
     111         
     112        public function objectClearReferences($builder) 
     113        { 
     114                return "\$this->clearNestedSetChildren();"; 
    104115        } 
    105116         
     
    144155                $this->addGetNextSibling($script); 
    145156                 
     157                $this->addNestedSetChildrenClear($script); 
     158                $this->addNestedSetChildrenInit($script); 
     159                $this->addNestedSetChildAdd($script); 
    146160                $this->addHasChildren($script); 
    147161                $this->addGetChildren($script); 
    148                 $this->addGetNumberOfChildren($script); 
     162                $this->addCountChildren($script); 
     163                 
    149164                $this->addGetFirstChild($script); 
    150165                $this->addGetLastChild($script); 
     
    571586"; 
    572587        } 
    573          
     588 
     589        protected function addNestedSetChildrenClear(&$script) 
     590        { 
     591                $script .= " 
     592/** 
     593 * Clears out the \$nestedSetChildren collection 
     594 * 
     595 * This does not modify the database; however, it will remove any associated objects, causing 
     596 * them to be refetched by subsequent calls to accessor method. 
     597 * 
     598 * @return     void 
     599 */ 
     600public function clearNestedSetChildren() 
     601{ 
     602        \$this->nestedSetChildren = null; 
     603} 
     604"; 
     605        } 
     606 
     607        protected function addNestedSetChildrenInit(&$script) 
     608        { 
     609                $script .= " 
     610/** 
     611 * Initializes the \$nestedSetChildren collection. 
     612 * 
     613 * @return     void 
     614 */ 
     615public function initNestedSetChildren() 
     616{ 
     617        \$this->nestedSetChildren = new PropelObjectCollection(); 
     618        \$this->nestedSetChildren->setModel('" . $this->builder->getNewStubObjectBuilder($this->table)->getClassname() . "'); 
     619} 
     620"; 
     621        } 
     622 
     623        protected function addNestedSetChildAdd(&$script) 
     624        { 
     625                $objectClassname = $this->objectClassname; 
     626                $objectName = '$' . $this->table->getStudlyPhpName(); 
     627                $script .= " 
     628/** 
     629 * Adds an element to the internal \$nestedSetChildren collection. 
     630 * Beware that this doesn't insert a node in the tree. 
     631 * This method is only used to facilitate children hydration. 
     632 * 
     633 * @param      $objectClassname $objectName 
     634 * 
     635 * @return     void 
     636 */ 
     637public function addNestedSetChild($objectName) 
     638{ 
     639        if (\$this->nestedSetChildren === null) { 
     640                \$this->initNestedSetChildren(); 
     641        } 
     642        if (!\$this->nestedSetChildren->contains($objectName)) { // only add it if the **same** object is not already associated 
     643                \$this->nestedSetChildren[]= $objectName; 
     644                // {$objectName}->setParent(\$this); 
     645        } 
     646} 
     647"; 
     648        } 
     649         
    574650        protected function addHasChildren(&$script) 
    575651        { 
     
    596672 * Gets the children of the given node 
    597673 * 
    598  * @param      Criteria \$query Criteria to filter results. 
     674 * @param      Criteria  \$criteria Criteria to filter results. 
    599675 * @param      PropelPDO \$con Connection to use. 
    600  * @return     array            List of $objectClassname objects 
    601  */ 
    602 public function getChildren(\$query = null, PropelPDO \$con = null) 
    603 { 
    604         if(\$this->isLeaf()) { 
    605                 return array(); 
     676 * @return     array     List of $objectClassname objects 
     677 */ 
     678public function getChildren(\$criteria = null, PropelPDO \$con = null) 
     679{ 
     680        if(null === \$this->nestedSetChildren || null !== \$criteria) { 
     681                if (\$this->isLeaf() || (\$this->isNew() && null === \$this->nestedSetChildren)) { 
     682                        // return empty collection 
     683                        \$this->initNestedSetChildren(); 
     684                } else { 
     685                        \$nestedSetChildren = $queryClassname::create(null, \$criteria) 
     686                        ->childrenOf(\$this) 
     687                        ->orderByBranch() 
     688                                ->find(\$con); 
     689                        if (null !== \$criteria) { 
     690                                return \$nestedSetChildren; 
     691                        } 
     692                        \$this->nestedSetChildren = \$nestedSetChildren; 
     693                } 
     694        } 
     695        return \$this->nestedSetChildren; 
     696} 
     697"; 
     698        } 
     699 
     700        protected function addCountChildren(&$script) 
     701        { 
     702                $objectClassname = $this->objectClassname; 
     703                $peerClassname = $this->peerClassname; 
     704                $queryClassname = $this->queryClassname; 
     705                $script .= " 
     706/** 
     707 * Gets number of children for the given node 
     708 * 
     709 * @param      Criteria  \$criteria Criteria to filter results.  
     710 * @param      PropelPDO \$con Connection to use. 
     711 * @return     int       Number of children 
     712 */ 
     713public function countChildren(\$criteria = null, PropelPDO \$con = null) 
     714{ 
     715        if(null === \$this->nestedSetChildren || null !== \$criteria) { 
     716                if (\$this->isLeaf() || (\$this->isNew() && null === \$this->nestedSetChildren)) { 
     717                        return 0; 
     718                } else { 
     719                        return $queryClassname::create(null, \$criteria) 
     720                                ->childrenOf(\$this) 
     721                                ->count(\$con); 
     722                } 
    606723        } else { 
    607                 return $queryClassname::create(null, \$query) 
    608                         ->childrenOf(\$this) 
    609                         ->orderByBranch() 
    610                         ->find(\$con); 
    611         } 
    612 } 
    613 "; 
    614         } 
    615  
    616         protected function addGetNumberOfChildren(&$script) 
    617         { 
    618                 $objectClassname = $this->objectClassname; 
    619                 $peerClassname = $this->peerClassname; 
    620                 $queryClassname = $this->queryClassname; 
    621                 $script .= " 
    622 /** 
    623  * Gets number of children for the given node 
    624  * 
    625  * @param      Criteria \$query Criteria to filter results.  
    626  * @param      PropelPDO \$con Connection to use. 
    627  * @return     int              Number of children 
    628  */ 
    629 public function getNumberOfChildren(\$query = null, PropelPDO \$con = null) 
    630 { 
    631         if(\$this->isLeaf()) { 
    632                 return 0; 
    633         } else { 
    634                 return $queryClassname::create(null, \$query) 
    635                         ->childrenOf(\$this) 
    636                         ->count(\$con); 
     724                return count(\$this->nestedSetChildren); 
    637725        } 
    638726} 
     
    890978                } 
    891979                $script .= " 
     980        // update the children collection of the parent 
     981        \$parent->addNestedSetChild(\$this); 
     982         
    892983        // Keep the tree modification query for the save() transaction 
    893984        \$this->nestedSetQueries []= array( 
     
    9321023                } 
    9331024                $script .= " 
     1025        // update the children collection of the parent 
     1026        \$parent->addNestedSetChild(\$this); 
     1027         
    9341028        // Keep the tree modification query for the save() transaction 
    9351029        \$this->nestedSetQueries []= array( 
     
    13511445 
    13521446/** 
     1447 * Alias for countChildren(), for BC with Propel 1.4 nested sets 
     1448 * 
     1449 * @deprecated since 1.5 
     1450 * @see        setParent 
     1451 */ 
     1452public function getNumberOfChildren(PropelPDO \$con = null) 
     1453{ 
     1454        return \$this->countChildren(null, \$con); 
     1455} 
     1456 
     1457 
     1458/** 
    13531459 * Alias for getPrevSibling(), for BC with Propel 1.4 nested sets 
    13541460 * 
  • branches/1.5/generator/lib/behavior/nestedset/NestedSetBehaviorPeerBuilderModifier.php

    r1541 r1571  
    442442                        } else if ($col->getPhpName() == $this->getColumnPhpName('level_column')) { 
    443443                                $script .= " 
    444                                         \$object->setLevel(\$row[$n]);"; 
     444                                        \$object->setLevel(\$row[$n]); 
     445                                        \$object->clearNestedSetChildren();"; 
    445446                        } 
    446447                        $n++; 
  • branches/1.5/generator/lib/builder/om/PHP5ObjectBuilder.php

    r1570 r1571  
    41244124"; 
    41254125 
     4126                $this->applyBehaviorModifier('objectClearReferences', $script, "                "); 
     4127                 
    41264128                foreach ($vars as $varName) { 
    41274129                        $script .= " 
  • branches/1.5/test/testsuite/generator/behavior/nestedset/NestedSetBehaviorObjectBuilderModifierTest.php

    r1497 r1571  
    385385                       t6 t7 
    386386                */ 
    387                 $this->assertEquals(array(), $t2->getChildren(), 'getChildren() returns an empty array for leafs'); 
    388                 $descendants = $t3->getChildren(); 
     387        $this->assertTrue($t2->getChildren() instanceof PropelObjectCollection, 'getChildren() returns a collection'); 
     388                $this->assertEquals(0, count($t2->getChildren()), 'getChildren() returns an empty collection for leafs'); 
     389                $children = $t3->getChildren(); 
    389390                $expected = array( 
    390391                        't4' => array(5, 6, 2),  
    391392                        't5' => array(7, 12, 2),  
    392393                ); 
    393                 $this->assertEquals($expected, $this->dumpNodes($descendants, true), 'getChildren() returns an array of children'); 
     394                $this->assertEquals($expected, $this->dumpNodes($children, true), 'getChildren() returns a collection of children'); 
    394395                $c = new Criteria(); 
    395396                $c->add(Table9Peer::TITLE, 't5'); 
    396                 $descendants = $t3->getDescendants($c); 
     397                $children = $t3->getChildren($c); 
    397398                $expected = array( 
    398399                        't5' => array(7, 12, 2),  
    399400                ); 
    400                 $this->assertEquals($expected, $this->dumpNodes($descendants, true), 'getChildren() accepts a criteria as parameter'); 
    401         } 
    402          
    403         public function testGetNumberOfChildren() 
    404         { 
    405                 list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
    406                 /* Tree used for tests 
    407                  t1 
    408                  |  \ 
    409                  t2 t3 
    410                     |  \ 
    411                     t4 t5 
    412                        |  \ 
    413                        t6 t7 
    414                 */ 
    415                 $this->assertEquals(0, $t2->getNumberOfChildren(), 'getNumberOfChildren() returns 0 for leafs'); 
    416                 $this->assertEquals(2, $t3->getNumberOfChildren(), 'getNumberOfChildren() returns the number of children'); 
     401                $this->assertEquals($expected, $this->dumpNodes($children, true), 'getChildren() accepts a criteria as parameter'); 
     402        } 
     403 
     404        public function testGetChildrenCache() 
     405        { 
     406                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     407                $con = Propel::getConnection(); 
     408                $count = $con->getQueryCount(); 
     409                $children = $t3->getChildren(null, $con); 
     410                $children = $t3->getChildren(null, $con); 
     411                $this->assertEquals($count + 1, $con->getQueryCount(), 'getChildren() only issues a query once'); 
     412                $expected = array( 
     413                        't4' => array(5, 6, 2),  
     414                        't5' => array(7, 12, 2),  
     415                ); 
     416                $this->assertEquals($expected, $this->dumpNodes($children, true), 'getChildren() returns a collection of children'); 
     417                // when using criteria, cache is not used 
    417418                $c = new Criteria(); 
    418419                $c->add(Table9Peer::TITLE, 't5'); 
    419                 $this->assertEquals(1, $t3->getNumberOfChildren($c), 'getNumberOfChildren() accepts a criteria as parameter'); 
     420                $children = $t3->getChildren($c, $con); 
     421                $this->assertEquals($count + 2, $con->getQueryCount(), 'getChildren() issues a new query when âssed a non-null Criteria'); 
     422                $expected = array( 
     423                        't5' => array(7, 12, 2),  
     424                ); 
     425                $this->assertEquals($expected, $this->dumpNodes($children, true), 'getChildren() accepts a criteria as parameter'); 
     426                // but not erased either 
     427                $children = $t3->getChildren(null, $con); 
     428                $this->assertEquals($count + 2, $con->getQueryCount(), 'getChildren() keeps its internal cache after being called with a Criteria'); 
     429                $expected = array( 
     430                        't4' => array(5, 6, 2),  
     431                        't5' => array(7, 12, 2),  
     432                ); 
     433        $this->assertEquals($expected, $this->dumpNodes($children, true), 'getChildren() returns a collection of children'); 
     434        } 
     435         
     436        public function testCountChildren() 
     437        { 
     438                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     439                /* Tree used for tests 
     440                 t1 
     441                 |  \ 
     442                 t2 t3 
     443                    |  \ 
     444                    t4 t5 
     445                       |  \ 
     446                       t6 t7 
     447                */ 
     448                $this->assertEquals(0, $t2->countChildren(), 'countChildren() returns 0 for leafs'); 
     449                $this->assertEquals(2, $t3->countChildren(), 'countChildren() returns the number of children'); 
     450                $c = new Criteria(); 
     451                $c->add(Table9Peer::TITLE, 't5'); 
     452                $this->assertEquals(1, $t3->countChildren($c), 'countChildren() accepts a criteria as parameter'); 
     453        } 
     454 
     455        public function testCountChildrenCache() 
     456        { 
     457                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     458                /* Tree used for tests 
     459                 t1 
     460                 |  \ 
     461                 t2 t3 
     462                    |  \ 
     463                    t4 t5 
     464                       |  \ 
     465                       t6 t7 
     466                */ 
     467                $con = Propel::getConnection(); 
     468                $count = $con->getQueryCount(); 
     469                $children = $t3->getChildren(null, $con); 
     470                $nbChildren = $t3->countChildren(null, $con); 
     471                $this->assertEquals($count + 1, $con->getQueryCount(), 'countChildren() uses the internal collection when passed no Criteria'); 
     472                $nbChildren = $t3->countChildren(new Criteria(), $con); 
     473                $this->assertEquals($count + 2, $con->getQueryCount(), 'countChildren() issues a new query when passed a Criteria'); 
    420474        } 
    421475         
     
    847901        } 
    848902 
     903        public function testMoveToFirstChildOfAndChildrenCache() 
     904        { 
     905                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     906                /* Tree used for tests 
     907                 t1 
     908                 |  \ 
     909                 t2 t3 
     910                    |  \ 
     911                    t4 t5 
     912                       |  \ 
     913                       t6 t7 
     914                */ 
     915                // fill children cache 
     916                $t3->getChildren(); 
     917                $t1->getChildren(); 
     918                // move 
     919                $t5->moveToFirstChildOf($t1); 
     920                $children = $t3->getChildren(); 
     921                $expected = array( 
     922                        't4' => array(11, 12, 2),  
     923                ); 
     924                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToFirstChildOf() reinitializes the child collection of all concerned nodes'); 
     925                $children = $t1->getChildren(); 
     926                $expected = array( 
     927                        't5' => array(2, 7, 1),  
     928                        't2' => array(8, 9, 1),  
     929                        't3' => array(10, 13, 1),  
     930                ); 
     931                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToFirstChildOf() reinitializes the child collection of all concerned nodes'); 
     932        } 
     933         
    849934        public function testMoveToLastChildOf() 
    850935        { 
     
    907992        } 
    908993 
     994        public function testMoveToLastChildOfAndChildrenCache() 
     995        { 
     996                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     997                /* Tree used for tests 
     998                 t1 
     999                 |  \ 
     1000                 t2 t3 
     1001                    |  \ 
     1002                    t4 t5 
     1003                       |  \ 
     1004                       t6 t7 
     1005                */ 
     1006                // fill children cache 
     1007                $t3->getChildren(); 
     1008                $t1->getChildren(); 
     1009                // move 
     1010                $t5->moveToLastChildOf($t1); 
     1011                $children = $t3->getChildren(); 
     1012                $expected = array( 
     1013                        't4' => array(5, 6, 2),  
     1014                ); 
     1015                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToLastChildOf() reinitializes the child collection of all concerned nodes'); 
     1016                $children = $t1->getChildren(); 
     1017                $expected = array( 
     1018                        't2' => array(2, 3, 1),  
     1019                        't3' => array(4, 7, 1),  
     1020                        't5' => array(8, 13, 1),  
     1021                ); 
     1022                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToLastChildOf() reinitializes the child collection of all concerned nodes'); 
     1023        } 
     1024 
    9091025        public function testMoveToPrevSiblingOf() 
    9101026        { 
     
    9951111                $this->assertEquals($expected, $this->dumpTree(), 'moveToPrevSiblingOf() moves the entire subtree at the same level correctly'); 
    9961112        } 
    997          
     1113 
     1114        public function testMoveToPrevSiblingOfAndChildrenCache() 
     1115        { 
     1116                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     1117                /* Tree used for tests 
     1118                 t1 
     1119                 |  \ 
     1120                 t2 t3 
     1121                    |  \ 
     1122                    t4 t5 
     1123                       |  \ 
     1124                       t6 t7 
     1125                */ 
     1126                // fill children cache 
     1127                $t3->getChildren(); 
     1128                $t1->getChildren(); 
     1129                // move 
     1130                $t5->moveToPrevSiblingOf($t2); 
     1131                $children = $t3->getChildren(); 
     1132                $expected = array( 
     1133                        't4' => array(11, 12, 2),  
     1134                ); 
     1135                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToPrevSiblingOf() reinitializes the child collection of all concerned nodes'); 
     1136                $children = $t1->getChildren(); 
     1137                $expected = array( 
     1138                        't5' => array(2, 7, 1),  
     1139                        't2' => array(8, 9, 1),  
     1140                        't3' => array(10, 13, 1),  
     1141                ); 
     1142                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToPrevSiblingOf() reinitializes the child collection of all concerned nodes'); 
     1143        } 
     1144 
     1145        public function testMoveToNextSiblingOfAndChildrenCache() 
     1146        { 
     1147                list($t1, $t2, $t3, $t4, $t5, $t6, $t7) = $this->initTree(); 
     1148                /* Tree used for tests 
     1149                 t1 
     1150                 |  \ 
     1151                 t2 t3 
     1152                    |  \ 
     1153                    t4 t5 
     1154                       |  \ 
     1155                       t6 t7 
     1156                */ 
     1157                // fill children cache 
     1158                $t3->getChildren(); 
     1159                $t1->getChildren(); 
     1160                // move 
     1161                $t5->moveToNextSiblingOf($t3); 
     1162                $children = $t3->getChildren(); 
     1163                $expected = array( 
     1164                        't4' => array(5, 6, 2),  
     1165                ); 
     1166                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToNextSiblingOf() reinitializes the child collection of all concerned nodes'); 
     1167                $children = $t1->getChildren(); 
     1168                $expected = array( 
     1169                        't2' => array(2, 3, 1),  
     1170                        't3' => array(4, 7, 1),  
     1171                        't5' => array(8, 13, 1),  
     1172                ); 
     1173                $this->assertEquals($expected, $this->dumpNodes($children, true), 'moveToNextSiblingOf() reinitializes the child collection of all concerned nodes'); 
     1174        } 
     1175 
    9981176        public function testMoveToNextSiblingOf() 
    9991177        { 
     
    11391317        public function testCompatibilityProxies() 
    11401318        { 
    1141                 $proxies = array('createRoot', 'retrieveParent', 'setParentNode', 'retrievePrevSibling', 'retrieveNextSibling', 'retrieveFirstChild', 'retrieveLastChild', 'getPath'); 
     1319                $proxies = array('createRoot', 'retrieveParent', 'setParentNode', 'getNumberOfChildren', 'retrievePrevSibling', 'retrieveNextSibling', 'retrieveFirstChild', 'retrieveLastChild', 'getPath'); 
    11421320                foreach ($proxies as $method) { 
    11431321                        $this->assertFalse(method_exists('Table9', $method), 'proxies are not enabled by default'); 
Note: See TracChangeset for help on using the changeset viewer.