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 * @subpackage model
*/ */
class Hierarchy extends DataObjectDecorator { class Hierarchy extends DataObjectDecorator {
protected $markedNodes; protected $markedNodes;
protected $markingFilter; protected $markingFilter;
/**
* @var Int
*/
protected $_cache_numChildren;
function augmentSQL(SQLQuery &$query) { function augmentSQL(SQLQuery &$query) {
} }
@ -475,31 +482,33 @@ class Hierarchy extends DataObjectDecorator {
"\"ParentID\" = " . (int)$this->owner->ID, "\"$baseClass\".\"ID\" ASC"); "\"ParentID\" = " . (int)$this->owner->ID, "\"$baseClass\".\"ID\" ASC");
} }
/** /**
* Cache for numChildren(). * Return the number of direct children.
*/ * By default, values are cached after the first invocation.
private static $num_children_cache = array(); * Can be augumented by {@link augmentNumChildrenCountQuery()}.
*
/** * @param Boolean $cache
* Return the number of children
* @return int * @return int
*/ */
public function numChildren() { public function numChildren($cache = true) {
$baseClass = ClassInfo::baseDataClass($this->owner->class); $baseClass = ClassInfo::baseDataClass($this->owner->class);
// Build the cache for this class if it doesn't exist. // 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. // 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('augmentSQL', $query);
$this->owner->extend('augmentNumChildrenCountQuery', $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. // 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_children = null;
$this->_cache_allChildrenIncludingDeleted = null; $this->_cache_allChildrenIncludingDeleted = null;
$this->_cache_allChildren = null; $this->_cache_allChildren = null;
$this->_cache_numChildren = null;
} }
} }

View File

@ -61,6 +61,22 @@ class HierarchyTest extends SapphireTest {
$this->assertEquals($this->objFromFixture('Page', 'page2b')->numChildren(), 0); $this->assertEquals($this->objFromFixture('Page', 'page2b')->numChildren(), 0);
$this->assertEquals($this->objFromFixture('Page', 'page3a')->numChildren(), 0); $this->assertEquals($this->objFromFixture('Page', 'page3a')->numChildren(), 0);
$this->assertEquals($this->objFromFixture('Page', 'page3b')->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()'
);
} }
} }