Doctrine 2: получение дерева

scorpion-ds

Новичок
Мне нужно получить список всех дочерних элементов дерева, начиная от указанного.

В черновом варианте, написал такую функцию:
PHP:
public function getAllChildrens($id = 0)
    {
      
        $childrens = array();
      
        $qb = $this->createQueryBuilder('c')->select('c');
        $qb
        ->where('c.parent = :id')
        ->setParameter('id', $id)      
        ;
      
        $rows = $qb->getQuery()->getResult();
      
        foreach ($rows as $item)
        {
            $childrens[] = $item;
          
            if(is_object($item->getParent()))
            {
                $childrens = array_merge($childrens, $this->getAllChildren($item->getId()));
            }
          
        }
      
        return $childrens;
      
    }
разумеется так делать нельзя.

Хотел поступить по старинке, одним запросом получить все записи из таблицы, а потом уже на PHP построить необходимое мне дерево:
PHP:
public function getAllChildrens($id = 0)
    {
      
        $qb = $this->createQueryBuilder('c')
                ->select('c')
                ;
        $rows = $qb->getQuery()->getArrayResult();
      
        print_r($rows);
      
    }
но при таком запросе я не получаю значение элемента "parent" в БД он содержит ИД родителя, но в модели это "поле-связь".

Подскажите, как мне получить значение parent или другой более правильный способ получения дерева.

P.S.: Да, дерево строится классически, то есть с использованием только "parent".
 
Последнее редактирование:

hell0w0rd

Продвинутый новичок
Выбери все и найти те, у кого parent === null, в чем проблема? Ну и определение children добавь, а то не понятно как ты будешь деревом пользоваться
 

scorpion-ds

Новичок
Немного разобрался (я там затупил немного), если результат обрабатывать как объект, то при доступе к parent ни каких дополнительных запросов не делается, а children у меня есть, но если я начинаю обращаться к потомкам, то происходят дополнительные запросы, в результате чего, если мне нужно получить всех потомков какого-то элемента, то выполняется масса запросов. К конкретной задаче, мне надо было получить ID всех дочерних категорий, для того, что бы потом сделать выборку товаров из них.

Я в итоге, обошелся одним запросом, который потом обрабатываю на php и получаю элемент и его потомков.

Проект новый (то есть пока можно экспериментировать), хочу сегодняшний день выделить и попробовать пойти по пути "деревьев" (http://phpclub.ru/detail/article/db_tree), но я использую Symfony 2 и Sonata, я не уверен, что последнюю будет просто настроить на работу с деревьями, нашел вот такую статью http://habrahabr.ru/post/143413/ она хоть и старая но вроде по теме, еще есть некий бандел "Doctrine2 PHPCR Admin" для Sonata, о нем тоже почитаю.
 

scorpion-ds

Новичок
Все же решил переделать на "деревья" категории в проекте, пришлось соответственно переделать и вывод, но думаю оно того стоит, так как этот проект придется еще в будущем дорабатывать и развивать, в решении задачи помогла статья с Хабра, а "Sonata Doctrine2 PHPCR Admin" это некая недоделанная и на мой взгляд неудобная заготовка для CMS основанной на деревьях.

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

AnrDaemon

Продвинутый новичок
Детей надо не отсеивать, а регистрировать, чтобы в итоге получить полносвязный список.
 

scorpion-ds

Новичок
Детей надо не отсеивать, а регистрировать, чтобы в итоге получить полносвязный список.
Подскажите, как это сделать, сейчас имеется такое:
PHP:
namespace CS\TaxonomyBundle\Entity;

use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;

/**
* Category
*
* @Gedmo\Tree(type="nested")
* @ORM\Table(name="cs_taxonomy_category")
* @ORM\Entity(repositoryClass="CS\TaxonomyBundle\Entity\Repository\CategoryRepository")
* @ORM\HasLifecycleCallbacks()
*/
class Category
{
    /**
    * @var integer
    *
    * @ORM\Column(name="id", type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;
  
    /**
    * @Gedmo\TreeLeft
    * @ORM\Column(name="lft", type="integer")
    */
    private $lft;

    /**
    * @Gedmo\TreeLevel
    * @ORM\Column(name="lvl", type="integer")
    */
    private $lvl;

    /**
    * @Gedmo\TreeRight
    * @ORM\Column(name="rgt", type="integer")
    */
    private $rgt;

    /**
    * @Gedmo\TreeRoot
    * @ORM\Column(name="root", type="integer", nullable=true, options={"default" = 0})
    */
    private $root;
  
    /**
    * @Gedmo\TreeParent
    * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
    * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE", nullable=true)
    */
    protected $parent;
  
    /**
    * @ORM\OneToMany(targetEntity="Category", mappedBy="parent", orphanRemoval=true, cascade={"persist", "remove"})
    * @ORM\OrderBy({"lft" = "ASC"})
    */
    protected $children;
  
}
 

scorpion-ds

Новичок
Насчет получения дочерних элементов, нашел опцию "fetch="EAGER"" для сущности, но она не решает проблемы, так как просто делает все запросы сразу, а не по мере необходимости, в итоге общие количество запросов выпростает с 7 до более 50.
 
Сверху