Symfony - дерево категорий

Мне нужно построить дерево категорий для FancyTree (формат JSON), поэтому я делаю:
Категория Entity

class Category
{    
    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Category", inversedBy = "children")
     * @ORM\JoinColumn(name = "parent_id", referencedColumnName = "id", nullable=true)
     */
    private $parent;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Category", mappedBy = "parent")
     */
    private $children;

    // ...

    public function __construct()
    {
        $this->children = new ArrayCollection();
    }

    // ...

    /**
     * @return Category
     */
    public function getParent(): Category
    {
        return $this->parent;
    }

    /**
     * @return Collection|Category[]
     */
    public function getChildren()
    {
        return $this->children;
    }
}

и метод построения дерева:

public function buildCategoryTree($categories, ?int $activeCategory = null)
{
    $tree = [];
    foreach ($categories as $category) {
        $tmp = [
            "title" => $category->getName(),
            "expanded" => true,
            "folder" => true
        ];

        if ($category->getId() === $activeCategory)
            $tmp['active'] = true;

        if ($category->getChildren() != null)
            $tmp['children'] = $this->buildCategoryTree($category->getChildren(), $activeCategory);

        $tree[] = $tmp;
    }

    return $tree;
}

Но у меня бесконечный цикл - почему?
Я исправляю все дочерние элементы указанной категории (я не добавляю ее вручную), и я могу без проблем повторить ее.

посмотрите здесь: docs.doctrine-project.org/en/latest/reference/…

Mohammed Yassine CHABLI 24.03.2018 16:09

Можете ли вы показать нам, что вы передаете buildCategoryTree при первом вызове?

Scaramouche 25.03.2018 06:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
2
1 900
4

Ответы 4

ты можешь попробовать это:

 function buildTree($categories, $parentCategory = null) {
        $branch = array();

        foreach ($categories as $element) {
            if ($element->getParent() == $parentCategory) {
                $children = buildTree($categories, $element);
                if ($children) {
                    $element->getChildren() = $children;
                }
                $branch[$element->getId()] = $element;
                unset($categories[$element->getId()]);
            }
        }
        return $branch;
    }

проверьте это, пожалуйста:

<?php

use Doctrine\Common\Collections\ArrayCollection;

/** @ORM\Entity */
class Category {

    /**
     * @ORM\Id
     * @ORM\Column(type = "integer", name = "id")
     * @ORM\GeneratedValue
     */
    protected $id;

    // ...

    /**
     * @ORM\OneToMany(targetEntity = "Category", mappedBy = "parent")
     */
    protected $children;

    /**
     * @ORM\ManyToOne(targetEntity = "Category", inversedBy = "children")
     * @ORM\JoinColumn(name = "parent", referencedColumnName = "id")
     */
    protected $parent;

    public function __construct() {
        $this->children = new ArrayCollection();
    }

    // Once you have that, accessing the parent and children should be straight forward 
    // (they will be lazy-loaded in this example as soon as you try to access them). IE:

    public function getParent() {
        return $this->parent;
    }

    public function getChildren() {
        return $this->children;
    }

    // ...

    // always use this to setup a new parent/child relationship
    public function addChild(Category $child) {
       $this->children[] = $child;
       $child->setParent($this);
    }

    public function setParent(Category $parent) {
       $this->parent = $parent;
    }

}

Предполагая, что вы пытаетесь создать какую-то иерархическую структуру, подобную следующей:

array (size=1)
  6 => 
    array (size=4)
      'title' => string 'title6'
      'expanded' => boolean true
      'folder' => boolean true
      'children' => 
        array (size=2)
          4 => 
            array (size=3)
              'title' => string 'title4'
              'expanded' => boolean true
              'folder' => boolean true
          3 => 
            array (size=4)
              'title' => string 'title3'
              'expanded' => boolean true
              'folder' => boolean true
              'children' => 
                array (size=1)
                  2 => 
                    array (size=3)
                      'title' => string 'title2'
                      'expanded' => boolean true
                      'folder' => boolean true

попробуйте что-то вроде этого:

public function buildTree($rootCategory, &$tree, $activeCategory = null) {
        $tree = ["title" => $rootCategory->getName(),
            "expanded" => true,
            "folder" => true
        ];

        if ($rootCategory->getId() === $activeCategory)
            $tree['active'] = true;

        if (count($rootCategory->getChildren()->toArray())) {
            foreach ($rootCategory->getChildren() as $child) {
                $this->buildTree($child, $tree['children'][$child->getId()], $activeCategory);
            }
        }
    }

и вы называете это так в первый раз:

buildTree($rootCategory, $tree[$rootCategory->getId()], $activeCategoryId);

где $rootCategory - это тот, у которого нет родитель, а $tree - пустой массив.

По сути, вы создаете функцию void и передаете ей только корневую категорию, из которой вы строите свое дерево, в то же время вы добавляете каждый узел в $tree, который будет содержать всю структуру, когда алгоритм будет выполнен.

дайте мне знать, как это происходит.

private function categoryTree($parent_id = null)
{
    $a=array();
    $rows = $this->findBy(array('parent' => $parent_id), array('id' => 'ASC'));

    foreach ($rows as $row) {
        array_push(
            $a,
            array_filter([
                $row->getId() => $row->getName(),
                'children' => $this->categoryTree($row->getId())
            ])
        );
    }
    return $a;
}

Есть проект Doctrine Extensions. Он имеет вложенное поведение Дерево, которое можно использовать для решения проблемы.

URL: https://github.com/Atlantic18/DoctrineExtensions/blob/HEAD//doc/tree.md

Пакет для Symfony: https://symfony.com/doc/master/bundles/StofDoctrineExtensionsBundle/index.html

Другие вопросы по теме