6

我有以下表结构,为了方便起见,它也在 sqlfiddle上:

+---------+------------+---------+----------+------ -----+--------------------------------+------------ ------------+--------+--------------+-------------+ ---------------+------------+
| 规则ID | parent_id | left_id | right_id | 规则类型 | 规则标题 | 规则描述 | 公共 | parse_bbcode | 解析链接 | parse_smilies | group_ids |
+---------+------------+---------+----------+------ -----+--------------------------------+------------ ------------+--------+--------------+-------------+ ---------------+------------+
| 1 | 0 | 1 | 6 | 猫 | 样品类别 1 | | 1 | 0 | 0 | 0 | 1 2 7 |
| 2 | 1 | 2 | 3 | 规则 | 示例规则 1 | 这是一个示例规则描述 | 1 | 1 | 1 | 1 | 1 2 7 |
| 3 | 0 | 7 | 8 | 猫 | 样品类别 2 | | 1 | 0 | 0 | 0 | 1 7 2 |
| 4 | 0 | 9 | 10 | 猫 | 样品类别 3 | | 1 | 0 | 0 | 0 | 1 7 2 |
| 5 | 1 | 4 | 5 | 规则 | 示例规则 3 | 大声笑| 1 | 1 | 1 | 1 | 1 2 7 |
+---------+------------+---------+----------+------ -----+--------------------------------+------------ ------------+--------+--------------+-------------+ ---------------+------------+

如您所见,rule_type可以是'cat''rule'

cat代表类别,类别是根节点:parent_id总是如此0。在我的代码中,我们可以通过检查 ifrule_type = 'cat'或来识别类别parent_id = 0

您还可以看到我正在为我的项目使用嵌套集,这就是问题所在。

我已经成功创建了以下功能:

  • 上下移动规则和类别;和

  • 将新规则或类别放在各自位置的末尾。

但是我没有设置规则 right_idleft_id如果我们改变它parent_id!如果我们删除规则或类别,right_id我也无法设置。left_id

例子

我将尝试用一个例子来解释。请注意,这只是一个示例,而不是实际情况,我需要一个一般性的答案。

从上表中,我们看到我们有 3 个类别rule_id IN (1, 3, 4)和两个规则rule_id IN (2, 5)

带的规则是带rule_id = 2的类别的一部分,我们可以从列rule_id = 1中看到。parent_id如果我更改parent_id为 4 怎么办?如何设置right_id&left_id以使一切都恢复原状?我知道我们需要更新两者rule_id IN (1, 4)以重新排序所有内容,但我不知道我的查询会是什么样子。

删除也是如此...例如我删除rule_id = 2(这是一个规则),我将如何以正确的顺序设置right_id& ?或者当我删除一个类别时?我将如何重新排序类别?left_idparent_id = 1

我并没有真正尝试在这里做任何事情,因为我不知道如何做这样的事情,因此我寻求你们的帮助,伙计们。

我希望我说清楚了。如果没有,请告诉我,我会尝试更具描述性。

4

2 回答 2

7

我假设您已成功设置 PDO 连接。

此外,请注意以下示例仅在所有类别都是根节点时才有效(如主题中)。更改此代码以使用嵌套类别不是问题。

删除规则

  1. 检索其right_idleft_id值。

  2. 从数据库中删除行。

  3. 更新表集right_id- 2,其中right_id大于right_id删除规则。

  4. 相同的left_id

