Description
Q | A |
---|---|
Version | 2.1.0 |
Support Question
tl;dr
When using targetDocument
and discriminatorMap
annotation property for EmbedMany
(I believe EmbedOne
as well) embedded documents do not save discriminator property.
I believe it should be mentioned in the docs that those two should not be mixed.
If possible I would either allow targetDocument
to coexist with discriminatorMap
as a "sanity check" when document passed is expected to be a specific class / interface.
Otherwise, I would throw an exception if they are used together.
Context:
I was extending an existing document to include a new type of embedded document with new properties. I had a document looking like this:
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
* @ODM\Document
*/
class Order
{
/**
* @ODM\EmbedMany(targetDocument=LegacyClass::class)
*/
private $embedded;
}
then I wanted to introduce another possible target document:
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
* @ODM\Document
*/
class Order
{
/**
* @ODM\EmbedMany(
* targetDocument=AbstractClass::class),
* strategy="atomicSetArray",
* discriminatorField="type",
* discriminatorMap={
* "legacy"=LegacyClass::class,
* "statistic_aggregate"=NewClass::class,
* },
* defaultDiscriminatorValue="legacy",
*/
private $embedded;
}
However, this resulted in type
property to never be set.
While documents inserted into this embedded collection were NewClass
instances and have it's property, when trying to read ODM was not finding type
property and tried to instantiate LegacyClass
.
Therefore I think that docs should explicitly warn about mixing those two annotations (targetDocument
& discriminatorMap
).
EDIT: A test that shown this misbehaving in my application:
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class OrderTest extends KernelTestCase
{
public function testEmbeddedDocumentsWorkCorrectly(): void
{
self::bootKernel();
$dm = self::$container->get('doctrine_mongodb.odm.default_document_manager');
$order = new Order();
$order->addClass(new NewClass());
$order->addClass(new LegacyClass());
$dm->persist($order);
$dm->flush();
$id = $order->getId();
$dm->clear();
/** @var Order $order */
$order = $dm->find(Order::class, $id);
[ $reference, $legacyReference ] = $order->getClasses()->toArray();
$this->assertInstanceOf(NewClass::class, $reference);
$this->assertInstanceOf(LegacyClass::class, $legacyReference);
}
}