1

According to the Doctrine 2 docs here you can create a hierarchy of entities using a class with self-reference one-to-many relationship. I want to be able to query all categories with all its related children.

At this moment when I dump from the controller the query returns 'uninitialized': #collection: ArrayCollection -elements: [].

I don't know how to adjust the QueryBuilder to hydrate the children.

Code inside the CategoryRepository:

public function retrieveHydratedCategories()
{
    return $this->createQueryBuilder('c')
                ->select('c, p, b')
                ->leftJoin('c.products', 'p')
                ->leftJoin('p.brand', 'b')
                ->Where("c.isActive = 1")
                ->getQuery()
                ->execute();
}

My Category entity:

<?php
// src/Entity/Category.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;


/**
 * @ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
 * @ORM\Table(name="categories")
 */
class Category
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=25)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=64)
     */
    private $brand;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $image;

    /**
     * One ProductCategory has Many ProductCategories.
     * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
     */
    private $children;

    /**
     * Many ProductCategories have One ProductCategory.
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
     */
    private $parent;

    /**
     * @ORM\Column(name="is_active", type="boolean")
     */
    private $isActive;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category")
     */
    private $products;

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

    /**
     * @return Collection|Product[]
     */
    public function getProducts()
    {
        return $this->products;
    }
    public function getChildren()
    {
        return $this->children;
    }
    public function getParent()
    {
        return $this->parent;
    }
    public function getName()
    {
        return $this->name;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getImage()
    {
        return $this->image;
    }

     public function setName($name)
    {
        $this->name = $name;
    }
   public function addChildren (Category $children)
   {
       $this->children[] = $children;

       return $this;
   }
    public function setIsActive($isActive)
    {
        $this->isActive = $isActive;
    }

    public function getBrand()
    {
        return $this->brand;
    }
}
Xenioz
  • 49
  • 2
  • 12

1 Answers1

3

Self-referencing One-To-Many associations are no different than regular One-To-Many associations when it comes to collection hydration. If you wish to retrieve the direct children of your categories, you will have to add another join to your current query. Something like:

public function retrieveHydratedCategories()
{
    $qb = $this->createQueryBuilder('c');
    // your other joins and conditions ...
    $qb->leftJoin('c.children', 'children')->addSelect('children');

    return $qb->getQuery()->getResult();
}

That being said, this works only if you have one level of depth. If you wish to retrieve the children of the children, you will either have to add another join (see this post) or generate your tree of categories from a flat result set as discussed here.

It goes the same for the products association of the children. The corresponding collections won't be hydrated unless you add a specific join in your query targeting the products of the children (well it might be hydrated if a child is also a parent retrieved in the main result set...).

Alan T.
  • 1,382
  • 1
  • 7
  • 14