ENHANCEMENT Changed Hierarchy->numChildren() caching to be instance specific and respect flushCache(). This increases the amount of queries on large sets, but decreases the time for a single instance call (implemented in r89999)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90084 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2009-10-26 20:56:54 +00:00
parent 2527b1543d
commit 5ca90fd00b
2 changed files with 42 additions and 16 deletions

View File

@ -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;
}
}

View File

@ -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()'
);
}
}