Symfony2 FOSElasticaBundle update index for all entities related to the entity updated

前端 未结 7 1509
無奈伤痛
無奈伤痛 2020-12-30 06:07

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

7条回答
  •  半阙折子戏
    2020-12-30 06:28

    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)

提交回复
热议问题