From 28d70da8e6685ba151c71325da51c4daf452b96d Mon Sep 17 00:00:00 2001 From: Cameron Date: Sun, 28 Jan 2018 13:41:16 -0800 Subject: [PATCH] Revert #3016 --- e107_handlers/admin_ui.php | 93 +++++++++++++++++++----- e107_handlers/model_class.php | 130 +++++----------------------------- 2 files changed, 92 insertions(+), 131 deletions(-) mode change 100755 => 100644 e107_handlers/model_class.php diff --git a/e107_handlers/admin_ui.php b/e107_handlers/admin_ui.php index bc1e2965f..25eefb1b8 100644 --- a/e107_handlers/admin_ui.php +++ b/e107_handlers/admin_ui.php @@ -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. { // $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); - //$this->listOrder = '_treesort '; // .$this->sortField; + $qry = $this->getParentChildQry(); + $this->listOrder = '_treesort '; // .$this->sortField; // $this->orderStep = ($this->orderStep === 1) ? 100 : $this->orderStep; } 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 - * - * 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. * @return string */ 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() - #return "SELECT SQL_CALC_FOUND_ROWS * FROM `#".$this->getTableName()."` ORDER BY ".$this->getSortParent().", ".$this->getSortField(); + + $parent= $this->getSortParent(); + $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) ->setUrl($this->url) ->setMessageStackName('admin_ui_tree_'.$this->table) - ->setParams(array('model_class' => 'e_admin_model', - '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(), - )); + ->setParams(array('model_class' => 'e_admin_model', 'model_message_stack' => 'admin_ui_model_'.$this->table ,'db_query' => $this->listQry)); return $this; } diff --git a/e107_handlers/model_class.php b/e107_handlers/model_class.php old mode 100755 new mode 100644 index 97a2399e1..1ef1cac0e --- a/e107_handlers/model_class.php +++ b/e107_handlers/model_class.php @@ -3310,6 +3310,7 @@ class e_tree_model extends e_front_model return $this; } + $class_name = $this->getParam('model_class', 'e_model'); // auto-load all 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)) { $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)) { - $rows = self::flatTreeFromArray($sql->rows(), - $this->getParam('primary_field'), - $this->getParam('sort_parent'), - $this->getParam('sort_field') - ); - foreach($rows as $tmp) + $this->_total = is_integer($sql->total_results) ? $sql->total_results : false; //requires SQL_CALC_FOUND_ROWS in query - see db handler + while($tmp = $sql->db_Fetch()) { $tmp = new $class_name($tmp); 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); } - 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()) @@ -3365,111 +3372,6 @@ class e_tree_model extends e_front_model 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 * @param integer $node_id