[Listener] Allow conditional indexing based on callback method

Added optional is_indexable_callback config param to persistence. If this is a method on the entity, the listener will only process it if the method returns true. Also updated documentation.
This commit is contained in:
r1pp3rj4ck 2012-04-05 15:15:08 +02:00 committed by Jeremy Mikola
parent 3863b2dba8
commit 0f46f4b96d
7 changed files with 81 additions and 5 deletions

View file

@ -91,6 +91,7 @@ class Configuration
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers))
->end()
->end()
->scalarNode('is_indexable_callback')->defaultNull()->end()
->scalarNode('identifier')->defaultValue('id')->end()
->arrayNode('provider')
->children()
@ -166,6 +167,7 @@ class Configuration
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($this->supportedDrivers))
->end()
->end()
->scalarNode('is_indexable_callback')->defaultNull()->end()
->scalarNode('model')->end()
->scalarNode('repository')->end()
->scalarNode('identifier')->defaultValue('id')->end()

View file

@ -305,6 +305,7 @@ class FOQElasticaExtension extends Extension
$listenerDef->replaceArgument(0, new Reference($objectPersisterId));
$listenerDef->replaceArgument(1, $typeConfig['model']);
$listenerDef->replaceArgument(3, $typeConfig['identifier']);
$listenerDef->replaceArgument(4, $typeConfig['is_indexable_callback']);
$listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig));
switch ($typeConfig['driver']) {
case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break;

View file

@ -31,16 +31,19 @@ abstract class AbstractListener
protected $esIdentifierField;
protected $scheduledForRemoval;
protected $isIndexableCallback;
/**
* Constructor
**/
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id')
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id', $isIndexableCallback = null)
{
$this->objectPersister = $objectPersister;
$this->objectClass = $objectClass;
$this->events = $events;
$this->esIdentifierField = $esIdentifierField;
$this->scheduledForRemoval = array();
$this->isIndexableCallback = $isIndexableCallback;
}
/**

View file

@ -13,7 +13,18 @@ class Listener extends AbstractListener implements EventSubscriber
$document = $eventArgs->getDocument();
if ($document instanceof $this->objectClass) {
$this->objectPersister->insertOne($document);
if ($this->isIndexableCallback && !is_callable(array($document, $this->isIndexableCallback))) {
if (method_exists($document, $this->isIndexableCallback)) {
$exception = sprintf('The specified check method %s::%s is out of scope.', $this->objectClass, $this->isIndexableCallback);
} else {
$exception = sprintf('The specified check method %s::%s does not exist', $this->objectClass, $this->isIndexableCallback);
}
throw new \RuntimeException($exception);
}
if (($this->isIndexableCallback && call_user_func(array($document, $this->isIndexableCallback))) || !$this->isIndexableCallback) {
$this->objectPersister->insertOne($document);
}
}
}
@ -22,7 +33,22 @@ class Listener extends AbstractListener implements EventSubscriber
$document = $eventArgs->getDocument();
if ($document instanceof $this->objectClass) {
$this->objectPersister->replaceOne($document);
if ($this->isIndexableCallback && !is_callable(array($document, $this->isIndexableCallback))) {
if (method_exists($document, $this->isIndexableCallback)) {
$exception = sprintf('The specified check method %s::%s is out of scope.', $this->objectClass, $this->isIndexableCallback);
} else {
$exception = sprintf('The specified check method %s::%s does not exist', $this->objectClass, $this->isIndexableCallback);
}
throw new \RuntimeException($exception);
}
if (($this->isIndexableCallback && call_user_func(array($document, $this->isIndexableCallback))) || !$this->isIndexableCallback) {
$this->objectPersister->replaceOne($document);
} else {
$this->scheduleForRemoval($document, $eventArgs->getDocumentManager());
$this->removeIfScheduled($document);
}
}
}

View file

@ -13,7 +13,18 @@ class Listener extends AbstractListener implements EventSubscriber
$entity = $eventArgs->getEntity();
if ($entity instanceof $this->objectClass) {
$this->objectPersister->insertOne($entity);
if ($this->isIndexableCallback && !is_callable(array($entity, $this->isIndexableCallback))) {
if (method_exists($entity, $this->isIndexableCallback)) {
$exception = sprintf('The specified check method %s::%s is out of scope.', $this->objectClass, $this->isIndexableCallback);
} else {
$exception = sprintf('The specified check method %s::%s does not exist', $this->objectClass, $this->isIndexableCallback);
}
throw new \RuntimeException($exception);
}
if (($this->isIndexableCallback && call_user_func(array($entity, $this->isIndexableCallback))) || !$this->isIndexableCallback) {
$this->objectPersister->insertOne($entity);
}
}
}
@ -22,7 +33,22 @@ class Listener extends AbstractListener implements EventSubscriber
$entity = $eventArgs->getEntity();
if ($entity instanceof $this->objectClass) {
$this->objectPersister->replaceOne($entity);
if ($this->isIndexableCallback && !is_callable(array($entity, $this->isIndexableCallback))) {
if (method_exists($entity, $this->isIndexableCallback)) {
$exception = sprintf('The specified check method %s::%s is out of scope.', $this->objectClass, $this->isIndexableCallback);
} else {
$exception = sprintf('The specified check method %s::%s does not exist', $this->objectClass, $this->isIndexableCallback);
}
throw new \RuntimeException($exception);
}
if (($this->isIndexableCallback && call_user_func(array($entity, $this->isIndexableCallback))) || !$this->isIndexableCallback) {
$this->objectPersister->replaceOne($entity);
} else {
$this->scheduleForRemoval($entity, $eventArgs->getEntityManager());
$this->removeIfScheduled($entity);
}
}
}

View file

@ -477,6 +477,23 @@ You can also choose to only listen for some of the events:
> **Propel** doesn't support this feature yet.
### Checking an entity method for listener
If you use listeners to update your index, you may need to validate your entities before you put them to the
index (e.g. is the entity public). You can do this with the is_indexable_callback config param.
persistence:
listener:
is_indexable_callback: "isPublic"
This is optional, but if you set the is_indexable_callback and the entity has a method with the specified name, your
entities will go into the index only if the method returns true. If you update an entity and the update
listener is active, it will check the method again, and if it returns true, the entity will be removed from
the index. If it returns true, it will be updated in the index of course. Delete listener disregards the
is_indexable_callback.
> **Propel** doesn't support this feature yet.
### Advanced elasticsearch configuration
Any setting can be specified when declaring a type. For example, to enable a custom analyzer, you could write:

View file

@ -18,6 +18,7 @@
<argument /> <!-- model -->
<argument type="collection" /> <!-- events -->
<argument/> <!-- identifier -->
<argument /> <!-- check method -->
</service>
<service id="foq_elastica.elastica_to_model_transformer.prototype.orm" class="FOQ\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer" public="false">