Last active
June 12, 2016 13:49
-
-
Save veewee/9787055 to your computer and use it in GitHub Desktop.
Doctrine MongoDB Event Subscriber to Remove DBRefs of Deleted Documents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Interface ReferencedDocumentInterface | |
* | |
*/ | |
interface ReferencedDocumentInterface | |
{ | |
/** | |
* @return mixed | |
*/ | |
public function getId(); | |
/** | |
* Returns an array with the entity name as key and the field property as value. | |
* | |
* @return array | |
*/ | |
public function getReferingValueFields(); | |
/** | |
* Returns an array with the entity name as key and the field property as value. | |
* | |
* @return array | |
*/ | |
public function getReferingCollectionFields(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Doctrine\Common\EventSubscriber; | |
use Doctrine\ODM\MongoDB\DocumentManager; | |
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs; | |
use Doctrine\ODM\MongoDB\Events; | |
/** | |
* Class RemoveReferencesListener | |
* | |
*/ | |
class RemoveReferencesListener | |
implements EventSubscriber | |
{ | |
/** | |
* @param LifecycleEventArgs $args | |
*/ | |
public function preRemove(LifecycleEventArgs $args) | |
{ | |
$document = $args->getDocument(); | |
$documentManager = $args->getDocumentManager(); | |
if (!($document instanceof ReferencedDocumentInterface)) { | |
return; | |
} | |
foreach ($document->getReferingValueFields() as $targetDocument => $field) { | |
$fields = is_array($field) ? $field : [$field]; | |
foreach ($fields as $key) { | |
$this->removeSingleValuedReference($documentManager, $document, $targetDocument, $key); | |
} | |
} | |
foreach ($document->getReferingCollectionFields() as $targetDocument => $field) { | |
$fields = is_array($field) ? $field : [$field]; | |
foreach ($fields as $key) { | |
$this->removeCollectionValuedReference($documentManager, $document, $targetDocument, $key); | |
} | |
} | |
} | |
/** | |
* @param DocumentManager $documentManager | |
* @param ReferencedDocumentInterface $document | |
* @param $targetDocument | |
* @param $field | |
*/ | |
protected function removeSingleValuedReference($documentManager, $document, $targetDocument, $field) | |
{ | |
$id = $document->getId(); | |
$searchField = $this->parseSearchField($field); | |
$queryBuilder = $documentManager->createQueryBuilder($targetDocument); | |
$queryBuilder | |
->update() | |
->multiple(true) | |
->field($field)->set(null) | |
->field($searchField)->equals($id); | |
$query = $queryBuilder->getQuery(); | |
$query->execute(); | |
} | |
/** | |
* @param DocumentManager $documentManager | |
* @param ReferencedDocumentInterface $document | |
* @param $targetDocument | |
* @param $field | |
*/ | |
protected function removeCollectionValuedReference($documentManager, $document, $targetDocument, $field) | |
{ | |
$id = $document->getId(); | |
$searchField = $this->parseSearchField($field); | |
list($field, $matcher) = explode('.', $searchField, 2); | |
$matcher = $matcher ? $matcher : '$id'; | |
$queryBuilder = $documentManager->createQueryBuilder($targetDocument); | |
$queryBuilder | |
->update() | |
->multiple(true) | |
->field($field)->pull([ | |
$matcher => $id, | |
]) | |
->field($searchField)->equals($id); | |
$query = $queryBuilder->getQuery(); | |
$query->execute(); | |
} | |
/** | |
* This method makes it possible to remove references in embedded collections. | |
* E.g.: | |
* Embedded reference field: items.$.asset will set items.$.asset to null | |
* Embedded reference collection: items.$.assets will pull the asset out of the selected embedded collection | |
* | |
* @param $field | |
* | |
* @return string | |
*/ | |
protected function parseSearchField($field) | |
{ | |
return str_replace('.$.', '.', $field) . '.$id'; | |
} | |
/** | |
* Returns an array of events this subscriber wants to listen to. | |
* | |
* @return array | |
*/ | |
public function getSubscribedEvents() | |
{ | |
return [Events::preRemove]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment