Hello everyone!

We have been investing plenty of personal time and energy for many years to share our knowledge with you all. However, we now need your help to keep this blog running. All you have to do is just click one of the adverts on the site, otherwise it will sadly be taken down due to hosting etc. costs. Thank you.

Default listener settings of FOSElasticaBundle is set to automatically update elasticsearch index in real time when an object is added, updated or removed. It is set as listener: ~ in the config file. If you want to manually update elasticsearch index then you can use example below.

In this example, there is a 'Post' entity and we will do insert, update and delete operations with doctrine then manually update elasticsearch index with an event listener.

Note: I suggest you to use this version rather than longer event subscriber version that I have in this blog.


Config


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
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);
}

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;
}
}

PostIndexListener


You should also study vendor/friendsofsymfony/elastica-bundle/Doctrine/Listener.php class to see how things actually work.


namespace Application\SearchBundle\Listener;

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;
}
}
}
}

public function postUpdate(LifecycleEventArgs $args)
{
$entity = $args->getObject();

if ($entity instanceof Post) {
if ($this->objectPersister->handlesObject($entity)) {
if ($this->isObjectIndexable($entity)) {
$this->scheduledForUpdate[] = $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;
}
}
}
}

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 }