Tree在CakePHP中重新排序

时间:2013-09-26 23:07:50

标签: cakephp

我正在使用树行为来存储有序的项目列表。

当我向树中添加新元素时,我将其重新排序,调用“reorder()”函数。这很慢。我一直在尝试很多东西。我的最后一次测试是一个包含70个元素的单个表(1个父项和69个孩子)。用于reorder()函数的时间是1分钟& 20秒我正在使用MySQL,我在id,parent_id,rght和lft字段中都有索引。

我可能做错了什么?

谢谢

1 个答案:

答案 0 :(得分:0)

我也花了一些时间调查这个。

事实证明,重新排序功能非常低效。基本上它将第一个项目的左侧和右侧字段设置为高值,然后重新排序其余字段。然后它对第二个项目执行相同的操作等。对于只有一百个项目的树,最终会运行数万个查询。

我使用以下代码对其进行了整理。这样做只会更新每个记录一次,并保留左右值之间的差距。它递归地遍历项目并正确地重新排序。

在app / Model / Behavior中创建一个名为“BRTreeBehavior.php”的新文件,然后修改模型的$ actsAs字段以使用BRTree而不是Tree。

<?php
/**
 * Copyright 2015, Perthweb Pty Ltd
 *
 */

App::uses('TreeBehavior', 'Model/Behavior');

/**
 * BetterReorderTree Behavior.
 *
 * Improves reorder of tree behavior
 *
 */
class BRTreeBehavior extends TreeBehavior {


    /**
     * Reorder method.
     *
     * Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters.
     * This method does not change the parent of any node.
     *
     * Requires a valid tree, by default it verifies the tree before beginning.
     *
     * Options:
     *
     * - 'id' id of record to use as top node for reordering
     * - 'field' Which field to use in reordering defaults to displayField
     * - 'order' Direction to order either DESC or ASC (defaults to ASC)
     * - 'verify' Whether or not to verify the tree before reorder. defaults to true.
     *
     * @param Model $Model Model instance
     * @param array $options array of options to use in reordering.
     * @return boolean true on success, false on failure
     * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::reorder
     */
    public function reorder(Model $Model, $options = array()) {
        $options = array_merge(array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true, 'startIndex' => null), $options);
        extract($options);
        if ($verify && !$this->verify($Model)) {
            return false;
        }
        $verify = false;
        extract($this->settings[$Model->alias]);
        $fields = array($Model->primaryKey, $field, $left, $right);
        $sort = $field . ' ' . $order;
        $nodes = $this->children($Model, $id, true, $fields, $sort, null, null, $recursive);

        $cacheQueries = $Model->cacheQueries;
        $Model->cacheQueries = false;
        if ($nodes) {
            if($id == null){
                $index = 1;
            }
            else if($startIndex == null){
                $index = $nodes[0][$Model->alias][$left];
            }
            else {
                $index = $startIndex;
            }

            foreach ($nodes as $node) {
                $id = $node[$Model->alias][$Model->primaryKey];

                $difference = $node[$Model->alias][$right] - $node[$Model->alias][$left];

                $nodeData = array(
                    $Model->alias => array(
                        $Model->primaryKey => $id,
                        $left => $index,
                        $right => $index + $difference
                    )
                );

                $Model->create();
                $Model->save($nodeData, array('validate' => false, 'callbacks' => false, 'fieldList' => array($left, $right)));
                $Model->clear();

                $startIndex = $index + 1;

                if ($difference != 1) {
                    $this->reorder($Model, compact('id', 'field', 'order', 'verify', 'startIndex'));
                }

                $index += $difference + 1;
            }
        }
        $Model->cacheQueries = $cacheQueries;
        return true;
    }


}