merged branch fabpot/expression-language-tweaks (PR #9091)
This PR was merged into the master branch. Discussion ---------- [ExpressionLanguage] made minor tweaks | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9087 | License | MIT | Doc PR | n/a * made ExpressionLanguage::parse return an ParsedExpression instance * optimized the size of the serialization of expressions Commits -------e869136
[ExpressionLanguage] renamed addFunction() to register()5076ec7
[ExpressionLanguage] optimized serialization of nodes and expressions60b9f85
[ExpressionLanguage] made ExpressionLanguage::parse return an ParsedExpression instance
This commit is contained in:
commit
8aa685bbe9
@ -615,7 +615,7 @@ class SecurityExtension extends Extension
|
||||
->register($id, 'Symfony\Component\ExpressionLanguage\SerializedParsedExpression')
|
||||
->setPublic(false)
|
||||
->addArgument($expression)
|
||||
->addArgument(serialize($this->getExpressionLanguage()->parse($expression, array('token', 'user', 'object', 'roles', 'request'))))
|
||||
->addArgument(serialize($this->getExpressionLanguage()->parse($expression, array('token', 'user', 'object', 'roles', 'request'))->getNodes()))
|
||||
;
|
||||
|
||||
return $this->expressions[$id] = new Reference($id);
|
||||
|
@ -27,13 +27,13 @@ class ExpressionLanguage extends BaseExpressionLanguage
|
||||
{
|
||||
parent::registerFunctions();
|
||||
|
||||
$this->addFunction('service', function ($arg) {
|
||||
$this->register('service', function ($arg) {
|
||||
return sprintf('$this->get(%s)', $arg);
|
||||
}, function (array $variables, $value) {
|
||||
return $variables['container']->get($value);
|
||||
});
|
||||
|
||||
$this->addFunction('parameter', function ($arg) {
|
||||
$this->register('parameter', function ($arg) {
|
||||
return sprintf('$this->getParameter(%s)', $arg);
|
||||
}, function (array $variables, $value) {
|
||||
return $variables['container']->getParameter($value);
|
||||
|
@ -36,14 +36,14 @@ class ExpressionLanguage
|
||||
/**
|
||||
* Compiles an expression source code.
|
||||
*
|
||||
* @param string $expression The expression to compile
|
||||
* @param array $names An array of valid names
|
||||
* @param Expression|string $expression The expression to compile
|
||||
* @param array $names An array of valid names
|
||||
*
|
||||
* @return string The compiled PHP source code
|
||||
*/
|
||||
public function compile($expression, $names = array())
|
||||
{
|
||||
return $this->getCompiler()->compile($this->parse($expression, $names))->getSource();
|
||||
return $this->getCompiler()->compile($this->parse($expression, $names)->getNodes())->getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,13 +56,7 @@ class ExpressionLanguage
|
||||
*/
|
||||
public function evaluate($expression, $values = array())
|
||||
{
|
||||
if ($expression instanceof ParsedExpression) {
|
||||
$expression = $expression->getNodes();
|
||||
} else {
|
||||
$expression = $this->parse($expression, array_keys($values));
|
||||
}
|
||||
|
||||
return $expression->evaluate($this->functions, $values);
|
||||
return $this->parse($expression, array_keys($values))->getNodes()->evaluate($this->functions, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,27 +64,39 @@ class ExpressionLanguage
|
||||
*
|
||||
* @param Expression|string $expression The expression to parse
|
||||
*
|
||||
* @return Node A Node tree
|
||||
* @return ParsedExpression A ParsedExpression instance
|
||||
*/
|
||||
public function parse($expression, $names)
|
||||
{
|
||||
if ($expression instanceof ParsedExpression) {
|
||||
return $expression;
|
||||
}
|
||||
|
||||
$key = $expression.'//'.implode('-', $names);
|
||||
|
||||
if (!isset($this->cache[$key])) {
|
||||
$this->cache[$key] = $this->getParser()->parse($this->getLexer()->tokenize((string) $expression), $names);
|
||||
$nodes = $this->getParser()->parse($this->getLexer()->tokenize((string) $expression), $names);
|
||||
$this->cache[$key] = new ParsedExpression((string) $expression, $nodes);
|
||||
}
|
||||
|
||||
return $this->cache[$key];
|
||||
}
|
||||
|
||||
public function addFunction($name, $compiler, $evaluator)
|
||||
/**
|
||||
* Registers a function.
|
||||
*
|
||||
* @param string $name The function name
|
||||
* @param callable $compiler A callable able to compile the function
|
||||
* @param callable $evaluator A callable able to evaluate the function
|
||||
*/
|
||||
public function register($name, $compiler, $evaluator)
|
||||
{
|
||||
$this->functions[$name] = array('compiler' => $compiler, 'evaluator' => $evaluator);
|
||||
}
|
||||
|
||||
protected function registerFunctions()
|
||||
{
|
||||
$this->addFunction('constant', function ($constant) {
|
||||
$this->register('constant', function ($constant) {
|
||||
return sprintf('constant(%s)', $constant);
|
||||
}, function (array $values, $constant) {
|
||||
return constant($constant);
|
||||
|
@ -15,13 +15,13 @@ use Symfony\Component\ExpressionLanguage\Compiler;
|
||||
|
||||
class BinaryNode extends Node
|
||||
{
|
||||
private $operators = array(
|
||||
private static $operators = array(
|
||||
'~' => '.',
|
||||
'and' => '&&',
|
||||
'or' => '||',
|
||||
);
|
||||
|
||||
private $functions = array(
|
||||
private static $functions = array(
|
||||
'**' => 'pow',
|
||||
'..' => 'range',
|
||||
'in' => 'in_array',
|
||||
@ -50,9 +50,9 @@ class BinaryNode extends Node
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->functions[$operator])) {
|
||||
if (isset(self::$functions[$operator])) {
|
||||
$compiler
|
||||
->raw(sprintf('%s(', $this->functions[$operator]))
|
||||
->raw(sprintf('%s(', self::$functions[$operator]))
|
||||
->compile($this->nodes['left'])
|
||||
->raw(', ')
|
||||
->compile($this->nodes['right'])
|
||||
@ -62,8 +62,8 @@ class BinaryNode extends Node
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->operators[$operator])) {
|
||||
$operator = $this->operators[$operator];
|
||||
if (isset(self::$operators[$operator])) {
|
||||
$operator = self::$operators[$operator];
|
||||
}
|
||||
|
||||
$compiler
|
||||
@ -83,12 +83,12 @@ class BinaryNode extends Node
|
||||
$left = $this->nodes['left']->evaluate($functions, $values);
|
||||
$right = $this->nodes['right']->evaluate($functions, $values);
|
||||
|
||||
if (isset($this->functions[$operator])) {
|
||||
if (isset(self::$functions[$operator])) {
|
||||
if ('not in' == $operator) {
|
||||
return !call_user_func('in_array', $left, $right);
|
||||
}
|
||||
|
||||
return call_user_func($this->functions[$operator], $left, $right);
|
||||
return call_user_func(self::$functions[$operator], $left, $right);
|
||||
}
|
||||
|
||||
switch ($operator) {
|
||||
|
@ -15,7 +15,7 @@ use Symfony\Component\ExpressionLanguage\Compiler;
|
||||
|
||||
class UnaryNode extends Node
|
||||
{
|
||||
private $operators = array(
|
||||
private static $operators = array(
|
||||
'!' => '!',
|
||||
'not' => '!',
|
||||
'+' => '+',
|
||||
@ -32,7 +32,7 @@ class UnaryNode extends Node
|
||||
{
|
||||
$compiler
|
||||
->raw('(')
|
||||
->raw($this->operators[$this->attributes['operator']])
|
||||
->raw(self::$operators[$this->attributes['operator']])
|
||||
->compile($this->nodes['node'])
|
||||
->raw(')')
|
||||
;
|
||||
|
@ -25,7 +25,7 @@ You can extend your DSL with functions:
|
||||
$evaluator = function (array $variables, $value) {
|
||||
return strtoupper($value);
|
||||
};
|
||||
$language->addFunction('upper', $compiler, $evaluator);
|
||||
$language->register('upper', $compiler, $evaluator);
|
||||
|
||||
echo $language->evaluate('"foo" ~ upper(foo)', array('foo' => 'bar'));
|
||||
// would output fooBAR
|
||||
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\ExpressionLanguage\Tests;
|
||||
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
class ExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$expression = new Expression('kernel.boot()');
|
||||
|
||||
$serializedExpression = serialize($expression);
|
||||
$unserializedExpression = unserialize($serializedExpression);
|
||||
|
||||
$this->assertEquals($expression, $unserializedExpression);
|
||||
}
|
||||
}
|
@ -16,6 +16,18 @@ use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
|
||||
|
||||
class ArrayNodeTest extends AbstractNodeTest
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$node = $this->createArrayNode();
|
||||
$node->addElement(new ConstantNode('foo'));
|
||||
|
||||
$serializedNode = serialize($node);
|
||||
$unserializedNode = unserialize($serializedNode);
|
||||
|
||||
$this->assertEquals($node, $unserializedNode);
|
||||
$this->assertNotEquals($this->createArrayNode(), $unserializedNode);
|
||||
}
|
||||
|
||||
public function getEvaluateData()
|
||||
{
|
||||
return array(
|
||||
|
@ -27,4 +27,14 @@ Node(
|
||||
EOF
|
||||
, (string) $node);
|
||||
}
|
||||
|
||||
public function testSerialization()
|
||||
{
|
||||
$node = new Node(array('foo' => 'bar'), array('bar' => 'foo'));
|
||||
|
||||
$serializedNode = serialize($node);
|
||||
$unserializedNode = unserialize($serializedNode);
|
||||
|
||||
$this->assertEquals($node, $unserializedNode);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\ExpressionLanguage\Tests;
|
||||
|
||||
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
|
||||
use Symfony\Component\ExpressionLanguage\ParsedExpression;
|
||||
|
||||
class ParsedExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$expression = new ParsedExpression('25', new ConstantNode('25'));
|
||||
|
||||
$serializedExpression = serialize($expression);
|
||||
$unserializedExpression = unserialize($serializedExpression);
|
||||
|
||||
$this->assertEquals($expression, $unserializedExpression);
|
||||
}
|
||||
}
|
@ -24,31 +24,31 @@ class ExpressionLanguage extends BaseExpressionLanguage
|
||||
{
|
||||
parent::registerFunctions();
|
||||
|
||||
$this->addFunction('is_anonymous', function () {
|
||||
$this->register('is_anonymous', function () {
|
||||
return '$trust_resolver->isAnonymous($token)';
|
||||
}, function (array $variables) {
|
||||
return $variables['trust_resolver']->isAnonymous($variables['token']);
|
||||
});
|
||||
|
||||
$this->addFunction('is_authenticated', function () {
|
||||
$this->register('is_authenticated', function () {
|
||||
return '!$trust_resolver->isAnonymous($token)';
|
||||
}, function (array $variables) {
|
||||
return !$variables['trust_resolver']->isAnonymous($variables['token']);
|
||||
});
|
||||
|
||||
$this->addFunction('is_fully_authenticated', function () {
|
||||
$this->register('is_fully_authenticated', function () {
|
||||
return '!$trust_resolver->isFullFledge($token)';
|
||||
}, function (array $variables) {
|
||||
return !$variables['trust_resolver']->isFullFledge($variables['token']);
|
||||
});
|
||||
|
||||
$this->addFunction('is_remember_me', function () {
|
||||
$this->register('is_remember_me', function () {
|
||||
return '!$trust_resolver->isRememberMe($token)';
|
||||
}, function (array $variables) {
|
||||
return !$variables['trust_resolver']->isRememberMe($variables['token']);
|
||||
});
|
||||
|
||||
$this->addFunction('has_role', function ($role) {
|
||||
$this->register('has_role', function ($role) {
|
||||
return sprintf('in_array(%s, $roles)', $role);
|
||||
}, function (array $variables, $role) {
|
||||
return in_array($role, $variables['roles']);
|
||||
|
Reference in New Issue
Block a user