例子:

    $ruleIdForDel = 2;
    $leftId = 2;
    $rightId = 3;

    $pdo->beginTransaction();
    try {
        $pdo->exec("DELETE FROM rules WHERE rule_id = $ruleIdForDel");
        $pdo->exec("UPDATE rules
                    SET left_id = CASE
                            WHEN left_id > $leftId THEN left_id - 2
                            ELSE left_id
                        END,
                        right_id = CASE
                            WHEN right_id > $rightId THEN right_id - 2
                            ELSE right_id
                        END");
        $pdo->commit();
    } catch (Exception $e) {
        $pdo->rollBack();
        throw $e;
    }

更新规则parent_id

假设我们要将节点移动到新父节点的最后一个位置

  1. 检索更新规则的left_idand right_id( $ruleLeftIdand $ruleRightId)

  2. 检索新的父规则的left_idand right_id( $newParentRuleLeftIdand $newParentRuleRightId)

  3. 检查一个节点是否在树上向上或向下移动,并根据它为更新规则(和)生成新的left_idright_id$ruleNewLeftId$ruleNewRightId

  4. 更新规则left_idright_id取决于更新规则的目的地

  5. 更新规则parent_id的更新left_idright_id

如果更新规则right_key小于新的父规则right_id,则规则向下移动树,否则向上移动。

如果规则沿着树向下移动,我们将对left_id位于更新规则left_id( $ruleLeftId) 和 new left_id( $ruleNewLeftId) + 1 之间的规则的值移动负 2。否则,将left_id位于新规则left_id($ruleNewLeftId) 和之间的规则的值移动 2初始left_id$ruleLeftId)。

right_id.

例子:

    // Updating rule
    $ruleId = 2;
    $ruleLeftId = 2;
    $ruleRightId = 3;

    // New parent rule
    $newParentRuleId = 3;
    $newParentRuleLeftId = 7;
    $newParentRuleRightId = 8;


    // Generate new rule's left and right keys
    // Moves up
    if ($newParentRuleRightId < $ruleRightId) {
        $ruleNewLeftId = $newParentRuleRightId;
        $ruleNewRightId = $newParentRuleRightId + 1;
    // Moves down
    } else {
        $ruleNewLeftId = $newParentRuleRightId - 2; // 6
        $ruleNewRightId = $newParentRuleRightId - 1; // 7
    }

    $pdo->beginTransaction();
    try {
        $pdo->exec("UPDATE rules
                            SET left_id = CASE
                                /* Moves down */
                                WHEN $ruleNewRightId > $ruleRightId AND
                                     left_id > $ruleLeftId AND
                                     left_id <= $ruleNewLeftId + 1 THEN left_id - 2
                                /* Moves up */
                                WHEN $ruleNewRightId < $ruleRightId AND
                                     left_id >= $ruleNewLeftId AND
                                     left_id < $ruleLeftId THEN left_id + 2
                                ELSE left_id
                            END,
                            right_id = CASE
                                WHEN $ruleNewRightId > $ruleRightId AND
                                     right_id > $ruleRightId AND
                                     right_id <= $ruleNewRightId THEN right_id - 2
                                WHEN $ruleNewRightId < $ruleRightId AND
                                     right_id >= $ruleNewLeftId AND
                                     right_id <= $ruleRightId THEN right_id + 2
                                ELSE right_id
                            END");
        $pdo->exec("UPDATE rules
                    SET parent_id = $newParentRuleId,
                        left_id = $ruleNewLeftId,
                        right_id = $ruleNewRightId
                    WHERE rule_id = $ruleId");
        $pdo->commit();
    } catch (Exception $e) {
        $pdo->rollBack();
        throw $e;
    }

我没有使用任何PDO::Statement只是为了节省空间。

我没有正确测试它,所以如果你发现一些问题,请发布一个问题。

于 2012-10-29T11:08:37.257 回答
1

rule_id = 2 的规则是 rule_id = 1 的类别的一部分,我们可以从 parent_id 列中看到。如果我将 parent_id 更改为 4 会怎样?如何设置 right_id 和 left_id 以便一切都恢复原状?我知道我们需要同时更新 rule_id IN (1, 4) 以重新排序所有内容,但我不知道我的查询会是什么样子。

试试这样的东西,我还没有测试过,但它可能会让你走上正轨

UPDATE table SET parent_id = 4, 
                 right_id = (CASE WHEN parent_id = 4 THEN 1 END), 
                 left_id = (CASE WHEN parent_id = 4 THEN 2 END)
于 2012-10-25T17:11:55.900 回答