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

前端 未结 7 1499
無奈伤痛
無奈伤痛 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:32

    With the BC Break #729 of FosElastica 3.1.0, things have changed and the code above wasn't working :

    BC BREAK: Removed Doctrine\Listener#getSubscribedEvents. The container configuration now configures tags with the methods to call to avoid loading this class on every request where doctrine is active. #729
    

    For those who are trying to make it work with FOSElastica 3.1.X here is how I did manage to make a nested objected to be indexed into his parent into Elastic Search when persisting/updating/removing a nested entity :

    Define the service listener :

    fos_elastica.listener.entity.nested:
        class: XX\CoreBundle\EventListener\EventSubscriber\ElasticaNestedListener
        arguments:
            - @fos_elastica.object_persister.app.entityname
            - @fos_elastica.indexable
            - {"indexName" : "app", "typeName": "entityname"}
        tags:
            - { name: 'doctrine.event_subscriber' }
    

    Create the listener :

    config = array_merge(array(
                'identifier' => 'id',
            ), $config);
        $this->indexable = $indexable;
        $this->objectPersister = $objectPersister;
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
    
        if ($logger && $this->objectPersister instanceof ObjectPersister) {
            $this->objectPersister->setLogger($logger);
        }
    }
    
    
    
    /**
     * Looks for objects being updated that should be indexed or removed from the index.
     *
     * @param LifecycleEventArgs $eventArgs
     */
    public function postUpdate(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();
    
        if ($entity instanceof EntityName) {
    
            $question = $entity->getParent();
            if ($this->objectPersister->handlesObject($question)) {
                if ($this->isObjectIndexable($question)) {
                    $this->scheduledForUpdate[] = $question;
                } else {
                    // Delete if no longer indexable
                    $this->scheduleForDeletion($question);
                }
            }
        }
    
    
    }
    
    
    public function postPersist(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();
    
        if ($entity instanceof EntityName) {
            $question = $entity->getParent();
            if ($this->objectPersister->handlesObject($question)) {
                if ($this->isObjectIndexable($question)) {
                    $this->scheduledForUpdate[] = $question;
                } else {
                    // Delete if no longer indexable
                    $this->scheduleForDeletion($question);
                }
            }
        }
    
    
    }
    
    
    /**
     * Delete objects preRemove instead of postRemove so that we have access to the id.  Because this is called
     * preRemove, first check that the entity is managed by Doctrine.
     *
     * @param LifecycleEventArgs $eventArgs
     */
    public function preRemove(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();
    
        if ($this->objectPersister->handlesObject($entity)) {
            $this->scheduleForDeletion($entity);
        }
    }
    
    /**
     * Persist scheduled objects to ElasticSearch
     * After persisting, clear the scheduled queue to prevent multiple data updates when using multiple flush calls.
     */
    private function persistScheduled()
    {
        if (count($this->scheduledForInsertion)) {
            $this->objectPersister->insertMany($this->scheduledForInsertion);
            $this->scheduledForInsertion = array();
        }
        if (count($this->scheduledForUpdate)) {
            $this->objectPersister->replaceMany($this->scheduledForUpdate);
            $this->scheduledForUpdate = array();
        }
        if (count($this->scheduledForDeletion)) {
            $this->objectPersister->deleteManyByIdentifiers($this->scheduledForDeletion);
            $this->scheduledForDeletion = array();
        }
    }
    
    /**
     * Iterate through scheduled actions before flushing to emulate 2.x behavior.
     * Note that the ElasticSearch index will fall out of sync with the source
     * data in the event of a crash during flush.
     *
     * This method is only called in legacy configurations of the listener.
     *
     * @deprecated This method should only be called in applications that depend
     *             on the behaviour that entities are indexed regardless of if a
     *             flush is successful.
     */
    public function preFlush()
    {
        $this->persistScheduled();
    }
    
    /**
     * Iterating through scheduled actions *after* flushing ensures that the
     * ElasticSearch index will be affected only if the query is successful.
     */
    public function postFlush()
    {
        $this->persistScheduled();
    }
    
    /**
     * Record the specified identifier to delete. Do not need to entire object.
     *
     * @param object $object
     */
    private function scheduleForDeletion($object)
    {
        if ($identifierValue = $this->propertyAccessor->getValue($object, $this->config['identifier'])) {
            $this->scheduledForDeletion[] = $identifierValue;
        }
    }
    
    /**
     * Checks if the object is indexable or not.
     *
     * @param object $object
     *
     * @return bool
     */
    private function isObjectIndexable($object)
    {
        return $this->indexable->isObjectIndexable(
            $this->config['indexName'],
            $this->config['typeName'],
            $object
        );
    }
    }
    

    EntityName could be a Comment and getParent() could be the Article who owns this comment ...

    Hope this help !

提交回复
热议问题