@vasisualii

Баг при копировании дерева?

Имеется некая древовидная структура папок. Хранится все в psql. Необходимо скопировать эту структуру, что бы папки имели новые id, но связи родитель-потомок осталась между всеми новыми папками. Т.к. в БД используются внешние ключи, то необходимо создавать папки рекурсивно, от корневой к дочерним, что бы в базе создались все нужные связи.

Получаем все текущие папки и вызываем рекурсивную функцию:
$groups = Group::query()->execute();
$newGroupId = $this->deployChildGroups($groups, 0,  []);


Сама рекурсивная функция
/**
     * @param $platformId
     * @param $parentId
     * @param $sourceGroups Device\Group[]
     * @param $resultsId
     */
    public function deployChildGroups($sourceGroups, $parentId, $resultsId)
    {
        // Если исходные папки находятся в корневой директории, то и новые создаем там же
        if ($parentId == 0) {
            $newParentId = 0;
        } else {
            if (! isset($resultsId[$parentId])) {
                return false;
            }
            $newParentId = $resultsId[$parentId];
        }

        foreach ($sourceGroups as $sourceGroup) {
            if ($sourceGroup->getParentId() == $parentId) {
                $group = new Group();
                $group->setName($sourceGroup->getName());
                $group->setParentId($newParentId);
                $group->save();

                $resultsId[$sourceGroup->getId()] = $group->getId();
                $resultsId = $this->deployChildGroups($sourceGroups, $sourceGroup->getId(), $resultsId);
            }
        }

        return $resultsId;
    }


Результат, если честно - не очень. Копируются только первые папки на каждом уровне. Вот эти:
2cc26380790a4d69ba1c71f9618a0837.png

Результат:
{"210":"296","273":"297","274":"298"}

Что за петрушка с рекурсией? Почему он в цикле не проходится по всем папкам?
  • Вопрос задан
  • 134 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Niomin
Не смотрели порядок обхода?
if (! isset($resultsId[$parentId])) {
    return false;
}

В этом месте он может пропустить приличное количество подпапок (в том числе все).
Даже отсортированные Group не гарантируют, что получится скопировать дерево целиком, ведь если родитель появился после потомка, то начнёт с потомка.

То есть предложенный алгоритм в принципе плохо справится с этой задачей. Нужно или хранить в виде дерева (то есть в памяти), или хранить флаг о том, что этот элемент уже прошли (с инкрементными айди можно использовать в качестве костыля-флага значение id, больше или меньше старого максимального).

Другие адекватные решения в голову не приходят :)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы