mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #10077 from chrometoasters/pulls/6127-hierarchy-query-class-fix
FIX Use owner class when querying for stage and live children
This commit is contained in:
commit
8b634d45cd
@ -501,7 +501,7 @@ class TreeDropdownField extends FormField
|
|||||||
// Begin marking
|
// Begin marking
|
||||||
$markingSet->markPartialTree();
|
$markingSet->markPartialTree();
|
||||||
|
|
||||||
// Explicitely mark our search results if necessary
|
// Explicitly mark our search results if necessary
|
||||||
foreach ($this->searchIds as $id => $marked) {
|
foreach ($this->searchIds as $id => $marked) {
|
||||||
if ($marked) {
|
if ($marked) {
|
||||||
$object = $this->objectForKey($id);
|
$object = $this->objectForKey($id);
|
||||||
|
@ -4,6 +4,8 @@ namespace SilverStripe\ORM\Hierarchy;
|
|||||||
|
|
||||||
use SilverStripe\Admin\LeftAndMain;
|
use SilverStripe\Admin\LeftAndMain;
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
|
use SilverStripe\Core\ClassInfo;
|
||||||
|
use SilverStripe\Core\Extensible;
|
||||||
use SilverStripe\ORM\DataList;
|
use SilverStripe\ORM\DataList;
|
||||||
use SilverStripe\ORM\SS_List;
|
use SilverStripe\ORM\SS_List;
|
||||||
use SilverStripe\ORM\ValidationResult;
|
use SilverStripe\ORM\ValidationResult;
|
||||||
@ -28,7 +30,7 @@ class Hierarchy extends DataExtension
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The lower bounds for the amount of nodes to mark. If set, the logic will expand nodes until it reaches at least
|
* The lower bounds for the amount of nodes to mark. If set, the logic will expand nodes until it reaches at least
|
||||||
* this number, and then stops. Root nodes will always show regardless of this settting. Further nodes can be
|
* this number, and then stops. Root nodes will always show regardless of this setting. Further nodes can be
|
||||||
* lazy-loaded via ajax. This isn't a hard limit. Example: On a value of 10, with 20 root nodes, each having 30
|
* lazy-loaded via ajax. This isn't a hard limit. Example: On a value of 10, with 20 root nodes, each having 30
|
||||||
* children, the actual node count will be 50 (all root nodes plus first expanded child).
|
* children, the actual node count will be 50 (all root nodes plus first expanded child).
|
||||||
*
|
*
|
||||||
@ -284,7 +286,7 @@ class Hierarchy extends DataExtension
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of direct children. By default, values are cached after the first invocation. Can be
|
* Return the number of direct children. By default, values are cached after the first invocation. Can be
|
||||||
* augumented by {@link augmentNumChildrenCountQuery()}.
|
* augmented by {@link augmentNumChildrenCountQuery()}.
|
||||||
*
|
*
|
||||||
* @param bool $cache Whether to retrieve values from cache
|
* @param bool $cache Whether to retrieve values from cache
|
||||||
* @return int
|
* @return int
|
||||||
@ -320,7 +322,7 @@ class Hierarchy extends DataExtension
|
|||||||
/**
|
/**
|
||||||
* Pre-populate any appropriate caches prior to rendering a tree.
|
* Pre-populate any appropriate caches prior to rendering a tree.
|
||||||
* This is used to allow for the efficient rendering of tree views, notably in the CMS.
|
* This is used to allow for the efficient rendering of tree views, notably in the CMS.
|
||||||
* In the cace of Hierarchy, it caches numChildren values. Other extensions can provide an
|
* In the case of Hierarchy, it caches numChildren values. Other extensions can provide an
|
||||||
* onPrepopulateTreeDataCache(DataList $recordList = null, array $options) methods to hook
|
* onPrepopulateTreeDataCache(DataList $recordList = null, array $options) methods to hook
|
||||||
* into this event as well.
|
* into this event as well.
|
||||||
*
|
*
|
||||||
@ -333,7 +335,7 @@ class Hierarchy extends DataExtension
|
|||||||
if (empty($options['numChildrenMethod']) || $options['numChildrenMethod'] === 'numChildren') {
|
if (empty($options['numChildrenMethod']) || $options['numChildrenMethod'] === 'numChildren') {
|
||||||
$idList = is_array($recordList) ? $recordList :
|
$idList = is_array($recordList) ? $recordList :
|
||||||
($recordList instanceof DataList ? $recordList->column('ID') : null);
|
($recordList instanceof DataList ? $recordList->column('ID') : null);
|
||||||
self::prepopulate_numchildren_cache($this->owner->baseClass(), $idList);
|
self::prepopulate_numchildren_cache($this->getHierarchyBaseClass(), $idList);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->owner->extend('onPrepopulateTreeDataCache', $recordList, $options);
|
$this->owner->extend('onPrepopulateTreeDataCache', $recordList, $options);
|
||||||
@ -407,25 +409,47 @@ class Hierarchy extends DataExtension
|
|||||||
&& in_array($controller->getAction(), ["treeview", "listview", "getsubtree"]);
|
&& in_array($controller->getAction(), ["treeview", "listview", "getsubtree"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first class in the inheritance chain that has Hierarchy extension applied
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getHierarchyBaseClass(): string
|
||||||
|
{
|
||||||
|
$ancestry = ClassInfo::ancestry($this->owner);
|
||||||
|
$ancestorClass = array_shift($ancestry);
|
||||||
|
while ($ancestorClass && !Extensible::has_extension($ancestorClass, self::class)) {
|
||||||
|
$ancestorClass = array_shift($ancestry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ancestorClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return children in the stage site.
|
* Return children in the stage site.
|
||||||
*
|
*
|
||||||
* @param bool $showAll Include all of the elements, even those not shown in the menus. Only applicable when
|
* @param bool $showAll Include all of the elements, even those not shown in the menus. Only applicable when
|
||||||
* extension is applied to {@link SiteTree}.
|
* extension is applied to {@link SiteTree}.
|
||||||
* @param bool $skipParentIDFilter Set to true to supress the ParentID and ID where statements.
|
* @param bool $skipParentIDFilter Set to true to suppress the ParentID and ID where statements.
|
||||||
* @return DataList
|
* @return DataList
|
||||||
*/
|
*/
|
||||||
public function stageChildren($showAll = false, $skipParentIDFilter = false)
|
public function stageChildren($showAll = false, $skipParentIDFilter = false)
|
||||||
{
|
{
|
||||||
$hideFromHierarchy = $this->owner->config()->hide_from_hierarchy;
|
/** @var DataObject|Hierarchy $owner */
|
||||||
$hideFromCMSTree = $this->owner->config()->hide_from_cms_tree;
|
$owner = $this->owner;
|
||||||
$baseClass = $this->owner->baseClass();
|
$hideFromHierarchy = $owner->config()->hide_from_hierarchy;
|
||||||
$baseTable = $this->owner->baseTable();
|
$hideFromCMSTree = $owner->config()->hide_from_cms_tree;
|
||||||
$staged = DataObject::get($baseClass)->where(sprintf(
|
$class = $this->getHierarchyBaseClass();
|
||||||
|
|
||||||
|
$schema = DataObject::getSchema();
|
||||||
|
$tableForParentID = $schema->tableForField($class, 'ParentID');
|
||||||
|
$tableForID = $schema->tableForField($class, 'ID');
|
||||||
|
|
||||||
|
$staged = DataObject::get($class)->where(sprintf(
|
||||||
'%s.%s <> %s.%s',
|
'%s.%s <> %s.%s',
|
||||||
Convert::symbol2sql($baseTable),
|
Convert::symbol2sql($tableForParentID),
|
||||||
Convert::symbol2sql("ParentID"),
|
Convert::symbol2sql("ParentID"),
|
||||||
Convert::symbol2sql($baseTable),
|
Convert::symbol2sql($tableForID),
|
||||||
Convert::symbol2sql("ID")
|
Convert::symbol2sql("ID")
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -466,7 +490,7 @@ class Hierarchy extends DataExtension
|
|||||||
|
|
||||||
$hideFromHierarchy = $owner->config()->hide_from_hierarchy;
|
$hideFromHierarchy = $owner->config()->hide_from_hierarchy;
|
||||||
$hideFromCMSTree = $owner->config()->hide_from_cms_tree;
|
$hideFromCMSTree = $owner->config()->hide_from_cms_tree;
|
||||||
$children = DataObject::get($owner->baseClass())
|
$children = DataObject::get($this->getHierarchyBaseClass())
|
||||||
->filter('ParentID', (int)$owner->ID)
|
->filter('ParentID', (int)$owner->ID)
|
||||||
->exclude('ID', (int)$owner->ID)
|
->exclude('ID', (int)$owner->ID)
|
||||||
->setDataQueryParam([
|
->setDataQueryParam([
|
||||||
|
@ -12,6 +12,8 @@ use SilverStripe\Forms\FieldList;
|
|||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
use SilverStripe\Forms\TreeDropdownField;
|
use SilverStripe\Forms\TreeDropdownField;
|
||||||
use SilverStripe\ORM\DataObject;
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestObject;
|
||||||
|
use SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject;
|
||||||
use SilverStripe\ORM\Tests\HierarchyTest\TestObject;
|
use SilverStripe\ORM\Tests\HierarchyTest\TestObject;
|
||||||
|
|
||||||
class TreeDropdownFieldTest extends SapphireTest
|
class TreeDropdownFieldTest extends SapphireTest
|
||||||
@ -20,7 +22,9 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
protected static $fixture_file = 'TreeDropdownFieldTest.yml';
|
protected static $fixture_file = 'TreeDropdownFieldTest.yml';
|
||||||
|
|
||||||
protected static $extra_dataobjects = [
|
protected static $extra_dataobjects = [
|
||||||
TestObject::class
|
TestObject::class,
|
||||||
|
HierarchyOnSubclassTestObject::class,
|
||||||
|
HierarchyOnSubclassTestSubObject::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function testSchemaStateDefaults()
|
public function testSchemaStateDefaults()
|
||||||
@ -52,7 +56,7 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
{
|
{
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
||||||
|
|
||||||
// case insensitive search against keyword 'sub' for folders
|
// case-insensitive search against keyword 'sub' for folders
|
||||||
$request = new HTTPRequest('GET', 'url', ['search'=>'sub', 'format' => 'json']);
|
$request = new HTTPRequest('GET', 'url', ['search'=>'sub', 'format' => 'json']);
|
||||||
$request->setSession(new Session([]));
|
$request->setSession(new Session([]));
|
||||||
$response = $field->tree($request);
|
$response = $field->tree($request);
|
||||||
@ -83,7 +87,7 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
{
|
{
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
||||||
|
|
||||||
// case insensitive search against keyword 'sub' for folders
|
// case-insensitive search against keyword 'sub' for folders
|
||||||
$request = new HTTPRequest('GET', 'url', ['search'=>'sub', 'format' => 'json', 'flatList' => '1']);
|
$request = new HTTPRequest('GET', 'url', ['search'=>'sub', 'format' => 'json', 'flatList' => '1']);
|
||||||
$request->setSession(new Session([]));
|
$request->setSession(new Session([]));
|
||||||
$response = $field->tree($request);
|
$response = $field->tree($request);
|
||||||
@ -137,11 +141,42 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
$this->assertEquals($expectedNodeIDs, $actualNodeIDs);
|
$this->assertEquals($expectedNodeIDs, $actualNodeIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTreeSearchJsonFlatlistWithLowNodeThresholdUsingSubObject()
|
||||||
|
{
|
||||||
|
// Initialise our TreeDropDownField
|
||||||
|
$field = new TreeDropdownField('TestTree', 'Test tree - Hierarchy on subclass', HierarchyOnSubclassTestSubObject::class);
|
||||||
|
$field->config()->set('node_threshold_total', 2);
|
||||||
|
|
||||||
|
// Search for all Test object matching our criteria
|
||||||
|
$request = new HTTPRequest(
|
||||||
|
'GET',
|
||||||
|
'url',
|
||||||
|
['search' => 'SubObject', 'format' => 'json', 'flatList' => '1']
|
||||||
|
);
|
||||||
|
$request->setSession(new Session([]));
|
||||||
|
$response = $field->tree($request);
|
||||||
|
$tree = json_decode($response->getBody(), true);
|
||||||
|
$actualNodeIDs = array_column($tree['children'], 'id');
|
||||||
|
|
||||||
|
// Get the list of expected node IDs from the YML Fixture
|
||||||
|
$expectedNodeIDs = array_map(
|
||||||
|
function ($key) {
|
||||||
|
return $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, $key)->ID;
|
||||||
|
},
|
||||||
|
['four', 'fourB', 'fourA2'] // Those are the identifiers of the object we expect our search to find
|
||||||
|
);
|
||||||
|
|
||||||
|
sort($actualNodeIDs);
|
||||||
|
sort($expectedNodeIDs);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedNodeIDs, $actualNodeIDs);
|
||||||
|
}
|
||||||
|
|
||||||
public function testTreeSearch()
|
public function testTreeSearch()
|
||||||
{
|
{
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
||||||
|
|
||||||
// case insensitive search against keyword 'sub' for folders
|
// case-insensitive search against keyword 'sub' for folders
|
||||||
$request = new HTTPRequest('GET', 'url', ['search'=>'sub']);
|
$request = new HTTPRequest('GET', 'url', ['search'=>'sub']);
|
||||||
$request->setSession(new Session([]));
|
$request->setSession(new Session([]));
|
||||||
$response = $field->tree($request);
|
$response = $field->tree($request);
|
||||||
@ -179,7 +214,7 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
|
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', File::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', File::class);
|
||||||
|
|
||||||
// case insensitive search against keyword 'sub' for files
|
// case-insensitive search against keyword 'sub' for files
|
||||||
$request = new HTTPRequest('GET', 'url', ['search'=>'sub']);
|
$request = new HTTPRequest('GET', 'url', ['search'=>'sub']);
|
||||||
$request->setSession(new Session([]));
|
$request->setSession(new Session([]));
|
||||||
$response = $field->tree($request);
|
$response = $field->tree($request);
|
||||||
@ -233,6 +268,39 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTreeSearchUsingSubObject()
|
||||||
|
{
|
||||||
|
$field = new TreeDropdownField('TestTree', 'Test tree', HierarchyOnSubclassTestSubObject::class);
|
||||||
|
|
||||||
|
// case-insensitive search against keyword 'SubObject' for objects that have Hierarchy extension
|
||||||
|
// applied to a class that doesn't directly inherit from DataObject
|
||||||
|
$request = new HTTPRequest('GET', 'url', ['search' => 'SubObject']);
|
||||||
|
$request->setSession(new Session([]));
|
||||||
|
$response = $field->tree($request);
|
||||||
|
$tree = $response->getBody();
|
||||||
|
|
||||||
|
$subObject1 = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'four');
|
||||||
|
$subObject1ChildB = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'fourB');
|
||||||
|
|
||||||
|
$parser = new CSSContentParser($tree);
|
||||||
|
$cssPath = 'ul.tree li#selector-TestTree-' . $subObject1->ID . ' li#selector-TestTree-' . $subObject1ChildB->ID . ' a';
|
||||||
|
$firstResult = $parser->getBySelector($cssPath);
|
||||||
|
$this->assertEquals(
|
||||||
|
$subObject1ChildB->Name,
|
||||||
|
(string)$firstResult[0],
|
||||||
|
$subObject1ChildB->Name . ' is found, nested under ' . $subObject1->Name
|
||||||
|
);
|
||||||
|
|
||||||
|
// other objects which don't contain the keyword 'SubObject' are not returned in search results
|
||||||
|
$subObject2 = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'five');
|
||||||
|
$cssPath = 'ul.tree li#selector-TestTree-' . $subObject2->ID . ' a';
|
||||||
|
$noResult = $parser->getBySelector($cssPath);
|
||||||
|
$this->assertEmpty(
|
||||||
|
$noResult,
|
||||||
|
$subObject2 . ' is not found'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testReadonly()
|
public function testReadonly()
|
||||||
{
|
{
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', File::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', File::class);
|
||||||
@ -272,7 +340,7 @@ class TreeDropdownFieldTest extends SapphireTest
|
|||||||
$treeBaseID = $this->idFromFixture(Folder::class, 'folder1');
|
$treeBaseID = $this->idFromFixture(Folder::class, 'folder1');
|
||||||
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
$field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
|
||||||
|
|
||||||
// getSchemaDataDefaults needs the field to be attach to a form
|
// getSchemaDataDefaults needs the field to be attached to a form
|
||||||
new Form(
|
new Form(
|
||||||
null,
|
null,
|
||||||
'mock',
|
'mock',
|
||||||
|
@ -62,3 +62,29 @@ SilverStripe\ORM\Tests\HierarchyTest\TestObject:
|
|||||||
ParentID: =>SilverStripe\ORM\Tests\HierarchyTest\TestObject.twoA
|
ParentID: =>SilverStripe\ORM\Tests\HierarchyTest\TestObject.twoA
|
||||||
three:
|
three:
|
||||||
Title: Three MatchSearchCriteria
|
Title: Three MatchSearchCriteria
|
||||||
|
SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject:
|
||||||
|
four:
|
||||||
|
Title: Four SubObject
|
||||||
|
fourA:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.four
|
||||||
|
Title: Child A of Four
|
||||||
|
fourB:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.four
|
||||||
|
Title: Child B of Four SubObject
|
||||||
|
fourA1:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourA
|
||||||
|
Title: Child 1 of Child A of Four
|
||||||
|
fourA2:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourA
|
||||||
|
Title: Child 2 of Child A of Four SubObject
|
||||||
|
fourB1:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB
|
||||||
|
Title: Child 1 of Child B of Four
|
||||||
|
fourB2:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB
|
||||||
|
Title: Child 2 of Child B of Four
|
||||||
|
fourB3:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB
|
||||||
|
Title: Child 3 of Child B of Four
|
||||||
|
five:
|
||||||
|
Title: Five
|
||||||
|
@ -48,10 +48,10 @@ class HierachyCacheTest extends SapphireTest
|
|||||||
[TestObject::class, 'obj2', true, 2, 'Root object numChildren should count direct children when cache'],
|
[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', 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, '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', false, 0, 'Childless Sub object numChildren should be 0'],
|
||||||
[TestObject::class, 'obj3d', true, 0, 'Childess Sub object numChildren should be 0 when cache'],
|
[TestObject::class, 'obj3d', true, 0, 'Childless Sub object numChildren should be 0 when cache'],
|
||||||
[HideTestObject::class, 'obj4', false, 1, 'Hidden object should not be included in count'],
|
[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']
|
[HideTestObject::class, 'obj4', true, 1, 'Hidden object should not be included in count when cache']
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ class HierachyCacheTest extends SapphireTest
|
|||||||
$this->assertEquals($expected, $actual, $message);
|
$this->assertEquals($expected, $actual, $message);
|
||||||
|
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
// When caching is eanbled, try re-accessing the numChildren value to make sure it doesn't change.
|
// When caching is enabled, try re-accessing the numChildren value to make sure it doesn't change.
|
||||||
$actual = $node->numChildren($cache);
|
$actual = $node->numChildren($cache);
|
||||||
$this->assertEquals($expected, $actual, $message);
|
$this->assertEquals($expected, $actual, $message);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ class HierarchyTest extends SapphireTest
|
|||||||
HierarchyTest\TestObject::class,
|
HierarchyTest\TestObject::class,
|
||||||
HierarchyTest\HideTestObject::class,
|
HierarchyTest\HideTestObject::class,
|
||||||
HierarchyTest\HideTestSubObject::class,
|
HierarchyTest\HideTestSubObject::class,
|
||||||
|
HierarchyTest\HierarchyOnSubclassTestObject::class,
|
||||||
|
HierarchyTest\HierarchyOnSubclassTestSubObject::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function getExtraDataObjects()
|
public static function getExtraDataObjects()
|
||||||
@ -145,6 +147,43 @@ class HierarchyTest extends SapphireTest
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNumChildrenHierarchyOnSubclass()
|
||||||
|
{
|
||||||
|
/** @var HierarchyTest\HierarchyOnSubclassTestObject $obj5 */
|
||||||
|
$obj5 = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestObject::class, 'obj5');
|
||||||
|
|
||||||
|
$this->assertFalse(
|
||||||
|
$obj5->hasMethod('numChildren'),
|
||||||
|
'numChildren() cannot be called on object without Hierarchy extension'
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var HierarchyTest\HierarchyOnSubclassTestSubObject $obj5a */
|
||||||
|
$obj5a = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestSubObject::class, 'obj5a');
|
||||||
|
/** @var HierarchyTest\HierarchyOnSubclassTestSubObject $obj5b */
|
||||||
|
$obj5b = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestSubObject::class, 'obj5b');
|
||||||
|
|
||||||
|
$this->assertEquals(2, $obj5a->numChildren());
|
||||||
|
$this->assertEquals(1, $obj5b->numChildren());
|
||||||
|
|
||||||
|
$obj5bChild2 = new HierarchyTest\HierarchyOnSubclassTestSubObject();
|
||||||
|
$obj5bChild2->ParentID = $obj5b->ID;
|
||||||
|
$obj5bChild2->write();
|
||||||
|
$this->assertEquals(
|
||||||
|
$obj5b->numChildren(false),
|
||||||
|
2,
|
||||||
|
'numChildren() caching can be disabled through method parameter'
|
||||||
|
);
|
||||||
|
$obj5bChild3 = new HierarchyTest\HierarchyOnSubclassTestSubObject();
|
||||||
|
$obj5bChild3->ParentID = $obj5b->ID;
|
||||||
|
$obj5bChild3->write();
|
||||||
|
$obj5b->flushCache();
|
||||||
|
$this->assertEquals(
|
||||||
|
$obj5b->numChildren(),
|
||||||
|
3,
|
||||||
|
'numChildren() caching can be disabled by flushCache()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testLoadDescendantIDListIntoArray()
|
public function testLoadDescendantIDListIntoArray()
|
||||||
{
|
{
|
||||||
/** @var HierarchyTest\TestObject $obj2 */
|
/** @var HierarchyTest\TestObject $obj2 */
|
||||||
@ -219,7 +258,7 @@ class HierarchyTest extends SapphireTest
|
|||||||
$this->assertEquals('Obj 2 » Obj 2a » Obj 2aa', $obj2aa->getBreadcrumbs());
|
$this->assertEquals('Obj 2 » Obj 2a » Obj 2aa', $obj2aa->getBreadcrumbs());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNoHideFromHeirarchy()
|
public function testNoHideFromHierarchy()
|
||||||
{
|
{
|
||||||
/** @var HierarchyTest\HideTestObject $obj4 */
|
/** @var HierarchyTest\HideTestObject $obj4 */
|
||||||
$obj4 = $this->objFromFixture(HierarchyTest\HideTestObject::class, 'obj4');
|
$obj4 = $this->objFromFixture(HierarchyTest\HideTestObject::class, 'obj4');
|
||||||
@ -232,7 +271,7 @@ class HierarchyTest extends SapphireTest
|
|||||||
$this->assertEquals($obj4->liveChildren()->Count(), 2);
|
$this->assertEquals($obj4->liveChildren()->Count(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHideFromHeirarchy()
|
public function testHideFromHierarchy()
|
||||||
{
|
{
|
||||||
HierarchyTest\HideTestObject::config()->update(
|
HierarchyTest\HideTestObject::config()->update(
|
||||||
'hide_from_hierarchy',
|
'hide_from_hierarchy',
|
||||||
|
@ -53,3 +53,20 @@ SilverStripe\ORM\Tests\HierarchyTest\HideTestObject:
|
|||||||
SilverStripe\ORM\Tests\HierarchyTest\HideTestSubObject:
|
SilverStripe\ORM\Tests\HierarchyTest\HideTestSubObject:
|
||||||
obj4b:
|
obj4b:
|
||||||
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HideTestObject.obj4
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HideTestObject.obj4
|
||||||
|
SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestObject:
|
||||||
|
obj5:
|
||||||
|
Title: Obj 5
|
||||||
|
SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject:
|
||||||
|
obj5a:
|
||||||
|
Title: Obj 5a
|
||||||
|
obj5b:
|
||||||
|
Title: Obj 5b
|
||||||
|
obj5aa:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5a
|
||||||
|
Title: Obj 5aa
|
||||||
|
obj5ab:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5a
|
||||||
|
Title: Obj 5ab
|
||||||
|
obj5ba:
|
||||||
|
Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5b
|
||||||
|
Title: Obj 5ba
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\HierarchyTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Versioned\Versioned;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin Versioned
|
||||||
|
*/
|
||||||
|
class HierarchyOnSubclassTestObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HierarchyOnSubclassTest_Object';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $extensions = [
|
||||||
|
Versioned::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $default_sort = 'Title ASC';
|
||||||
|
|
||||||
|
public function cmstreeclasses()
|
||||||
|
{
|
||||||
|
return $this->markingClasses();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\HierarchyTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\Hierarchy\Hierarchy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin Hierarchy
|
||||||
|
*/
|
||||||
|
class HierarchyOnSubclassTestSubObject extends HierarchyOnSubclassTestObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HierarchyOnSubclassTest_SubObject';
|
||||||
|
|
||||||
|
private static $extensions = [
|
||||||
|
Hierarchy::class,
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user