Search code examples
phpinheritancedoctrine-ormdoctrine-odmbidirectional

Doctrine ODM bi-direction reference with inheritance


I have this problem: I have several documents that extend some base document. All of these documents have sort of note feature meaning that users can add notes to them. I thus have Note document that is stored in separate collection (it needs to be searchable and cannot be embedded) and have owner property that references the document the note belongs to. I have trouble modelling this with doctrine:

<?php

/** @ODM\MappedSuperclass */
abstract class Base {
    /** @ODM\Id */
    public $id;

    /** @ODM\ReferenceMany(targetDocument="Note", mappedBy="owner") */
    public $notes;
}


/** @ODM\Document */
class MyDocument extends Base {
    /** @ODM\String */
    public $name;
}


/** @ODM\Document */
class Note {
    /** @ODM\Id */
    public $id;

    /** @ODM\ReferenceOne(targetDocument="Base", inversedBy="notes") */
    public $owner;

    /** @ODM\String */
    public $text;
}

$mdoc = new MyDocument;
$note = new Note;

$mdoc->name = 'foo';
$note->text = 'bar';

$mdoc->notes[] = $note;
$note->owner = $mdoc;

$dm->persist($mdoc);
$dm->persist($note);

$dm->flush();   

$dm->clear();

$note2 = $dm->find(Note::class, $note->id);
echo $note2->owner->name;

And I get the: Notice: Undefined property: Proxies__CG__\Base::$name. In other instances I got: The "Proxies__CG__\Base" document with identifier "XXX" could not be found.

It obviously tries to load the Base class instead of MyDocument. How to force it to load the correct class? I tried setting the Base as MappedSuperclass, setting discriminator field, omitting targetDocument etc. And nothing works as expected and ends with different errors/wrong behaviors.

Is this even possible?

Possibly related:

Note: none of them helped really or I missed something.


Solution

  • You're missing a discriminator definition for the base class:

    /**
     * @ODM\MappedSuperclass
     * @ODM\InheritanceType("COLLECTION_PER_CLASS")
     * @ODM\DiscriminatorField("type")
     * @ODM\DiscriminatorMap({
     *     "document"=MyDocument::class
     * })
     */
    abstract class Base {
        // ...
    }
    

    Once you have that, it should work as expected. Note that the inheritance type can also be SINGLE_COLLECTION, depending on whether you want to store the documents in the same or in different collections.