zoopcommerce / shard

Add new behaviours to Doctrine Mongo ODM Documents
MIT License
4 stars 1 forks source link

EmbedMany #54

Open joshystuart opened 10 years ago

joshystuart commented 10 years ago

Currently EmbedMany fails using a discriminatorMap here: https://github.com/zoopcommerce/shard/blob/master/lib/Zoop/Shard/ODMCore/PreLoadSubscriber.php#L55

See doctrine docs for allowed attributes: http://doctrine-mongodb-odm.readthedocs.org/en/latest/reference/annotations-reference.html#embedmany

superdweebie commented 10 years ago

The preLoadSubscriber is there so that access control gets honoured for embedded documents. Here's what needs to be done. When using a discriminator map, target document isn't set, which is why the code is failing. Need to add a new if to first check for a discriminiator map - if it exisists, then use it, if not, then use the target document. Something like this should work:

if (isset($mapping['discriminatorField'])) {
    $targetMetadata = $documentManager->getClassMetadata($mapping['discriminatorMap'][$eventArgs->getData[$mapping['discriminatorField']]]);
} else {
    $targetMetadata = $documentManager->getClassMetadata($mapping['targetDocument']);
}

:)

joshystuart commented 10 years ago

Thanks for the advice :+1:

I wasn't entirely sure how to approach the $mapping['discriminatorMap'][$eventArgs->getData[$mapping['discriminatorField']]] section.

superdweebie commented 10 years ago

$eventArgs->getData contains the raw data from the database, before it has been hydrated into a document.

Actually, I just realised I made a mistake. Try this:

if (isset($mapping['discriminatorField'])) {
    $targetMetadata = $documentManager->getClassMetadata(
        $mapping['discriminatorMap'][$eventArgs->getData[$field][$mapping['discriminatorField']]]
    );
} else {
    $targetMetadata = $documentManager->getClassMetadata($mapping['targetDocument']);
}

Or the long version of the important bit:

$unhydratedEmbeddedDoc = $eventArgs->getData[$field];
$discriminatorFieldValue = $unhydratedEmbeddedDoc[$mapping['discriminatorField']];
$embeddedClassName = $mapping['discriminatorMap'][$discriminatorFieldValue];
$targetMetadata = $documentManager->getClassMetadata($embeddedClassName);
joshystuart commented 10 years ago

Unfortunately it's a little more complicated than that.

If you have something like:

/**
     * @ODM\EmbedMany(
     *   discriminatorMap={
     *     "Artist"="Artist",
     *     "SongWriter"="SongWriter"
     *   }
     * ) 
     */
    protected $songWriters = [];

I think we need to loop through each item within the field and check against it's discriminatorFieldValue.

I'm going to submit a PR soon. It's a little messy so I'd like to get your thoughts.