mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Revert "TreeDropDown performance boost."
This commit is contained in:
parent
292aaf6530
commit
7b6aad8a65
@ -107,13 +107,6 @@ class TreeDropdownField extends FormField {
|
|||||||
$this->childrenMethod = 'ChildFolders';
|
$this->childrenMethod = 'ChildFolders';
|
||||||
$this->numChildrenMethod = 'numChildFolders';
|
$this->numChildrenMethod = 'numChildFolders';
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// AllChildren should be used as a default because
|
|
||||||
// if you use AllChildrenIncludingDeleted instead, the filters will be much more demanding
|
|
||||||
// this is because instead of working with DataList you will be working with ArrayList
|
|
||||||
// AllChildren should be always used when dealing with more pages than the node leaf limit
|
|
||||||
$this->childrenMethod = 'AllChildren';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addExtraClass('single');
|
$this->addExtraClass('single');
|
||||||
|
|
||||||
@ -310,57 +303,16 @@ class TreeDropdownField extends FormField {
|
|||||||
if ($this->filterCallback || $this->search != "" )
|
if ($this->filterCallback || $this->search != "" )
|
||||||
$obj->setMarkingFilterFunction(array($this, "filterMarking"));
|
$obj->setMarkingFilterFunction(array($this, "filterMarking"));
|
||||||
|
|
||||||
// prepare a filter by ids, this is very useful when we have thousands of child pages under common parent
|
$obj->markPartialTree($nodeCountThreshold = 30, $context = null,
|
||||||
$filteredIds = ($this->search != '' && !is_null($this->searchIds) && is_array($this->searchIds))
|
$this->childrenMethod, $this->numChildrenMethod);
|
||||||
? array_keys($this->searchIds) : array();
|
|
||||||
|
|
||||||
// collect IDs of currently selected pages (this includes hierarchy path)
|
|
||||||
$forceValue = $request->requestVar('forceValue');
|
|
||||||
if (!is_null($forceValue) || $this->value) {
|
|
||||||
$fieldValue = (!is_null($forceValue) ? $forceValue : $this->value);
|
|
||||||
|
|
||||||
if (($values = preg_split('/,\s*/', $fieldValue)) && count($values)) {
|
|
||||||
foreach ($values as $value) {
|
|
||||||
if (!$value || $value == 'unchanged') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$selectedObject = $this->objectForKey($value);
|
|
||||||
|
|
||||||
// add all pages along the hierarchy path
|
|
||||||
$stack = $selectedObject->parentStack();
|
|
||||||
foreach ($stack as $stackItem) {
|
|
||||||
$filteredIds[] = $stackItem->ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// main node leaf limit configuration
|
|
||||||
$nodeCountThreshold = 30;
|
|
||||||
$obj->markPartialTree(
|
|
||||||
$nodeCountThreshold, $context = null,
|
|
||||||
$this->childrenMethod, $this->numChildrenMethod, $filteredIds
|
|
||||||
);
|
|
||||||
|
|
||||||
// allow to pass values to be selected within the ajax request
|
// allow to pass values to be selected within the ajax request
|
||||||
if (!is_null($forceValue) || $this->value) {
|
if( isset($_REQUEST['forceValue']) || $this->value ) {
|
||||||
$fieldValue = (!is_null($forceValue) ? $forceValue : $this->value);
|
$forceValue = ( isset($_REQUEST['forceValue']) ? $_REQUEST['forceValue'] : $this->value);
|
||||||
|
if(($values = preg_split('/,\s*/', $forceValue)) && count($values)) foreach($values as $value) {
|
||||||
|
if(!$value || $value == 'unchanged') continue;
|
||||||
|
|
||||||
if (($values = preg_split('/,\s*/', $fieldValue)) && count($values)) {
|
$obj->markToExpose($this->objectForKey($value));
|
||||||
foreach ($values as $value) {
|
|
||||||
if (!$value || $value == 'unchanged') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$obj->markToExpose(
|
|
||||||
$this->objectForKey($value),
|
|
||||||
$this->childrenMethod,
|
|
||||||
$this->numChildrenMethod,
|
|
||||||
$nodeCountThreshold,
|
|
||||||
$filteredIds
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +337,7 @@ class TreeDropdownField extends FormField {
|
|||||||
// Skip the check if we're filtering the tree, since its not clear how many children will
|
// Skip the check if we're filtering the tree, since its not clear how many children will
|
||||||
// match the filter criteria until they're queried (and matched up with previously marked nodes).
|
// match the filter criteria until they're queried (and matched up with previously marked nodes).
|
||||||
$nodeThresholdLeaf = Config::inst()->get('Hierarchy', 'node_threshold_leaf');
|
$nodeThresholdLeaf = Config::inst()->get('Hierarchy', 'node_threshold_leaf');
|
||||||
if($nodeThresholdLeaf && !$this->filterCallback && !$this->search && count($filteredIds) == 0) {
|
if($nodeThresholdLeaf && !$this->filterCallback && !$this->search) {
|
||||||
$className = $this->sourceObject;
|
$className = $this->sourceObject;
|
||||||
$nodeCountCallback = function($parent, $numChildren) use($className, $nodeThresholdLeaf) {
|
$nodeCountCallback = function($parent, $numChildren) use($className, $nodeThresholdLeaf) {
|
||||||
if($className == 'SiteTree' && $parent->ID && $numChildren > $nodeThresholdLeaf) {
|
if($className == 'SiteTree' && $parent->ID && $numChildren > $nodeThresholdLeaf) {
|
||||||
@ -409,8 +361,7 @@ class TreeDropdownField extends FormField {
|
|||||||
$this->numChildrenMethod,
|
$this->numChildrenMethod,
|
||||||
true, // root call
|
true, // root call
|
||||||
null,
|
null,
|
||||||
$nodeCountCallback,
|
$nodeCountCallback
|
||||||
$filteredIds
|
|
||||||
);
|
);
|
||||||
return substr(trim($html), 4, -5);
|
return substr(trim($html), 4, -5);
|
||||||
} else {
|
} else {
|
||||||
@ -423,8 +374,7 @@ class TreeDropdownField extends FormField {
|
|||||||
$this->numChildrenMethod,
|
$this->numChildrenMethod,
|
||||||
true, // root call
|
true, // root call
|
||||||
null,
|
null,
|
||||||
$nodeCountCallback,
|
$nodeCountCallback
|
||||||
$filteredIds
|
|
||||||
);
|
);
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,6 @@ class Hierarchy extends DataExtension {
|
|||||||
* overload this function
|
* overload this function
|
||||||
* @param bool $limitToMarked Display only marked children
|
* @param bool $limitToMarked Display only marked children
|
||||||
* @param string $childrenMethod The name of the method used to get children from each object
|
* @param string $childrenMethod The name of the method used to get children from each object
|
||||||
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
|
||||||
* @param bool $rootCall Set to true for this first call, and then to false for calls inside
|
* @param bool $rootCall Set to true for this first call, and then to false for calls inside
|
||||||
* the recursion. You should not change this.
|
* the recursion. You should not change this.
|
||||||
* @param int $nodeCountThreshold See {@link self::$node_threshold_total}
|
* @param int $nodeCountThreshold See {@link self::$node_threshold_total}
|
||||||
@ -126,14 +125,12 @@ class Hierarchy extends DataExtension {
|
|||||||
* intercept the query. Useful e.g. to avoid excessive children listings
|
* intercept the query. Useful e.g. to avoid excessive children listings
|
||||||
* (Arguments: $parent, $numChildren)
|
* (Arguments: $parent, $numChildren)
|
||||||
*
|
*
|
||||||
* @param array $filteredIds list of ids that will be used to filter list items (reduce the result set before processing)
|
|
||||||
*
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child->Title', $extraArg = null,
|
public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child->Title', $extraArg = null,
|
||||||
$limitToMarked = false, $childrenMethod = "AllChildrenIncludingDeleted",
|
$limitToMarked = false, $childrenMethod = "AllChildrenIncludingDeleted",
|
||||||
$numChildrenMethod = "numChildren", $rootCall = true,
|
$numChildrenMethod = "numChildren", $rootCall = true,
|
||||||
$nodeCountThreshold = null, $nodeCountCallback = null, array $filteredIds = array()) {
|
$nodeCountThreshold = null, $nodeCountCallback = null) {
|
||||||
|
|
||||||
if(!is_numeric($nodeCountThreshold)) {
|
if(!is_numeric($nodeCountThreshold)) {
|
||||||
$nodeCountThreshold = Config::inst()->get('Hierarchy', 'node_threshold_total');
|
$nodeCountThreshold = Config::inst()->get('Hierarchy', 'node_threshold_total');
|
||||||
@ -152,18 +149,6 @@ class Hierarchy extends DataExtension {
|
|||||||
|
|
||||||
if($this->owner->hasMethod($childrenMethod)) {
|
if($this->owner->hasMethod($childrenMethod)) {
|
||||||
$children = $this->owner->$childrenMethod($extraArg);
|
$children = $this->owner->$childrenMethod($extraArg);
|
||||||
|
|
||||||
// apply filter before any further processing to limit excessive amount of items
|
|
||||||
// filter is applied only after limit has been reached
|
|
||||||
if (count($filteredIds) > 0 && $nodeCountThreshold && $children->count() > $nodeCountThreshold) {
|
|
||||||
$children = $children->filter(array('ID' => $filteredIds));
|
|
||||||
}
|
|
||||||
|
|
||||||
// too many children, display nothing
|
|
||||||
if ($nodeCountThreshold && $children->count() > $nodeCountThreshold) {
|
|
||||||
$children = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
user_error(sprintf("Can't find the method '%s' on class '%s' for getting tree children",
|
user_error(sprintf("Can't find the method '%s' on class '%s' for getting tree children",
|
||||||
$childrenMethod, get_class($this->owner)), E_USER_ERROR);
|
$childrenMethod, get_class($this->owner)), E_USER_ERROR);
|
||||||
@ -203,7 +188,7 @@ class Hierarchy extends DataExtension {
|
|||||||
$child->markClosed();
|
$child->markClosed();
|
||||||
} else {
|
} else {
|
||||||
$output .= $child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked,
|
$output .= $child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked,
|
||||||
$childrenMethod, $numChildrenMethod, false, $nodeCountThreshold, null, $filteredIds);
|
$childrenMethod, $numChildrenMethod, false, $nodeCountThreshold);
|
||||||
}
|
}
|
||||||
} elseif($child->isTreeOpened()) {
|
} elseif($child->isTreeOpened()) {
|
||||||
// Since we're not loading children, don't mark it as open either
|
// Since we're not loading children, don't mark it as open either
|
||||||
@ -231,14 +216,10 @@ class Hierarchy extends DataExtension {
|
|||||||
* {@link isExpanded()} and {@link isMarked()} on individual nodes.
|
* {@link isExpanded()} and {@link isMarked()} on individual nodes.
|
||||||
*
|
*
|
||||||
* @param int $nodeCountThreshold See {@link getChildrenAsUL()}
|
* @param int $nodeCountThreshold See {@link getChildrenAsUL()}
|
||||||
* @param mixed $context
|
|
||||||
* @param string $childrenMethod The name of the instance method to call to get the object's list of children
|
|
||||||
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
|
||||||
* @param array $filteredIds list of ids that will be used to filter list items (reduce the result set before processing)
|
|
||||||
* @return int The actual number of nodes marked.
|
* @return int The actual number of nodes marked.
|
||||||
*/
|
*/
|
||||||
public function markPartialTree($nodeCountThreshold = 30, $context = null,
|
public function markPartialTree($nodeCountThreshold = 30, $context = null,
|
||||||
$childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren", array $filteredIds = array()) {
|
$childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren") {
|
||||||
|
|
||||||
if(!is_numeric($nodeCountThreshold)) $nodeCountThreshold = 30;
|
if(!is_numeric($nodeCountThreshold)) $nodeCountThreshold = 30;
|
||||||
|
|
||||||
@ -247,19 +228,7 @@ class Hierarchy extends DataExtension {
|
|||||||
|
|
||||||
// foreach can't handle an ever-growing $nodes list
|
// foreach can't handle an ever-growing $nodes list
|
||||||
while(list($id, $node) = each($this->markedNodes)) {
|
while(list($id, $node) = each($this->markedNodes)) {
|
||||||
// first determine the number of children, if it's too high the tree view can't be used
|
$children = $this->markChildren($node, $context, $childrenMethod, $numChildrenMethod);
|
||||||
// so will will not even bother to display the subtree
|
|
||||||
// this covers two cases:
|
|
||||||
// either no search filter is in use or search filter is in use but it's too broad
|
|
||||||
$numberOfChildren = $node->$numChildrenMethod();
|
|
||||||
if ($nodeCountThreshold && $numberOfChildren > $nodeCountThreshold
|
|
||||||
&& (count($filteredIds) == 0 || count($filteredIds) > $nodeCountThreshold)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$children = $this->markChildren(
|
|
||||||
$node, $context, $childrenMethod, $numChildrenMethod, $nodeCountThreshold, $filteredIds
|
|
||||||
);
|
|
||||||
if($nodeCountThreshold && sizeof($this->markedNodes) > $nodeCountThreshold) {
|
if($nodeCountThreshold && sizeof($this->markedNodes) > $nodeCountThreshold) {
|
||||||
// Undo marking children as opened since they're lazy loaded
|
// Undo marking children as opened since they're lazy loaded
|
||||||
if($children) foreach($children as $child) $child->markClosed();
|
if($children) foreach($children as $child) $child->markClosed();
|
||||||
@ -330,20 +299,12 @@ class Hierarchy extends DataExtension {
|
|||||||
* @param mixed $context
|
* @param mixed $context
|
||||||
* @param string $childrenMethod The name of the instance method to call to get the object's list of children
|
* @param string $childrenMethod The name of the instance method to call to get the object's list of children
|
||||||
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
||||||
* @param int $nodeCountThreshold
|
|
||||||
* @param array $filteredIds list of ids that will be used to filter list items (reduce the result set before processing)
|
|
||||||
* @return DataList
|
* @return DataList
|
||||||
*/
|
*/
|
||||||
public function markChildren($node, $context = null, $childrenMethod = "AllChildrenIncludingDeleted",
|
public function markChildren($node, $context = null, $childrenMethod = "AllChildrenIncludingDeleted",
|
||||||
$numChildrenMethod = "numChildren", $nodeCountThreshold = null, array $filteredIds = array()) {
|
$numChildrenMethod = "numChildren") {
|
||||||
|
|
||||||
if($node->hasMethod($childrenMethod)) {
|
if($node->hasMethod($childrenMethod)) {
|
||||||
$children = $node->$childrenMethod($context);
|
$children = $node->$childrenMethod($context);
|
||||||
|
|
||||||
// apply filter before any further processing
|
|
||||||
if (count($filteredIds) > 0 && $nodeCountThreshold && $children->count() > $nodeCountThreshold) {
|
|
||||||
$children = $children->filter(array('ID' => $filteredIds));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
user_error(sprintf("Can't find the method '%s' on class '%s' for getting tree children",
|
user_error(sprintf("Can't find the method '%s' on class '%s' for getting tree children",
|
||||||
$childrenMethod, get_class($node)), E_USER_ERROR);
|
$childrenMethod, get_class($node)), E_USER_ERROR);
|
||||||
@ -414,18 +375,11 @@ class Hierarchy extends DataExtension {
|
|||||||
*
|
*
|
||||||
* @param int $id ID of parent node
|
* @param int $id ID of parent node
|
||||||
* @param bool $open If this is true, mark the parent node as opened
|
* @param bool $open If this is true, mark the parent node as opened
|
||||||
* @param string $childrenMethod The name of the instance method to call to get the object's list of children
|
|
||||||
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
|
||||||
* @param int $nodeCountThreshold
|
|
||||||
* @param array $filteredIds list of ids that will be used to filter list items (reduce the result set before processing)
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function markById($id, $open = false, $childrenMethod = "AllChildrenIncludingDeleted",
|
public function markById($id, $open = false) {
|
||||||
$numChildrenMethod = "numChildren", $nodeCountThreshold = null, array $filteredIds = array()) {
|
|
||||||
if(isset($this->markedNodes[$id])) {
|
if(isset($this->markedNodes[$id])) {
|
||||||
$this->markChildren(
|
$this->markChildren($this->markedNodes[$id]);
|
||||||
$this->markedNodes[$id], null, $childrenMethod, $numChildrenMethod, $nodeCountThreshold, $filteredIds
|
|
||||||
);
|
|
||||||
if($open) {
|
if($open) {
|
||||||
$this->markedNodes[$id]->markOpened();
|
$this->markedNodes[$id]->markOpened();
|
||||||
}
|
}
|
||||||
@ -439,19 +393,12 @@ class Hierarchy extends DataExtension {
|
|||||||
* Expose the given object in the tree, by marking this page and all it ancestors.
|
* Expose the given object in the tree, by marking this page and all it ancestors.
|
||||||
*
|
*
|
||||||
* @param DataObject $childObj
|
* @param DataObject $childObj
|
||||||
* @param string $childrenMethod The name of the instance method to call to get the object's list of children
|
|
||||||
* @param string $numChildrenMethod The name of the instance method to call to count the object's children
|
|
||||||
* @param int $nodeCountThreshold
|
|
||||||
* @param array $filteredIds list of ids that will be used to filter list items (reduce the result set before processing)
|
|
||||||
*/
|
*/
|
||||||
public function markToExpose($childObj, $childrenMethod = "AllChildrenIncludingDeleted",
|
public function markToExpose($childObj) {
|
||||||
$numChildrenMethod = "numChildren", $nodeCountThreshold = null, array $filteredIds = array()) {
|
|
||||||
if(is_object($childObj)){
|
if(is_object($childObj)){
|
||||||
$stack = array_reverse($childObj->parentStack());
|
$stack = array_reverse($childObj->parentStack());
|
||||||
foreach($stack as $stackItem) {
|
foreach($stack as $stackItem) {
|
||||||
$this->markById(
|
$this->markById($stackItem->ID, true);
|
||||||
$stackItem->ID, true, $childrenMethod, $numChildrenMethod, $nodeCountThreshold, $filteredIds
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ EOT;
|
|||||||
$obj2aa->delete();
|
$obj2aa->delete();
|
||||||
$obj2ab->delete();
|
$obj2ab->delete();
|
||||||
// Don't pre-load all children
|
// Don't pre-load all children
|
||||||
$nodeCountThreshold = 3;
|
$nodeCountThreshold = 1;
|
||||||
|
|
||||||
$childrenMethod = 'AllChildren';
|
$childrenMethod = 'AllChildren';
|
||||||
$numChildrenMethod = 'numChildren';
|
$numChildrenMethod = 'numChildren';
|
||||||
@ -500,7 +500,7 @@ EOT;
|
|||||||
$obj2aa->delete();
|
$obj2aa->delete();
|
||||||
$obj2ab->delete();
|
$obj2ab->delete();
|
||||||
// Don't pre-load all children
|
// Don't pre-load all children
|
||||||
$nodeCountThreshold = 3;
|
$nodeCountThreshold = 1;
|
||||||
|
|
||||||
$childrenMethod = 'AllChildrenIncludingDeleted';
|
$childrenMethod = 'AllChildrenIncludingDeleted';
|
||||||
$numChildrenMethod = 'numHistoricalChildren';
|
$numChildrenMethod = 'numHistoricalChildren';
|
||||||
|
Loading…
Reference in New Issue
Block a user