Когда речь идет о удалении дерева с помощью вложенных множеств, очень важно пересчитать значения lft
(левый индекс) и rgt
(правый индекс) для остальных узлов в дереве.
Перед тем, как пересчитать эти значения, нужно определить, какие узлы будут удалены. В Symfony есть встроенная функция preRemove
для обнаружения предстоящего удаления объекта. В этой функции вы можете определить всех родителей и детей удаляемого узла.
После определения удаляемых узлов вы должны обновить lft
и rgt
для всех остальных узлов в дереве. Это делается с помощью алгоритма, который включает следующие шаги:
1. Увеличьте все lft
и rgt
узлов, у которых их текущие значения больше, чем rgt
удаляемого узла. Это нужно сделать, чтобы сделать место для удаления узлов.
2. Вычтите разницу между rgt
и lft
удаленного узла из всех rgt
, которые находятся выше удаляемого узла. Таким образом, вы уменьшите значения rgt
для всех родительских узлов дерева.
3. Вычтите разницу между rgt
и lft
(плюс единица) удаленного узла из всех lft
, которые находятся выше удаляемого узла. Это уменьшает значение lft
для всех узлов выше удаленного узла.
4. После этого вы можете удалить сами узлы из базы данных.
Вам также нужно учесть, что пересчет lft
и rgt
может вызывать изменения в базе данных, поэтому рекомендуется выполнять эту операцию в одной транзакции для обеспечения целостности данных.
Пример кода для выполнения этих шагов может выглядеть следующим образом:
/** * @ORMPreRemove() */ public function preRemove() { $parent = $this->getParent(); // получить родительский узел $children = $this->getChildren(); // получить дочерние узлы $difference = $this->getRgt() - $this->getLft() + 1; // вычислить разницу между rgt и lft узла // Обновите lft и rgt для узлов выше удаленного узла // увеличьте lft и rgt для узлов, у которых их текущие значения больше, чем rgt удаляемого узла $qb = $this->createQueryBuilder('n') ->update() ->set('n.lft', 'n.lft + :difference') ->set('n.rgt', 'n.rgt + :difference') ->where('n.rgt > :rgt') ->setParameter('difference', $difference) ->setParameter('rgt', $this->getRgt()) ->getQuery(); $qb->execute(); // уменьшить rgt для всех родительских узлов дерева if ($parent) { $qb = $this->createQueryBuilder('n') ->update() ->set('n.rgt', 'n.rgt - :difference') ->where('n.lft < :lft') ->andWhere('n.rgt > :rgt') ->andWhere('n.root = :root') ->setParameter('difference', $difference) ->setParameter('lft', $this->getLft()) ->setParameter('rgt', $this->getRgt()) ->setParameter('root', $this->getRoot()) ->getQuery(); $qb->execute(); } // уменьшить lft для всех узлов выше удаленного узла if ($parent) { $qb = $this->createQueryBuilder('n') ->update() ->set('n.lft', 'n.lft - :difference') ->where('n.lft > :lft') ->andWhere('n.root = :root') ->setParameter('difference', $difference) ->setParameter('lft', $this->getRgt()) ->setParameter('root', $this->getRoot()) ->getQuery(); $qb->execute(); } // удалить сами узлы $qb = $this->createQueryBuilder('n') ->delete() ->where('n.lft >= :lft') ->andWhere('n.rgt <= :rgt') ->andWhere('n.root = :root') ->setParameter('lft', $this->getLft()) ->setParameter('rgt', $this->getRgt()) ->setParameter('root', $this->getRoot()) ->getQuery(); $qb->execute(); }
Это всего лишь пример, и вам может потребоваться настроить его для ваших конкретных требований и моделей данных в Symfony. Однако он предоставляет общую идею о том, как пересчитывать значения lft
и rgt
при удалении узлов в дереве, используя вложенные множества.