Search code examples
phpmysqldoctrine-ormdoctrinezend-framework2

Parent Child Relationship With A Single Entity In Doctrine 2


I have database table that looks like this:

+----+--------+--------------------+
| id | parent | description        |
+----+--------+--------------------+
|  1 | null   | P Cat 1            |
|  2 | 1      | Child 1 of P Cat 1 |
|  3 | 1      | Child 2 of P Cat 1 |
|  4 | null   | P Cat 2            |
|  5 | 4      | Child 1 of P Cat 2 |
|  6 | 4      | Child 2 of P Cat 2 |
+----+--------+--------------------+

How can I create a doctrine 2 entity that has these columns, but I need the parent column to reference the "id" column as a parent. Of course, a parent record has a null "parent" column value.

So fair I have

<?php
namespace MyNamespace;
use Doctrine\ORM\Mapping AS ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * @ORM\Entity
 * @ORM\Table(name="category")
 **/
class Category
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * Creates a parent / child relationship on this entity.
     *
     * @ORM\ManyToOne(targetEntity="MyNamespace\Category",inversedBy="id")
     * @ORM\JoinColumn(name="FK_parent_id", referencedColumnName="id", nullable=true)
     */
    protected $parent = null;

    /**
     * @ORM\Column(type="string", name="description", length=250)
     *
     * @var string
     */
    protected $description;

    /**
     * Gets the Primary key value.
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Sets another category ID as the parent of this category.
     */
    public function setParent(Category $category)
    {
        $this->parent = $category;
    }

    /**
     * Clears the parent id and makes it null.
     */
    public function clearParent()
    {
        $this->parent = null;
    }

    /**
     * Sets the description.
     *
     * @param string $description
     * @return Category
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }

    /**
     * Gets the description value.
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }
}

Needless to say, this doesn't appear to work. The questions are:

  1. The setParent() method doesn't appear to work as expected when another entity is added as a parent.
  2. I need a getChildren() method on this entity. How can I achieve that?

Solution

  • This should work:

    <?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;
        }
    
    }