在symfony中创建一个自定义监听器的代码示例

101 阅读2分钟

FOSElasticaBundle的默认listener ,设置为当一个对象被添加、更新或删除时,自动实时更新弹性搜索索引。它在配置文件中被设置为listener: ~ 。然而,这只适用于父对象,所以如果你有一对多的关系,那么子对象将永远不会被索引。这个例子解决了这个问题。

在这个例子中,有'Post'和'Comment'两个实体(1对n),我们将对这两个对象单独进行插入、更新和删除操作,也会和教义一起,然后用事件监听器手动更新elasticsearch索引。

注意:我建议你使用这个版本,而不是我在这个博客中的长事件订阅者版本。

配置

fos_elastica:
    clients:
        default: { host: 127.0.0.1, port: 9200 }
    indexes:
        post_index:
            client: default
            index_name: post_dev
            types:
                post:
                    mappings:
                        id:
                            type: integer
                            index: not_analyzed
                        title:
                            type: string
                            analyzer: english
                        year:
                            type: integer
                            index: not_analyzed
                        price:
                            type: double
                            index: not_analyzed
                        is_published:
                            type: boolean
                            index: not_analyzed
                        comment:
                            type: object
                            properties:
                                id:
                                    type: integer
                                    index: not_analyzed
                                message:
                                    type: string
                    persistence:
                        driver: orm
                        model: Application\SearchBundle\Entity\Post
                        finder: ~
                        provider: ~
                        listener: ~

帖服务

namespace Application\SearchBundle\Service;
 
........
........
 
class PostDatabaseService
{
    ........
    ........
 
    public function createPost()
    {
        $post = new Post();
        $post->setTitle('inanzzz');
        $post->setYear(1999);
        $post->setPrice(6.99);
        $post->setIsPublished(true);
 
        $this->entityManager->persist($post);
        $this->entityManager->flush();
 
        return sprintf('create-post ID: %s', $post->getId());
    }
 
    public function updatePost($id)
    {
        /** @var Post $post */
        $post = $this->findPost($id);
        $post->setTitle('inanzzz inanzzz');
 
        $this->entityManager->flush();
 
        return sprintf('update-post ID: %s', $id);
    }
 
    public function deletePost($id)
    {
        /** @var Post $post */
        $post = $this->findPost($id);
 
        $this->entityManager->remove($post);
        $this->entityManager->flush();
 
        return sprintf('delete-post ID: %s', $id);
    }
 
    public function createChild($id)
    {
        /** @var Post $post */
        $post = $this->findPost($id);
 
        $comment = new Comment();
        $comment->setMessage('inanzzz');
        $comment->setPost($post);
 
        $this->entityManager->persist($comment);
        $this->entityManager->flush();
 
        return sprintf('create-child ID: %s', $comment->getId());
    }
 
    public function updateChild($id)
    {
        /** @var Comment $comment */
        $comment = $this->findComment($id);
        $comment->setMessage('inanzzz inanzzz');
 
        $this->entityManager->flush();
 
        return sprintf('update-child ID: %s', $id);
    }
 
    public function deleteChild($id)
    {
        /** @var Comment $comment */
        $comment = $this->findComment($id);
 
        $this->entityManager->remove($comment);
        $this->entityManager->flush();
 
        return sprintf('delete-child ID: %s', $id);
    }
 
    public function createPostChild()
    {
        $post = new Post();
        $post->setTitle('inanzzz');
        $post->setYear(1999);
        $post->setPrice(6.99);
        $post->setIsPublished(true);
 
        $comment = new Comment();
        $comment->setMessage('inanzzz');
        $comment->setPost($post);
 
        $this->entityManager->persist($post);
        $this->entityManager->persist($comment);
        $this->entityManager->flush();
 
        return sprintf('create-post-child ID-ID: %s-%s', $post->getId(), $comment->getId());
    }
 
