使用CakePHP 2.x Tree和jstree更改节点的位置

时间:2018-01-03 11:16:01

标签: php cakephp tree cakephp-2.0 jstree

我有一个使用CakePHP 2.x和jstree 3.2.1的应用程序。我试图弄清楚在使用CakePHP将节点写入数据库时​​如何指定节点的位置。该职位本身来自jstree ......

当我使用jstree拖放项目时,请求URL会给我:

  • id - 正在拖动的节点的ID。
  • parent_id - 已删除节点的(父)ID。
  • position - 这是一个从0开始的整数,表示idparent_id被删除的位置。例如,position 2表示它应该出现在第3个位置(第3个,而不是第2个,因为它们从0开始)。

CakePHP中的方法Tree Behaviour允许您上下移动树中的节点。这些方法分别称为moveUp()moveDown()

我不明白如何使用jstree提供的数据与Cake的树行为,以便您可以正确更新/保存位置。 < / p>

position传递给moveUp()moveDown()会产生错误的结果。为什么呢?

  • 如果jstree提供position = 2并且您正在通过CakePHP调用moveUp(2)的列表中移动第10个项目意味着它将进入第8个位置,而不是按预期进入第2个位置。同样,moveDown(2)会将其移至第12位,这不是理想的结果。

Cake为其提供的架构树行为没有&#34;位置&#34;领域。而是使用lftrght字段。架构有:

  • id - 每个树节点的ID(自动增量)
  • parent_id - 节点的父ID。 NULL如果是最高级别(没有父级)。
  • lftrght - 用于MPTT逻辑。 Cake会自动生成这些值。它们可用于使用ORDER BY lft ASC确定订单。但它们与jstree提供的position值不同,并且每行都是唯一的
  • name - 节点的文本名称。

例如,请考虑以下树:

  • D(id = 149
    • 1(id = 150parent_id = 149
    • 2(id = 153parent_id = 149
    • 3(id = 154parent_id = 149
    • 4(id = 155parent_id = 149
    • 5(id = 156parent_id = 149

在数据库Cake中存储如下:

enter image description here

如果我要使用jstree来拖放&#34; 2&#34;所以它出现在&#34; 3&#34;和&#34; 4&#34;它会发出一个包含以下GET变量的请求:

id = 153。这是&#34; 2&#34;

的ID

parent_id = 149。这是&#34; D&#34;的ID这是&#34; 2&#34;的父节点。

position = 2。这意味着第3个位置(第3个位置,因为位置从0开始)。

但我无法从此数据中重新生成lftrght值? moveUp() / moveDown()在这里没有帮助,因为position无法以一种可以使其发挥作用的方式传递。

树应按以下顺序排列。 idparent_id不应更改,但lftrght必须更改,因为&#34; D&#34;已被有效重新订购:

  • d
    • 1
    • 3
    • 2(移动
    • 4
    • 5

任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

我从未使用过jsTree,但如果它为您提供了新的父ID和排序位置,那么您应该可以使用保存新父级的组合:

$Model->save(array('parent_id' => $parentId));

之后获得其子列表,其中包括新孩子:

$children = $Model->children($parentId, true, array('id'));

并使用排序位置确定移动修改后的子项的增量:

$childIds = Hash::extract($children, '{n}.Model.id');
$positionMap = array_flip($childIds);

$currentPosition = $positionMap[$nodeId];
$delta = (int)$position - $currentPosition;

if ($delta !== 0) {
    if ($delta < 0) {
        $Model->moveUp($nodeId, abs($delta));
    } else {
        $Model->moveDown($nodeId, abs($delta));
    }
}

这只是一个粗略的例子,应该说明这是如何工作的想法,它假设$parentId是新父的ID,$nodeId是要移动的行的ID ,和$position孩子被移动到的(零基础)位置。您也必须考虑其他情况,例如父母ID没有变化,即只有排序位置发生变化,这应该都是在交易中完成的!

这是一个基于Cookbook示例的完整代码段,它会将Gwendolyn节点移动到Work节点中的第二个位置:

$nodeId = 8;
$parentId = 9;
$position = 1;

$dataSource = $this->Category->getDataSource();
$dataSource->begin();

$this->Category->id = $nodeId;
if (!$this->Category->save(array('parent_id' => $parentId))) {
    $dataSource->rollback();
} else {
    $children = $this->Category->children($parentId, true, array('id'));
    $childIds = Hash::extract($children, '{n}.Category.id');
    $positionMap = array_flip($childIds);

    $result = true;

    if (isset($positionMap[$nodeId])) {
        $currentPosition = $positionMap[$nodeId];
        $delta = (int)$position - $currentPosition;

        if ($delta !== 0) {
            if ($delta < 0) {
                $result = $this->Category->moveUp($nodeId, abs($delta));
            } else {
                $result = $this->Category->moveDown($nodeId, abs($delta));
            }
        }
    }

    if ($result) {
        $dataSource->commit();
    } else {
        $dataSource->rollback();
    }
}