Рекурсивное удаление ребенка нижнего уровня Symfony / Doctrine - PullRequest
0 голосов
/ 10 апреля 2020

В настоящее время я работаю со структурой данных, которая использует узлы в таблице узлов. Это самоссылка, в которой есть столбец id и parent_id. Родительско-дочерние отношения один-ко-многим. Это означает, что несколько узлов могут иметь один и тот же parent_id. Это также может переходить вниз на переменное количество уровней.

Проблема в том, что я не могу просто удалить родителя, так как это не удается из-за ограничения внешнего ключа. Это хорошо, потому что я не хочу, чтобы дети осиротели. Однако это означает, что я должен рекурсивно проходить через детей до тех пор, пока не доберусь до самого нижнего уровня, удалить этого ребенка и затем вернуться обратно.

Мне пока не повезло. Это моя «лучшая» попытка, но массив toRemove всегда оказывается пустым, когда я его сбрасываю.

/**
 * @var array
 */
private $toRemove;

/**
 * constructor.
 *
 * @param array $toRemove
 */
public function __construct(
    EntityManagerInterface $entityManager,
    array $toRemove = []
)
{
    $this->toRemove = $toRemove;
}

someMainFunc(blabla)
{
    foreach ($nodes as $node) {
        $this->removeChildrenFromLowestLevelUp($node)
    }
    dump($this->toRemove);die;
}

public function removeChildrenFromLowestLevelUp(Node $node)
{
    if (null === $node->getChildren()) {
        // Node has no children, add to toRemove array
        $this->toRemove[] = $node;
    }

    /** @var Node $child */
    foreach ($node->getChildren() as $child) {
        $this->removeChildrenFromLowestLevelUp($child);
    }
}

Я знаю, что есть множество решений для этого на inte rnet, но я не могу заставить любого из них сделать это так, как я хочу.

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 10 апреля 2020

Ты не хочешь этого делать.

Прежде всего, это означает много запросов и операций с памятью. Во-вторых, это изобретение колеса, поскольку такие механизмы уже реализованы в обеих базах данных и Doctrine.

. Вы можете сделать это на уровне Doctrine, используя опцию cascade:remove в сопоставлении для этой взаимосвязи. Проверьте документацию для получения более подробной информации.

Просто помните, что - как указано в документации - все связанные объекты будут загружены из БД в память и затем удалены. Это также означает некоторые ненужные запросы.

Второй способ достижения этого - использование SQL ON DELETE CASCADE, что делает то же самое, но на уровне базы данных. Вы можете установить его в Doctrine, используя опцию onDelete=CASCADE в вашем отображении.

Исходя из вашего описания, я бы порекомендовал второй вариант.

...