    public function updatePostChild($pid, $cid)
    {
        /** @var Post $post */
        $post = $this->findPost($pid);
        $post->setTitle('inanzzz inanzzz');
 
        /** @var Comment $comment */
        $comment = $this->findComment($cid);
        $comment->setMessage('inanzzz inanzzz');
 
        $this->entityManager->flush();
 
        return sprintf('update-post-child ID-ID: %s-%s', $pid, $cid);
    }
 
    private function findPost($id)
    {
        $post = $this->postRepository->findOneById($id);
        if (!$post instanceof Post) {
            throw new EntityNotFoundException(sprintf('Post [%s] cannot be found.', $id));
        }
 
        return $post;
    }
 
    private function findComment($id)
    {
        $comment = $this->commentRepository->findOneById($id);
        if (!$comment instanceof Comment) {
            throw new EntityNotFoundException(sprintf('Comment [%s] cannot be found.', $id));
        }
 
        return $comment;
    }
}

PostIndexListener

你也应该研究一下vendor/friendsofsymfony/elastica-bundle/Doctrine/Listener.php 类,看看事情到底是如何运作的:

namespace Application\SearchBundle\Listener;
 
use Application\SearchBundle\Entity\Comment;
use Application\SearchBundle\Entity\Post;
use Doctrine\Common\EventSubscriber;
use FOS\ElasticaBundle\Doctrine\Listener;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use FOS\ElasticaBundle\Provider\IndexableInterface;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\PropertyAccess\PropertyAccess;
 
class PostIndexListener extends Listener implements EventSubscriber
{
    protected $propertyAccessor;
 
    private $indexable;
    private $config;
 
    public function __construct(
        ObjectPersisterInterface $postPersister,
        IndexableInterface $indexable,
        array $config
    ) {
        $this->objectPersister = $postPersister;
        $this->indexable = $indexable;
        $this->config = $config;
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
    }
 
    public function getSubscribedEvents()
    {
        return ['postPersist', 'postUpdate', 'preRemove', 'preFlush', 'postFlush'];
    }
 
    public function postPersist(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getObject();
 
        if ($entity instanceof Post) {
            if ($this->objectPersister->handlesObject($entity)) {
                if ($this->isObjectIndexable($entity)) {
                    $this->scheduledForInsertion[] = $entity;
                }
            }
        }
 
        $this->handleChild($entity);
    }
 
    public function postUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
 
        if ($entity instanceof Post) {
            if ($this->objectPersister->handlesObject($entity)) {
                if ($this->isObjectIndexable($entity)) {
                    $this->scheduledForUpdate[] = $entity;
                }
            }
        }
 
        $this->handleChild($entity);
    }
 
    public function preRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
 
        if ($entity instanceof Post) {
            if ($this->objectPersister->handlesObject($entity)) {
                if ($identifierValue = $this->propertyAccessor->getValue($entity, $this->config['identifier'])) {
                    $this->scheduledForDeletion[] = $identifierValue;
                }
            }
        }
 
        $this->handleChild($entity, false);
    }
 
    private function handleChild($entity, $add = true)
    {
        if ($entity instanceof Comment) {
            $post = $entity->getPost();
            $post->removeComment($entity);
            if ($add) {
                $post->addComment($entity);
            }
            if ($this->objectPersister->handlesObject($post)) {
                if ($this->isObjectIndexable($post)) {
                    $this->scheduledForUpdate[] = $post;
                }
            }
        }
    }
 
    private function isObjectIndexable($object)
    {
        return $this->indexable->isObjectIndexable(
            $this->config['index'],
            $this->config['type'],
            $object
        );
    }
}

Services.yml

services:
    application_search.listener.post_index:
        class: Application\SearchBundle\Listener\PostIndexListener
        arguments:
            - @fos_elastica.object_persister.post_index.post
            - @fos_elastica.indexable
            - { index: post_index, type: post, identifier: id }
        tags:
            - { name: doctrine.event_subscriber }