Когда речь идет о удалении дерева с помощью вложенных множеств, очень важно пересчитать значения lft
(левый индекс) и rgt
(правый индекс) для остальных узлов в дереве.
Перед тем, как пересчитать эти значения, нужно определить, какие узлы будут удалены. В Symfony есть встроенная функция preRemove
для обнаружения предстоящего удаления объекта. В этой функции вы можете определить всех родителей и детей удаляемого узла.
После определения удаляемых узлов вы должны обновить lft
и rgt
для всех остальных узлов в дереве. Это делается с помощью алгоритма, который включает следующие шаги:
- Увеличьте все
lft
иrgt
узлов, у которых их текущие значения больше, чемrgt
удаляемого узла. Это нужно сделать, чтобы сделать место для удаления узлов. - Вычтите разницу между
rgt
иlft
удаленного узла из всехrgt
, которые находятся выше удаляемого узла. Таким образом, вы уменьшите значенияrgt
для всех родительских узлов дерева. - Вычтите разницу между
rgt
иlft
(плюс единица) удаленного узла из всехlft
, которые находятся выше удаляемого узла. Это уменьшает значениеlft
для всех узлов выше удаленного узла. - После этого вы можете удалить сами узлы из базы данных.
Вам также нужно учесть, что пересчет 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
при удалении узлов в дереве, используя вложенные множества.