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 Doctrine\Common\Persistence\ObjectManager;
|
||||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||||
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
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
|
abstract class AbstractListener implements EventSubscriber
|
||||||
{
|
{
|
||||||
|
@ -51,6 +54,13 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
*/
|
*/
|
||||||
private $scheduledForRemoval = array();
|
private $scheduledForRemoval = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of ExpressionLanguage
|
||||||
|
*
|
||||||
|
* @var ExpressionLanguage
|
||||||
|
*/
|
||||||
|
protected $expressionLanguage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -89,8 +99,21 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
public function setIsIndexableCallback($callback)
|
public function setIsIndexableCallback($callback)
|
||||||
{
|
{
|
||||||
if (is_string($callback)) {
|
if (is_string($callback)) {
|
||||||
|
|
||||||
if (!is_callable(array($this->objectClass, $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)) {
|
} elseif (!is_callable($callback)) {
|
||||||
if (is_array($callback)) {
|
if (is_array($callback)) {
|
||||||
|
@ -98,6 +121,7 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
if (is_object($class)) {
|
if (is_object($class)) {
|
||||||
$class = get_class($class);
|
$class = get_class($class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($class && $method) {
|
if ($class && $method) {
|
||||||
throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($this->isIndexableCallback instanceof Expression) {
|
||||||
|
return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object));
|
||||||
|
}
|
||||||
|
|
||||||
return is_string($this->isIndexableCallback)
|
return is_string($this->isIndexableCallback)
|
||||||
? call_user_func(array($object, $this->isIndexableCallback))
|
? call_user_func(array($object, $this->isIndexableCallback))
|
||||||
: call_user_func($this->isIndexableCallback, $object);
|
: call_user_func($this->isIndexableCallback, $object);
|
||||||
|
@ -155,4 +183,33 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
unset($this->scheduledForRemoval[$objectHash]);
|
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
|
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).
|
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
|
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
|
`true`. Additionally, modified entities will be updated or removed from the
|
||||||
index depending on whether the callback_class returns `true` or `false`, respectively.
|
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('nonexistentEntityMethod'),
|
||||||
array(array(new Listener\IndexableDecider(), 'internalMethod')),
|
array(array(new Listener\IndexableDecider(), 'internalMethod')),
|
||||||
array(42),
|
array(42),
|
||||||
|
array('entity.getIsIndexable() && nonexistentEntityFunction()'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +174,7 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
array('getIsIndexable'),
|
array('getIsIndexable'),
|
||||||
array(array(new Listener\IndexableDecider(), 'isIndexable')),
|
array(array(new Listener\IndexableDecider(), 'isIndexable')),
|
||||||
array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }),
|
array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }),
|
||||||
|
array('entity.getIsIndexable()')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,14 +24,16 @@
|
||||||
"doctrine/mongodb-odm": "1.0.*@dev",
|
"doctrine/mongodb-odm": "1.0.*@dev",
|
||||||
"propel/propel1": "1.6.*",
|
"propel/propel1": "1.6.*",
|
||||||
"pagerfanta/pagerfanta": "1.0.*@dev",
|
"pagerfanta/pagerfanta": "1.0.*@dev",
|
||||||
"knplabs/knp-components": "1.2.*"
|
"knplabs/knp-components": "1.2.*",
|
||||||
|
"symfony/expression-language" : "2.4.*@dev"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"doctrine/orm": ">=2.2,<2.5-dev",
|
"doctrine/orm": ">=2.2,<2.5-dev",
|
||||||
"doctrine/mongodb-odm": "1.0.*@dev",
|
"doctrine/mongodb-odm": "1.0.*@dev",
|
||||||
"propel/propel1": "1.6.*",
|
"propel/propel1": "1.6.*",
|
||||||
"pagerfanta/pagerfanta": "1.0.*@dev",
|
"pagerfanta/pagerfanta": "1.0.*@dev",
|
||||||
"knplabs/knp-components": "1.2.*"
|
"knplabs/knp-components": "1.2.*",
|
||||||
|
"symfony/expression-language" : "2.4.*@dev"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "FOS\\ElasticaBundle": "" }
|
"psr-0": { "FOS\\ElasticaBundle": "" }
|
||||||
|
|
Loading…
Reference in a new issue