与更新的实体相关的所有实体的Symfony2 FOSElasticaBundle更新索引

Ben*_*ton 13 doctrine symfony symfony-2.4 foselasticabundle

我在我的项目中使用FOSElasticaBundle和Doctrine,我的代码用于使用Doctrine生命周期事件进行选择性索引更新.我遇到的问题是我是否单独更新相关实体.

例如,一个人可能通过多种关系与公司相关.如果我直接通过公司实体更新公司名称,那么与公司相关的人员的索引将过时,并且仍与公司的旧名称相关.

关于如何处理这个我有点迷失,有人有什么建议吗?我是否必须依赖计划的索引更新并同时处理不准确的索引数据,或者我是否可以调用与已更新的实体相关的实体的更新.

我依靠JMSSerializer组来建立映射.我很欣赏这可能不是长期做事的最佳方式.

小智 11

我遇到了同样的问题.看来我的安装(Symfony 2.5.4和FOSElastica 3.0.4)与你的安装有很大不同.因此,使代码工作存在一些问题.我正在发布我的解决方案,因为它可能对其他开发人员有用.

监听器不在FOS\ElasticaBundle\Doctrine\ORM \中,而是在FOS\ElasticaBundle\Doctrine中.所以你必须使用那个.此外,我不得不使用Doctrine\Common\EventArgs而不是Doctrine\ORM\Event\LifecycleEventArgs,因为否则我自己的postUpdate方法与BaseListener中的方法不兼容.

在我的应用程序中,课程(研讨会)可以有很多会话,但在这个项目中,elastica将只使用这些会话.该应用程序需要了解与课程相关的课程的一些细节.所以,这是我的代码:

在config.yml中,我的elastica bundle配置如下所示:

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        courses:
            index_name: courses
            types:
                session:
                    mappings:
                        id: ~
                        name: ~
                        course:
                            type: "nested"
                            properties:
                                id: ~
                                name: ~
Run Code Online (Sandbox Code Playgroud)

再进一步,仍然在config.yml

services:
     # some other services here

     fos_elastica.listener.courses.course:
         class: XXX\CourseBundle\EventListener\ElasticaCourseListener
         arguments:
             - @fos_elastica.object_persister.courses.course
             - ['postPersist', 'postUpdate', 'preRemove']
             - @fos_elastica.indexable
         calls:
             - [ setContainer, ['@service_container', @fos_elastica.object_persister.courses.session ] ]
         tags:
             - { name: 'doctrine.event_subscriber' }
Run Code Online (Sandbox Code Playgroud)

我自己的监听器(XXX\CourseBundle\EventListener\ElasticaCourseListener)然后看起来像这样:

<?php

namespace XXX\CourseBundle\EventListener;

use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as BaseListener;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use Symfony\Component\DependencyInjection\ContainerInterface;
use XXX\CourseBundle\Entity\Course;

class ElasticaCourseListener extends BaseListener
{
    private $container;
    private $objectPersisterSession;

    public function setContainer(ContainerInterface $container, ObjectPersister $objectPersisterSession)
    {
        $this->container = $container;
        $this->objectPersisterSession = $objectPersisterSession;
    }

    public function postUpdate(EventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Course) {
            $this->scheduledForUpdate[] = $entity;
            foreach ($entity->getSessions() as $session) {
                $this->objectPersisterSession->replaceOne($session);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我更新课程时,它将作为ElasticSearch中的嵌套对象进行更新;-)


Ben*_*ton 4

我想我已经在此页面上找到了解决方案https://groups.google.com/forum/#!topic/elastica-php-client/WTONX-zBTI4 谢谢 Cassiano

基本上,您需要扩展 FOS\ElasticaBundle\Doctrine\ORM\Listener,以便您可以查找相关实体,然后也更新它们的索引。

class CompanyListener extends BaseListener
{

    /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
    private $container;

    public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container) {
        $this->container = $container;
    }

    protected function initialiseJob() {
        $this->objectPersisterJob = $this->container->get('fos_elastica.object_persister.application.job');
        $this->em = $this->container->get('doctrine')->getEntityManager(); //maybe move this to postUpdate function so it can be used for all
    }

    /**
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $eventArgs
     */
    public function postUpdate(LifecycleEventArgs $eventArgs)
    {
        /** @var $entity Story */
        $entity = $eventArgs->getEntity();

        if ($entity instanceof $this->objectClass) {
            if ($this->isObjectIndexable($entity)) {
                $this->objectPersister->replaceOne($entity);
                $this->initialiseJob();
                foreach ($entity->getJobOpenings() as $job) {
                    $this->objectPersisterJob->replaceOne($job);
                }
            } else {
                $this->scheduleForRemoval($entity, $eventArgs->getEntityManager());
                $this->removeIfScheduled($entity);
            }
        }
    }

    public function preRemove(\Doctrine\Common\EventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();

        if ($entity instanceof $this->objectClass) {

            $this->scheduleForDeletion($entity);
            $this->initialiseJob();
            foreach ($entity->getJobOpenings() as $job) {
                $this->objectPersisterJob->replaceOne($job);
            }
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

以及您的服务定义如下

fos_elastica.listener.application.company:
    class: 'xxx\RMSBundle\EventListener\CompanyListener'
    arguments:
        - '@fos_elastica.object_persister.application.company'
        - 'xxx\RMSBundle\Entity\Company'
        - ['postPersist', 'postUpdate', 'postRemove', 'preRemove']
        - id
    calls:
        - [ setContainer, [ '@service_container' ] ]
    tags:
        - { name: 'doctrine.event_subscriber' }
Run Code Online (Sandbox Code Playgroud)

这将更新两者的索引:-)