Reputation: 619
I'm getting the following critical error on my page
The "WildkatProxy\DocumentsTagProxy" document with identifier "4e90eede17bc2ec68c000001" could not be found.
I'm assuming this is because the Documents Tag Proxy has been deleted from another action, and so the reference is no longer valid. I now want to delete the stale reference to this object, but silently. (As this could happen in a lot of other situations too) Is there anyway I can do a "reverse cascade" on all objects referencing the deleted object when the object is deleted?
What are best practices for accomplishing this?
Thanks Andy
Upvotes: 4
Views: 2078
Reputation: 3573
I assume you have two collections, ArticleTag and Article in which articles have references to article tags. If you want to delete tag references from articles when a tag is removed you can implement an event listener.
Create a class:
namespace Foo\BarBundle\EventListener;
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
use Foo\BarBundle\Document\Article;
class ArticleTagRemovalListener
{
public function preRemove(LifecycleEventArgs $args)
{
$document = $args->getDocument();
if ($document instanceof Article) {
// Remove tag from all articles
$args
->getDocumentManager()
->getRepository('FooBarBundle:Article')
->removeTag($document);
}
}
}
And register this class in your services.yml
or xml file:
foo_bar.listener.tag_removal:
class: Foo\BarBundle\EventListener\ArticleTagRemovalListener
tags:
- { name: doctrine_mongodb.odm.event_listener, event: preRemove }
Next in the custom repository class of your Article add the following method:
public function removeTag($tag)
{
return $this
->createQueryBuilder()
->update()
->field('tags')->pull($tag)
->multiple(true)
->getQuery()
->execute();
}
This will remove the tag from all available articles before deleting it. If you want to cascade the delete operation to all article documents. (Thus, remove all articles with a particular tag when that tag is removed, use the following repository method.)
public function purgeByTag($tag)
{
$result = $this
->createQueryBuilder()
->remove()
->field('tags')->equals($tag)
->getQuery()
->execute();
return $result['n'];
}
Update the ArticleTagRemovalListener to call this method and done!
Upvotes: 1
Reputation: 561
By default Doctrine will not cascade any UnitOfWork operations to referenced documents so if wish to have this functionality you must explicitly enable it
You can enable it on any field with either 'remove' or 'detach' depending on the behavior you want.
@ReferenceOne(targetDocument="Profile", cascade={"detach"})
Upvotes: 0