I\'m using FOSElasticaBundle and Doctrine in my project, and my code works for the selective index update using the Doctrine lifecycle events. The issue I come up against is
I'm using Symphony 3 and FOSElasticaBundle 3.2 and I did things a bit differently. After reviewing the code given in the other answers, which helped a lot, I've decided not to extend the default listener. Instead I let it do its thing and I just added my own listener.
I have some Categories (1) which can have multiple (many-to-many) Subjects (2) which can have multiple (one-to-many) Posts (3). The Posts are the entities being saved in Elasticsearch with infos on their respective Subject and its own Categories.
Like so:
fos_elastica:
#...
indexes:
my_index:
#...
types:
post: # (3)
mappings:
field_one: ~
# ... Other fields
subject: # (2)
type: "object"
properties:
subject_field_one: ~
# ... Other fields
categories: # (1)
type: "nested"
properties:
category_field_one: ~
# ... Other fields
The service definition (app/config/services.yml)
services:
# ...
app.update_elastica_post.listener:
class: AppBundle\EventListener\UpdateElasticaPostListener
arguments: ['@service_container']
tags:
- { name: doctrine.event_listener, event: postUpdate }
And the listener AppBundle\EventListener\UpdateElasticaPostListener.php
namespace AppBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use AppBundle\Entity\Category;
use AppBundle\Entity\Subject;
class UpdateElasticaPostListener
{
private $container;
private $objectPersisterPost;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->objectPersisterPost = null;
}
/**
* @param \Doctrine\ORM\Event\LifecycleEventArgs $eventArgs
*/
public function postUpdate(LifecycleEventArgs $eventArgs)
{
$this->checkAndUpdate($eventArgs);
}
protected function checkAndUpdate(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof Category) {
foreach ($entity->getSubjects() as $subject) {
$this->updateSubjectPosts($subject);
}
} elseif ($entity instanceof Subject) {
$this->updateSubjectPosts($entity);
}
}
protected function updateSubjectPosts(Subject $subject)
{
$this->initPostPersister();
foreach ($subject->getPosts() as $post) {
$this->objectPersisterPost->replaceOne($post);
}
}
protected function initPostPersister()
{
if (null === $this->objectPersisterPost) {
// fos_elastica.object_persister..
$this->objectPersisterPost = $this->container->get('fos_elastica.object_persister.my_index.post');
}
}
}
And that's it! I didn't try it for the remove event and now that I think about it, maybe this solution wouldn't be the best one for it... but maybe it is...
Thanks a lot to @Ben Stinton and @maercky above.
I hope it helps! (this is my first answer around here so I hope I didn't screw up)