0

I am working on a custom ancestry-chain hydrator which hydrates Root entities (see entity excerpt below). It works quite well. The hydrator gets its entities from Doctrine and works on them. The hydrator then returns what it has worked as actual result.

So now the hydrator requires a property in the entity called leaves to store ancestors. I imagined the below property setup would work, and that I would get an empty initialized leaves property when Doctrine is bringing Root entities from the database to the hydrator, then the hydrator would just store in their leaves the objects it has determined to be ancestors for further processing.

The property has to be initialized with an empty Doctrine ArrayCollection (unmapped). So I added it and... nothing. It doesn't get initialized. Mapped associations collections however, work.

Is there some switch, declaration or standard one has to adhere to? Or what should I do to make Doctrine initialize it?

class Root
{
    ...

    /**
     * @var Collection
     */
    public Collection $leaves;

    /**
     * @ORM\OneToMany(targetEntity="Root", mappedBy="parent", fetch="EXTRA_LAZY", indexBy="id")
     */
    private Collection $children;

    /**
     * @throws Exception
     */
    public function __construct()
    {
        $this->leaves=new ArrayCollection(); <- no effect
        $this->children=new ArrayCollection(); <- is initialized
    }

    ...
}
John Miller
  • 527
  • 4
  • 15
  • 1
    You initialize in the constructor `$this->leaves` and it's not initialized later? Is it null? – Jared Farrish Dec 13 '22 at 13:24
  • @JaredFarrish Thanks for the edit and no, its not a nullable property. – John Miller Dec 13 '22 at 13:46
  • 1
    I don't follow. It's not initialized as an `ArrayCollection`, but it's not null? What is it? What does "make it work" mean? – Jared Farrish Dec 13 '22 at 13:50
  • @JaredFarrish I've corrected the question. It's about how to get Doctrine to initialize the property. On your fist question, the error thrown in hydrator when trying to access `leaves` is `Typed property Root::$leaves must not be accessed before initialization` – John Miller Dec 13 '22 at 14:05
  • 1
    I'm guessing you're accessing a proxy, something that isn't using the constructor. If you want Doctrine to initialize it, I believe you'd have to have either an attribute or annotation, something that indicates what Doctrine should do with it. – Jared Farrish Dec 13 '22 at 14:15
  • See: https://stackoverflow.com/questions/4923817/what-is-a-proxy-in-doctrine-2/17787070#17787070 and https://www.doctrine-project.org/projects/doctrine-orm/en/2.13/reference/advanced-configuration.html#proxy-objects – Jared Farrish Dec 13 '22 at 14:18
  • @JaredFarrish Oh my. You're right it's using a Proxy of the entity stored in a file cache. I've read through the two articles and turns out, proxies are actually good stuff. They work transparently, entities shouldn't care and the efficiency is tremendous. Also I've given the hydrator another closer look and found that it actually adds to the leaves, but leaves come in uninitialized. Counting empty leaves results in the error like so `$root->leaves->count()`. Will manually initialize empty-leaved roots for a smooth flow. Thanks a lot. Incase there's another non-hacky way, please let me know. – John Miller Dec 13 '22 at 14:37
  • 1
    You can access through a getter and make sure it's initialized. – Jared Farrish Dec 13 '22 at 14:44
  • @JaredFarrish Thanks Jared and I've just done that in the `addLeaf(Root $root)` method with a `->leaves??=new ArrayCollection()`; and that should hold. I wouldn't want Doctrine to mess up with the proxies since they only work to provide what's needed. – John Miller Dec 13 '22 at 15:08

0 Answers0