mirror of
https://github.com/e107inc/e107.git
synced 2025-08-05 06:07:32 +02:00
Revert #3016
This commit is contained in:
@@ -4209,8 +4209,8 @@ class e_admin_controller_ui extends e_admin_controller
|
|||||||
elseif($this->sortField && $this->sortParent && !deftrue('e_DEBUG_TREESORT')) // automated 'tree' sorting.
|
elseif($this->sortField && $this->sortParent && !deftrue('e_DEBUG_TREESORT')) // automated 'tree' sorting.
|
||||||
{
|
{
|
||||||
// $qry = "SELECT SQL_CALC_FOUND_ROWS a. *, CASE WHEN a.".$this->sortParent." = 0 THEN a.".$this->sortField." ELSE b.".$this->sortField." + (( a.".$this->sortField.")/1000) END AS treesort FROM `#".$this->table."` AS a LEFT JOIN `#".$this->table."` AS b ON a.".$this->sortParent." = b.".$this->pid;
|
// $qry = "SELECT SQL_CALC_FOUND_ROWS a. *, CASE WHEN a.".$this->sortParent." = 0 THEN a.".$this->sortField." ELSE b.".$this->sortField." + (( a.".$this->sortField.")/1000) END AS treesort FROM `#".$this->table."` AS a LEFT JOIN `#".$this->table."` AS b ON a.".$this->sortParent." = b.".$this->pid;
|
||||||
$qry = $this->getParentChildQry(true);
|
$qry = $this->getParentChildQry();
|
||||||
//$this->listOrder = '_treesort '; // .$this->sortField;
|
$this->listOrder = '_treesort '; // .$this->sortField;
|
||||||
// $this->orderStep = ($this->orderStep === 1) ? 100 : $this->orderStep;
|
// $this->orderStep = ($this->orderStep === 1) ? 100 : $this->orderStep;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -4337,18 +4337,84 @@ class e_admin_controller_ui extends e_admin_controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a Parent/Child SQL Query based on sortParent and sortField variables
|
* Return a Parent/Child SQL Query based on sortParent and sortField variables
|
||||||
*
|
|
||||||
* Note: Since 2018-01-28, the queries were replaced with pure PHP sorting. See:
|
|
||||||
* https://github.com/e107inc/e107/issues/3015
|
|
||||||
*
|
|
||||||
* @param bool|false $orderby - include 'ORDER BY' in the qry.
|
* @param bool|false $orderby - include 'ORDER BY' in the qry.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getParentChildQry($orderby=false)
|
public function getParentChildQry($orderby=false)
|
||||||
{
|
{
|
||||||
return "SELECT SQL_CALC_FOUND_ROWS * FROM `#".$this->getTableName()."` ";
|
|
||||||
// Use the following return statement to break e107 native sorting but speed up tree creation by presorting for e_tree_model::arrayToTree()
|
$parent= $this->getSortParent();
|
||||||
#return "SELECT SQL_CALC_FOUND_ROWS * FROM `#".$this->getTableName()."` ORDER BY ".$this->getSortParent().", ".$this->getSortField();
|
$table = $this->getTableName();
|
||||||
|
$pid = $this->getPrimaryName();
|
||||||
|
$order = $this->getSortField();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$sql = "DROP FUNCTION IF EXISTS `getDepth` ;";
|
||||||
|
|
||||||
|
e107::getDb()->gen($sql);
|
||||||
|
|
||||||
|
|
||||||
|
$sql = "
|
||||||
|
CREATE FUNCTION `getDepth` (project_id INT) RETURNS int
|
||||||
|
BEGIN
|
||||||
|
DECLARE depth INT;
|
||||||
|
SET depth=1;
|
||||||
|
|
||||||
|
WHILE project_id > 0 DO
|
||||||
|
|
||||||
|
SELECT IFNULL(".$parent.",-1)
|
||||||
|
INTO project_id
|
||||||
|
FROM ( SELECT ".$parent." FROM `#".$table."` WHERE ".$pid." = project_id) AS t;
|
||||||
|
|
||||||
|
IF project_id > 0 THEN
|
||||||
|
SET depth = depth + 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
END WHILE;
|
||||||
|
|
||||||
|
RETURN depth;
|
||||||
|
|
||||||
|
END
|
||||||
|
;
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
e107::getDb()->gen($sql);
|
||||||
|
|
||||||
|
$sql = "DROP FUNCTION IF EXISTS `getTreeSort`;";
|
||||||
|
|
||||||
|
e107::getDb()->gen($sql);
|
||||||
|
$sql = "
|
||||||
|
CREATE FUNCTION getTreeSort(incid INT)
|
||||||
|
RETURNS CHAR(255)
|
||||||
|
BEGIN
|
||||||
|
SET @parentstr = CONVERT(incid, CHAR);
|
||||||
|
SET @parent = -1;
|
||||||
|
label1: WHILE @parent != 0 DO
|
||||||
|
SET @parent = (SELECT ".$parent." FROM `#".$table."` WHERE ".$pid." =incid);
|
||||||
|
SET @order = (SELECT ".$order." FROM `#".$table."` WHERE ".$pid." =incid);
|
||||||
|
SET @parentstr = CONCAT(if(@parent = 0,'',@parent), LPAD(@order,4,0), @parentstr);
|
||||||
|
SET incid = @parent;
|
||||||
|
END WHILE label1;
|
||||||
|
|
||||||
|
RETURN @parentstr;
|
||||||
|
END
|
||||||
|
;
|
||||||
|
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
e107::getDb()->gen($sql);
|
||||||
|
|
||||||
|
$qry = "SELECT SQL_CALC_FOUND_ROWS *, getTreeSort(".$pid.") as _treesort, getDepth(".$pid.") as _depth FROM `#".$table."` ";
|
||||||
|
|
||||||
|
if($orderby === true)
|
||||||
|
{
|
||||||
|
$qry .= " ORDER BY _treesort";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6190,14 +6256,7 @@ class e_admin_ui extends e_admin_controller_ui
|
|||||||
->setFieldIdName($this->pid)
|
->setFieldIdName($this->pid)
|
||||||
->setUrl($this->url)
|
->setUrl($this->url)
|
||||||
->setMessageStackName('admin_ui_tree_'.$this->table)
|
->setMessageStackName('admin_ui_tree_'.$this->table)
|
||||||
->setParams(array('model_class' => 'e_admin_model',
|
->setParams(array('model_class' => 'e_admin_model', 'model_message_stack' => 'admin_ui_model_'.$this->table ,'db_query' => $this->listQry));
|
||||||
'model_message_stack' => 'admin_ui_model_'.$this->table ,
|
|
||||||
'db_query' => $this->listQry,
|
|
||||||
// Information necessary for PHP-based tree sort
|
|
||||||
'sort_parent' => $this->getSortParent(),
|
|
||||||
'sort_field' => $this->getSortField(),
|
|
||||||
'primary_field' => $this->getPrimaryName(),
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
130
e107_handlers/model_class.php
Executable file → Normal file
130
e107_handlers/model_class.php
Executable file → Normal file
@@ -3310,6 +3310,7 @@ class e_tree_model extends e_front_model
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$class_name = $this->getParam('model_class', 'e_model');
|
||||||
// auto-load all
|
// auto-load all
|
||||||
if(!$this->getParam('db_query') && $this->getModelTable())
|
if(!$this->getParam('db_query') && $this->getModelTable())
|
||||||
{
|
{
|
||||||
@@ -3322,7 +3323,6 @@ class e_tree_model extends e_front_model
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$class_name = $this->getParam('model_class', 'e_model');
|
|
||||||
if($this->getParam('db_query') && $class_name && class_exists($class_name))
|
if($this->getParam('db_query') && $class_name && class_exists($class_name))
|
||||||
{
|
{
|
||||||
$sql = e107::getDb($this->getParam('model_class', 'e_model'));
|
$sql = e107::getDb($this->getParam('model_class', 'e_model'));
|
||||||
@@ -3330,12 +3330,8 @@ class e_tree_model extends e_front_model
|
|||||||
|
|
||||||
if($sql->gen($this->getParam('db_query'), $this->getParam('db_debug') ? true : false))
|
if($sql->gen($this->getParam('db_query'), $this->getParam('db_debug') ? true : false))
|
||||||
{
|
{
|
||||||
$rows = self::flatTreeFromArray($sql->rows(),
|
$this->_total = is_integer($sql->total_results) ? $sql->total_results : false; //requires SQL_CALC_FOUND_ROWS in query - see db handler
|
||||||
$this->getParam('primary_field'),
|
while($tmp = $sql->db_Fetch())
|
||||||
$this->getParam('sort_parent'),
|
|
||||||
$this->getParam('sort_field')
|
|
||||||
);
|
|
||||||
foreach($rows as $tmp)
|
|
||||||
{
|
{
|
||||||
$tmp = new $class_name($tmp);
|
$tmp = new $class_name($tmp);
|
||||||
if($this->getParam('model_message_stack'))
|
if($this->getParam('model_message_stack'))
|
||||||
@@ -3344,9 +3340,20 @@ class e_tree_model extends e_front_model
|
|||||||
}
|
}
|
||||||
$this->_onLoad($tmp)->setNode($tmp->get($this->getFieldIdName()), $tmp);
|
$this->_onLoad($tmp)->setNode($tmp->get($this->getFieldIdName()), $tmp);
|
||||||
}
|
}
|
||||||
unset($tmp);
|
|
||||||
|
|
||||||
$this->countResults($sql);
|
if(false === $this->_total && $this->getModelTable() && !$this->getParam('nocount'))
|
||||||
|
{
|
||||||
|
//SQL_CALC_FOUND_ROWS not found in the query, do one more query
|
||||||
|
// $this->_total = e107::getDb()->db_Count($this->getModelTable()); // fails with specific listQry
|
||||||
|
|
||||||
|
// Calculates correct total when using filters and search. //XXX Optimize.
|
||||||
|
$countQry = preg_replace('/(LIMIT ([\d,\s])*)$/', "", $this->getParam('db_query'));
|
||||||
|
|
||||||
|
$this->_total = e107::getDb()->gen($countQry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($sql->getLastErrorNumber())
|
if($sql->getLastErrorNumber())
|
||||||
@@ -3365,111 +3372,6 @@ class e_tree_model extends e_front_model
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Depth-first sort a relational array with a parent field and a sort order field
|
|
||||||
* @param array $rows Relational array with a parent field and a sort order field
|
|
||||||
* @param string $primary_field The field name of the primary key (matches children to parents)
|
|
||||||
* @param string $sort_parent The field name whose value is the parent ID
|
|
||||||
* @param string $sort_field The field name whose value is the sort order in the current tree node
|
|
||||||
* @return array Input array sorted depth-first as if it were a tree
|
|
||||||
*/
|
|
||||||
private static function flatTreeFromArray($rows, $primary_field, $sort_parent, $sort_field)
|
|
||||||
{
|
|
||||||
$rows_tree = self::arrayToTree($rows, $primary_field, $sort_parent);
|
|
||||||
return self::flattenTree($rows_tree, $sort_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a relational array with a parent field and a sort order field to a tree
|
|
||||||
* @param array $rows Relational array with a parent field and a sort order field
|
|
||||||
* @param string $primary_field The field name of the primary key (matches children to parents)
|
|
||||||
* @param string $sort_parent The field name whose value is the parent ID
|
|
||||||
* @return array Multidimensional array with child nodes under the "_children" key
|
|
||||||
*/
|
|
||||||
private static function arrayToTree($rows, $primary_field, $sort_parent)
|
|
||||||
{
|
|
||||||
$nodes = array();
|
|
||||||
$root = array($primary_field => 0);
|
|
||||||
$nodes[] = &$root;
|
|
||||||
|
|
||||||
while(!empty($nodes))
|
|
||||||
{
|
|
||||||
$node = &$nodes[0];
|
|
||||||
array_shift($nodes);
|
|
||||||
foreach($rows as $key => $row)
|
|
||||||
{
|
|
||||||
$rowParentID = (int) $row[$sort_parent];
|
|
||||||
$nodeID = (int) $node[$primary_field];
|
|
||||||
if($rowParentID === $nodeID)
|
|
||||||
{
|
|
||||||
$node['_children'][] = &$row;
|
|
||||||
unset($rows[$key]);
|
|
||||||
$nodes[] = &$row;
|
|
||||||
unset($row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(0 => $root);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flattens a tree into a depth-first array, sorting each node by a field's values
|
|
||||||
* @param array $tree Tree with child nodes under the "_children" key
|
|
||||||
* @param string $sort_field The field name whose value is the sort order in the current tree node
|
|
||||||
* @param int $depth The depth that this level of recursion is entering
|
|
||||||
* @return array One-dimensional array in depth-first order with depth indicated by the "_depth" key
|
|
||||||
*/
|
|
||||||
private static function flattenTree($tree, $sort_field = null, $depth = 0)
|
|
||||||
{
|
|
||||||
$flat = array();
|
|
||||||
|
|
||||||
foreach($tree as $item)
|
|
||||||
{
|
|
||||||
$children = $item['_children'];
|
|
||||||
unset($item['_children']);
|
|
||||||
$item['_depth'] = $depth;
|
|
||||||
if($depth > 0)
|
|
||||||
$flat[] = $item;
|
|
||||||
if(is_array($children))
|
|
||||||
{
|
|
||||||
uasort($children, function($node1, $node2)
|
|
||||||
{
|
|
||||||
if(intval($node1[$sort_field]) === intval($node2[$sort_field])) return 0;
|
|
||||||
return intval($node1[$sort_field]) < intval($node2[$sort_field]) ? -1 : 1;
|
|
||||||
});
|
|
||||||
$flat = array_merge($flat, self::flattenTree($children, $sort_field, $depth+1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $flat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resiliently counts the results from the last SQL query in the given resource
|
|
||||||
*
|
|
||||||
* Sets the count in $this->_total
|
|
||||||
*
|
|
||||||
* @param resource $sql SQL resource that executed a query
|
|
||||||
* @return int Number of results from the latest query
|
|
||||||
*/
|
|
||||||
private function countResults($sql)
|
|
||||||
{
|
|
||||||
$this->_total = is_integer($sql->total_results) ? $sql->total_results : false; //requires SQL_CALC_FOUND_ROWS in query - see db handler
|
|
||||||
if(false === $this->_total && $this->getModelTable() && !$this->getParam('nocount'))
|
|
||||||
{
|
|
||||||
//SQL_CALC_FOUND_ROWS not found in the query, do one more query
|
|
||||||
// $this->_total = e107::getDb()->db_Count($this->getModelTable()); // fails with specific listQry
|
|
||||||
|
|
||||||
// Calculates correct total when using filters and search. //XXX Optimize.
|
|
||||||
$countQry = preg_replace('/(LIMIT ([\d,\s])*)$/', "", $this->getParam('db_query'));
|
|
||||||
|
|
||||||
$this->_total = e107::getDb()->gen($countQry);
|
|
||||||
|
|
||||||
}
|
|
||||||
return $this->_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get single model instance from the collection
|
* Get single model instance from the collection
|
||||||
* @param integer $node_id
|
* @param integer $node_id
|
||||||
|
Reference in New Issue
Block a user