Eğer FOSElasticaBundle kullanıyorsanız, listener seçeneğinin varsayılan değerinin, veritabanındaki bir object üzerinde yapılan değişikliklerden sonra elasticsearch listenerin indexi yenilemesi için ayarlandığını bilirsiniz. Bu ayar config dosyasında listener: ~ olarak belirtilmiştir. Bilmeniz gereken, eğer one to many ilişkili bir index kullanıyorsanız, bu işlem sadece ana objeyi yeniler ve çocuk olan objeye dokunmaz. Bu problemi aşağıdaki örnek ile ortadan kaldırabilirsiniz.

Bu örneğimizde elimizde "Post" ve "Comment" (1-to-n) objeleri var. Objeler üzerinde ekleme, yenileme ve silme işlemlerini yapacağız ve arka planda ise event listener ile elasticsearch indexini yenileyeceğiz.

Not: Size daha uzun olan sebscriber versiyonunu kullanmanız yerine, bu versiyonu kullanmanızı tavsiye ederim.


Konfigürasyon


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: ~

PostService


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


Bazı işlemlerin aslında nasıl yapıldığını görmek isterseniz vendor/friendsofsymfony/elastica-bundle/Doctrine/Listener.php dosyasını okumanızı tavsiye ederim.


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 }