Add Symfony ExpressionLanguage support for indexable callback
This commit is contained in:
parent
28641427d5
commit
97c98a0243
|
@ -6,6 +6,9 @@ use Doctrine\Common\EventSubscriber;
|
|||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\ExpressionLanguage\SyntaxError;
|
||||
|
||||
abstract class AbstractListener implements EventSubscriber
|
||||
{
|
||||
|
@ -51,6 +54,13 @@ abstract class AbstractListener implements EventSubscriber
|
|||
*/
|
||||
private $scheduledForRemoval = array();
|
||||
|
||||
/**
|
||||
* An instance of ExpressionLanguage
|
||||
*
|
||||
* @var ExpressionLanguage
|
||||
*/
|
||||
protected $expressionLanguage;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -89,8 +99,21 @@ abstract class AbstractListener implements EventSubscriber
|
|||
public function setIsIndexableCallback($callback)
|
||||
{
|
||||
if (is_string($callback)) {
|
||||
|
||||
if (!is_callable(array($this->objectClass, $callback))) {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback));
|
||||
|
||||
if(false !== ($expression = $this->getExpressionLanguage())) {
|
||||
|
||||
$callback = new Expression($callback);
|
||||
|
||||
try {
|
||||
$expression->compile($callback, array($this->getExpressionVar()));
|
||||
} catch(SyntaxError $e) {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback));
|
||||
}
|
||||
}
|
||||
} elseif (!is_callable($callback)) {
|
||||
if (is_array($callback)) {
|
||||
|
@ -98,6 +121,7 @@ abstract class AbstractListener implements EventSubscriber
|
|||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
|
||||
if ($class && $method) {
|
||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method));
|
||||
}
|
||||
|
@ -120,6 +144,10 @@ abstract class AbstractListener implements EventSubscriber
|
|||
return true;
|
||||
}
|
||||
|
||||
if($this->isIndexableCallback instanceof Expression) {
|
||||
return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object));
|
||||
}
|
||||
|
||||
return is_string($this->isIndexableCallback)
|
||||
? call_user_func(array($object, $this->isIndexableCallback))
|
||||
: call_user_func($this->isIndexableCallback, $object);
|
||||
|
@ -155,4 +183,33 @@ abstract class AbstractListener implements EventSubscriber
|
|||
unset($this->scheduledForRemoval[$objectHash]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $object
|
||||
* @return string
|
||||
*/
|
||||
private function getExpressionVar($object = null)
|
||||
{
|
||||
$class = $object ?: $this->objectClass;
|
||||
|
||||
$ref = new \ReflectionClass($class);
|
||||
|
||||
return strtolower($ref->getShortName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|ExpressionLanguage
|
||||
*/
|
||||
private function getExpressionLanguage()
|
||||
{
|
||||
if(null === $this->expressionLanguage) {
|
||||
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->expressionLanguage = new ExpressionLanguage();
|
||||
}
|
||||
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -630,6 +630,13 @@ In this case, the callback_class will be the `isIndexable()` method on the speci
|
|||
service and the object being considered for indexing will be passed as the only
|
||||
argument. This allows you to do more complex validation (e.g. ACL checks).
|
||||
|
||||
If you have the [Symfony ExpressionLanguage](https://github.com/symfony/expression-language) component installed, you can use expressions
|
||||
to evaluate the callback:
|
||||
|
||||
persistence:
|
||||
listener:
|
||||
is_indexable_callback: "user.isActive() && user.hasRole('ROLE_USER')"
|
||||
|
||||
As you might expect, new entities will only be indexed if the callback_class returns
|
||||
`true`. Additionally, modified entities will be updated or removed from the
|
||||
index depending on whether the callback_class returns `true` or `false`, respectively.
|
||||
|
|
|
@ -164,6 +164,7 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
|||
array('nonexistentEntityMethod'),
|
||||
array(array(new Listener\IndexableDecider(), 'internalMethod')),
|
||||
array(42),
|
||||
array('entity.getIsIndexable() && nonexistentEntityFunction()'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -173,6 +174,7 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
|||
array('getIsIndexable'),
|
||||
array(array(new Listener\IndexableDecider(), 'isIndexable')),
|
||||
array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }),
|
||||
array('entity.getIsIndexable()')
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,14 +24,16 @@
|
|||
"doctrine/mongodb-odm": "1.0.*@dev",
|
||||
"propel/propel1": "1.6.*",
|
||||
"pagerfanta/pagerfanta": "1.0.*@dev",
|
||||
"knplabs/knp-components": "1.2.*"
|
||||
"knplabs/knp-components": "1.2.*",
|
||||
"symfony/expression-language" : "2.4.*@dev"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/orm": ">=2.2,<2.5-dev",
|
||||
"doctrine/mongodb-odm": "1.0.*@dev",
|
||||
"propel/propel1": "1.6.*",
|
||||
"pagerfanta/pagerfanta": "1.0.*@dev",
|
||||
"knplabs/knp-components": "1.2.*"
|
||||
"knplabs/knp-components": "1.2.*",
|
||||
"symfony/expression-language" : "2.4.*@dev"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "FOS\\ElasticaBundle": "" }
|
||||
|
|
Loading…
Reference in a new issue