diff --git a/core/model/Hierarchy.php b/core/model/Hierarchy.php index 800013ab8..f45fc6b7e 100755 --- a/core/model/Hierarchy.php +++ b/core/model/Hierarchy.php @@ -6,9 +6,16 @@ * @subpackage model */ class Hierarchy extends DataObjectDecorator { + protected $markedNodes; + protected $markingFilter; + /** + * @var Int + */ + protected $_cache_numChildren; + function augmentSQL(SQLQuery &$query) { } @@ -474,32 +481,34 @@ class Hierarchy extends DataObjectDecorator { return Versioned::get_including_deleted($baseClass, "\"ParentID\" = " . (int)$this->owner->ID, "\"$baseClass\".\"ID\" ASC"); } - /** - * Cache for numChildren(). - */ - private static $num_children_cache = array(); - - /** - * Return the number of children + * Return the number of direct children. + * By default, values are cached after the first invocation. + * Can be augumented by {@link augmentNumChildrenCountQuery()}. + * + * @param Boolean $cache * @return int */ - public function numChildren() { + public function numChildren($cache = true) { $baseClass = ClassInfo::baseDataClass($this->owner->class); // Build the cache for this class if it doesn't exist. - if(!isset(self::$num_children_cache[$baseClass])) { + if(!$cache || !is_numeric($this->_cache_numChildren)) { // We build the query in an extension-friendly way. - $query = new SQLQuery("ParentID, COUNT(*)","\"$baseClass\"", "", "", "ParentID"); + $query = new SQLQuery( + "COUNT(*)", + "\"$baseClass\"", + sprintf('"ParentID" = %d', $this->owner->ID) + ); $this->owner->extend('augmentSQL', $query); $this->owner->extend('augmentNumChildrenCountQuery', $query); - self::$num_children_cache[$baseClass] = $query->execute()->map(); + $this->_cache_numChildren = (int)$query->execute()->value(); } - + // If theres no value in the cache, it just means that it doesn't have any children. - return isset(self::$num_children_cache[$baseClass][$this->owner->ID]) ? self::$num_children_cache[$baseClass][$this->owner->ID] : 0; + return $this->_cache_numChildren; } /** @@ -657,6 +666,7 @@ class Hierarchy extends DataObjectDecorator { $this->_cache_children = null; $this->_cache_allChildrenIncludingDeleted = null; $this->_cache_allChildren = null; + $this->_cache_numChildren = null; } } diff --git a/tests/model/HierarchyTest.php b/tests/model/HierarchyTest.php index 4d4177b8b..10897a539 100644 --- a/tests/model/HierarchyTest.php +++ b/tests/model/HierarchyTest.php @@ -11,11 +11,11 @@ class HierarchyTest extends SapphireTest { $this->objFromFixture('Page', 'page2b')->delete(); $this->objFromFixture('Page', 'page3a')->delete(); $this->objFromFixture('Page', 'page3')->delete(); - + // Check that page1-3 appear at the top level of the AllHistoricalChildren tree $this->assertEquals(array("Page 1", "Page 2", "Page 3"), singleton('Page')->AllHistoricalChildren()->column('Title')); - + // Check that both page 2 children are returned $page2 = $this->objFromFixture('Page', 'page2'); $this->assertEquals(array("Page 2a", "Page 2b"), @@ -23,7 +23,7 @@ class HierarchyTest extends SapphireTest { // Page 3 has been deleted; let's bring it back from the grave $page3 = Versioned::get_including_deleted("SiteTree", "\"Title\" = 'Page 3'")->First(); - + // Check that both page 3 children are returned $this->assertEquals(array("Page 3a", "Page 3b"), $page3->AllHistoricalChildren()->column('Title')); @@ -61,6 +61,22 @@ class HierarchyTest extends SapphireTest { $this->assertEquals($this->objFromFixture('Page', 'page2b')->numChildren(), 0); $this->assertEquals($this->objFromFixture('Page', 'page3a')->numChildren(), 0); $this->assertEquals($this->objFromFixture('Page', 'page3b')->numChildren(), 0); + + $page1 = $this->objFromFixture('Page', 'page1'); + $this->assertEquals($page1->numChildren(), 0); + $page1Child1 = new Page(); + $page1Child1->ParentID = $page1->ID; + $page1Child1->write(); + $this->assertEquals($page1->numChildren(false), 1, + 'numChildren() caching can be disabled through method parameter' + ); + $page1Child2 = new Page(); + $page1Child2->ParentID = $page1->ID; + $page1Child2->write(); + $page1->flushCache(); + $this->assertEquals($page1->numChildren(), 2, + 'numChildren() caching can be disabled by flushCache()' + ); } }