mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
5b7a84141b
* NEW: Add Hierarchy::prepopulate_numchildren_cache() API: Hierarchy::stageChildren() customisations must be applied to the base class and not include record-specific behaviour. Adds the ability to prepopulate the cache for Hierarchy::numChildren() in a batch. Note that this optimisation means that stageChildren() is not called on each record in order to calculate numChildren(). This means that the structure of the stageChildren() query must be the same for all records and the behaviour cannot be customised only for a subclass of the base data class. For example, apply your customisations to SiteTree and not a subclass. This is an useful part of optimising the query count on tree generation. See https://github.com/silverstripe/silverstripe-framework/issues/8379 * NEW: Add Hierarchy::prepopulateTreeDataCache() This provides a more extensible way of preopulating caches for optimised tree generation. Fixes https://github.com/silverstripe/silverstripe-framework/issues/8391
150 lines
5.3 KiB
PHP
150 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Versioned\Tests;
|
|
|
|
use SilverStripe\Dev\SapphireTest;
|
|
use SilverStripe\ORM\DataObject;
|
|
use SilverStripe\ORM\Hierarchy\Hierarchy;
|
|
use SilverStripe\Versioned\Versioned;
|
|
use SilverStripe\ORM\Tests\HierarchyTest\TestObject;
|
|
use SilverStripe\ORM\Tests\HierarchyTest\HideTestObject;
|
|
use SilverStripe\ORM\Tests\HierarchyTest\HideTestSubObject;
|
|
|
|
/**
|
|
* @internal Only test the right values are returned, not that the cache is actually used.
|
|
*/
|
|
class HierachyCacheTest extends SapphireTest
|
|
{
|
|
|
|
protected static $fixture_file = 'HierarchyTest.yml';
|
|
|
|
protected static $extra_dataobjects = array(
|
|
TestObject::class,
|
|
HideTestObject::class,
|
|
HideTestSubObject::class,
|
|
);
|
|
|
|
public function setUp()
|
|
{
|
|
parent::setUp();
|
|
TestObject::singleton()->flushCache();
|
|
}
|
|
|
|
public static function setUpBeforeClass()
|
|
{
|
|
parent::setUpBeforeClass();
|
|
HideTestObject::config()->update(
|
|
'hide_from_hierarchy',
|
|
[ HideTestSubObject::class ]
|
|
);
|
|
}
|
|
|
|
public function cacheNumChildrenDataProvider()
|
|
{
|
|
return [
|
|
[TestObject::class, 'obj1', false, 0, 'childless object should have a numChildren of 0'],
|
|
[TestObject::class, 'obj1', true, 0, 'childless object should have a numChildren of 0 when cache'],
|
|
[TestObject::class, 'obj2', false, 2, 'Root object numChildren should count direct children'],
|
|
[TestObject::class, 'obj2', true, 2, 'Root object numChildren should count direct children when cache'],
|
|
[TestObject::class, 'obj3a', false, 2, 'Sub object numChildren should count direct children'],
|
|
[TestObject::class, 'obj3a', true, 2, 'Sub object numChildren should count direct children when cache'],
|
|
[TestObject::class, 'obj3d', false, 0, 'Childess Sub object numChildren should be 0'],
|
|
[TestObject::class, 'obj3d', true, 0, 'Childess Sub object numChildren should be 0 when cache'],
|
|
[HideTestObject::class, 'obj4', false, 1, 'Hidden object should not be included in count'],
|
|
[HideTestObject::class, 'obj4', true, 1, 'Hidden object should not be included in couunt when cache']
|
|
];
|
|
}
|
|
|
|
|
|
/**
|
|
* @dataProvider cacheNumChildrenDataProvider
|
|
*/
|
|
public function testNumChildrenCache($className, $identifier, $cache, $expected, $message)
|
|
{
|
|
$node = $this->objFromFixture($className, $identifier);
|
|
|
|
$actual = $node->numChildren($cache);
|
|
|
|
$this->assertEquals($expected, $actual, $message);
|
|
|
|
if ($cache) {
|
|
// When caching is eanbled, try re-accessing the numChildren value to make sure it doesn't change.
|
|
$actual = $node->numChildren($cache);
|
|
$this->assertEquals($expected, $actual, $message);
|
|
}
|
|
}
|
|
|
|
public function prepopulateCacheNumChildrenDataProvider()
|
|
{
|
|
return [
|
|
[
|
|
TestObject::class, [],
|
|
'obj1', false, 0, 'childless object should have a numChildren of 0'
|
|
],
|
|
[
|
|
TestObject::class, [],
|
|
'obj1', true, 0, 'childless object should have a numChildren of 0 when cache'
|
|
],
|
|
[
|
|
TestObject::class, [2],
|
|
'obj1', false, 0, 'childless object should have a numChildren of 0'
|
|
],
|
|
[
|
|
TestObject::class, [2],
|
|
'obj1', true, 0, 'childless object should have a numChildren of 0 when cache'
|
|
],
|
|
[
|
|
TestObject::class, [],
|
|
'obj2', false, 2, 'Root object numChildren should count direct children'
|
|
],
|
|
[
|
|
TestObject::class, [],
|
|
'obj2', true, 2, 'Root object numChildren should count direct children when cache'
|
|
],
|
|
[
|
|
TestObject::class, [2],
|
|
'obj2', false, 2, 'Root object numChildren should count direct children'
|
|
],
|
|
[
|
|
TestObject::class, [2],
|
|
'obj2', true, 2, 'Root object numChildren should count direct children when cache'
|
|
],
|
|
[
|
|
HideTestObject::class, [],
|
|
'obj4', false, 1, 'Hidden object should not be included in count'
|
|
],
|
|
[
|
|
HideTestObject::class, [],
|
|
'obj4', true, 1, 'Hidden object should not be included in count when cache'
|
|
],
|
|
[
|
|
HideTestObject::class, [2],
|
|
'obj4', false, 1, 'Hidden object should not be included in count'
|
|
],
|
|
[
|
|
HideTestObject::class, [2],
|
|
'obj4', true, 1, 'Hidden object should not be included in count when cache'
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider prepopulateCacheNumChildrenDataProvider
|
|
*/
|
|
public function testPrepopulatedNumChildrenCache(
|
|
$className,
|
|
$idList,
|
|
$identifier,
|
|
$cache,
|
|
$expected,
|
|
$message
|
|
) {
|
|
DataObject::singleton($className)->prepopulateTreeDataCache($idList, ['numChildrenMethod' => 'numChildren']);
|
|
$node = $this->objFromFixture($className, $identifier);
|
|
|
|
$actual = $node->numChildren($cache);
|
|
|
|
$this->assertEquals($expected, $actual, $message);
|
|
}
|
|
}
|