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 }