【发布时间】:2018-01-05 15:14:27
【问题描述】:
我正在开发一个将树存储在数据库中的应用程序。该应用程序是使用 CakePHP 2.x 和 jstree 3.2.1 构建的
保存数据的架构如下:
-
id- 自动递增 ID,对于树的每个节点都是唯一的 -
parent_id- 元素的父 ID;null如果没有父级(顶级元素)。 -
lft,rght- 使用 CakePHP 的 Tree Behaviour,它使用 Modified Preorder Tree Traversal。这些代表lft和rght值。 -
name- 节点的文本名称 -
pos- 一个从 0 开始的整数,用于确定节点在其父节点下的位置。
我遇到的问题是在对树中节点的位置进行更新时“调整”所有 pos 元素。
例如,考虑以下数据:
id | parent_id | name | pos
--------------------------------------------------
149 | NULL | Foo | 0
150 | 149 | A | 0
151 | 149 | B | 1
152 | 149 | C | 2
153 | 149 | D | 3
154 | 149 | E | 4
155 | 149 | F | 5
在视觉上,如下所示:
- 富
- 一个
- B
- C
- D
- E
- F
现在,如果我将“E”拖放到“B”和“C”之间...
- 富
- 一个
- B
- E(移动)
- C
- D
- F
...我需要更新我的数据库中的 pos 值,用于“Foo”的所有子项。
当拖放发生时,jstree 为我提供:
- 我移动的元素的
id。 “E”是154。 -
parent_id,“E”已被删除。在这种情况下,它是149,因为它仍然是“Foo”的子元素,但理论上可以移动到树上的任何其他元素下。 - 它被放入的
pos(位置)。它们从0开始,所以在上面的例子中,移动“E”后它位于pos = 2。
了解节点可以向上或向下拖动是很重要的,但 jstree 只会提供与其在父节点下的位置相关的pos(以及parent_id和id)。
所以我可以用“E”的新pos 更新我的数据库:
>UPDATE tree SET pos = 2 WHERE id = 154 AND parent_id = 149;
id | parent_id | name | pos
--------------------------------------------------
149 | NULL | Foo | 0
150 | 149 | A | 0
151 | 149 | B | 1
152 | 149 | C | 2
153 | 149 | D | 3
154 | 149 | E | 2 (*updated*)
155 | 149 | F | 5
我遇到的问题是如何重新排列其他 pos 值。例如,“C”现在应该有一个pos 值4。
GitHub上有一些代码显示an example of how the data is saved when a node is moved,但我无法遵循(尽管经历了几天)或将其调整为CakePHP。事实上,提供的大部分代码都是不必要的,因为 Cake 负责生成 lft 和 rght 值。所以我想知道的是如何使用 PHP/MySQL 将数字“转换”或“调整”回数字序列。
我提供这个以防万一:
pos 值按顺序在每个父节点 (parent_id) 下。因此,如果我们有另一个父元素“Bar”,它有子元素“XX”、“YY”和“ZZ”,数据可能看起来像这样。注意pos 的值是什么。
所以查询应该只在任何特定时间为给定的parent_id 调整pos 的序列。在前面的示例中,我只想将 pos 重新排序为 parent_id = 149 - 假设我正在移动节点“E”。
id | parent_id | name | pos
--------------------------------------------------
149 | NULL | Foo | 0
150 | 149 | A | 0
151 | 149 | B | 1
152 | 149 | C | 2
153 | 149 | D | 3
154 | 149 | E | 4
155 | 149 | F | 5
906 | NULL | Bar | 0
907 | 906 | XX | 0
908 | 906 | YY | 1
909 | 906 | ZZ | 2
【问题讨论】:
-
您应该能够使用 Tree 行为的 moveUp 和 moveDown 方法吗? book.cakephp.org/2.0/en/core-libraries/behaviors/…
-
我也这么认为,但事实并非如此。我们只有
pos值可以使用,所以我们不知道移动它的方向,甚至不知道它相对于它移动之前的位置的数量。我也花了很长时间研究它,但在这种情况下它无法使用。 -
您是否尝试过使用我在上一个问题中描述的方法?持有该职位的列似乎是多余的,因为这就是
lft列的用途。 -
@ndm 否,因为您在哪里说“确定
moveUp/Down()的增量”,根本不清楚如何做到这一点。我提供给 GitHub 的链接显示开发人员同时使用了pos字段以及lft和rght,所以我认为这是有原因的。此外,您不能使用 Cake 提供的moveUp()或moveDown(),因为您不知道节点已移入哪个方向(向上或向下)。您只知道它在父节点下方的相对位置 - 例如如果pos值为 2,则表示它在列表中的第三个(第三个不是第二个,因为索引为 0)。 -
您可以通过从新位置减去当前位置(在子节点列表中)并检查结果是负数(上移)还是正数(下移)来确定方向。我不知道开发人员为什么选择做他所做的事情,但是为了能够重新排序嵌套集,没有必要这样做,因为它实际上只是复制了已经由左值确定的内容。