[ExpressionLanguage] Create an ExpressionFunction from a PHP function name

This commit is contained in:
Dany Maillard 2017-01-02 02:49:09 +01:00 committed by Fabien Potencier
parent 61a67ecc5a
commit 44d67ed5f5
5 changed files with 101 additions and 6 deletions

View File

@ -62,4 +62,41 @@ class ExpressionFunction
{
return $this->evaluator;
}
/**
* Creates an ExpressionFunction from a PHP function name.
*
* @param string $phpFunctionName The PHP function name
* @param string|null $expressionFunctionName The expression function name (default: same than the PHP function name)
*
* @return self
*
* @throws \InvalidArgumentException if given PHP function name does not exist
* @throws \InvalidArgumentException if given PHP function name is in namespace
* and expression function name is not defined
*/
public static function fromPhp($phpFunctionName, $expressionFunctionName = null)
{
$phpFunctionName = ltrim($phpFunctionName, '\\');
if (!function_exists($phpFunctionName)) {
throw new \InvalidArgumentException(sprintf('PHP function "%s" does not exist.', $phpFunctionName));
}
$parts = explode('\\', $phpFunctionName);
if (!$expressionFunctionName && count($parts) > 1) {
throw new \InvalidArgumentException(sprintf('An expression function name must be defined when PHP function "%s" is namespaced.', $phpFunctionName));
}
$compiler = function () use ($phpFunctionName) {
return sprintf('\%s(%s)', $phpFunctionName, implode(', ', func_get_args()));
};
$evaluator = function () use ($phpFunctionName) {
$args = func_get_args();
return call_user_func_array($phpFunctionName, array_splice($args, 1));
};
return new self($expressionFunctionName ?: end($parts), $compiler, $evaluator);
}
}

View File

@ -143,11 +143,7 @@ class ExpressionLanguage
protected function registerFunctions()
{
$this->register('constant', function ($constant) {
return sprintf('constant(%s)', $constant);
}, function (array $values, $constant) {
return constant($constant);
});
$this->addFunction(ExpressionFunction::fromPhp('constant'));
}
private function getLexer()

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
/**
* Tests ExpressionFunction.
*
* @author Dany Maillard <danymaillard93b@gmail.com>
*/
class ExpressionFunctionTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage PHP function "fn_does_not_exist" does not exist.
*/
public function testFunctionDoesNotExist()
{
ExpressionFunction::fromPhp('fn_does_not_exist');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage An expression function name must be defined when PHP function "Symfony\Component\ExpressionLanguage\Tests\fn_namespaced" is namespaced.
*/
public function testFunctionNamespaced()
{
ExpressionFunction::fromPhp('Symfony\Component\ExpressionLanguage\Tests\fn_namespaced');
}
}
function fn_namespaced()
{
}

View File

@ -108,7 +108,7 @@ class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(PHP_VERSION, $expressionLanguage->evaluate('constant("PHP_VERSION")'));
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals('constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")'));
$this->assertEquals('\constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")'));
}
public function testProviders()
@ -116,6 +116,12 @@ class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase
$expressionLanguage = new ExpressionLanguage(null, array(new TestProvider()));
$this->assertEquals('foo', $expressionLanguage->evaluate('identity("foo")'));
$this->assertEquals('"foo"', $expressionLanguage->compile('identity("foo")'));
$this->assertEquals('FOO', $expressionLanguage->evaluate('strtoupper("foo")'));
$this->assertEquals('\strtoupper("foo")', $expressionLanguage->compile('strtoupper("foo")'));
$this->assertEquals('foo', $expressionLanguage->evaluate('strtolower("FOO")'));
$this->assertEquals('\strtolower("FOO")', $expressionLanguage->compile('strtolower("FOO")'));
$this->assertTrue($expressionLanguage->evaluate('fn_namespaced()'));
$this->assertEquals('\Symfony\Component\ExpressionLanguage\Tests\Fixtures\fn_namespaced()', $expressionLanguage->compile('fn_namespaced()'));
}
/**

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests\Fixtures;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\ExpressionLanguage\ExpressionPhpFunction;
class TestProvider implements ExpressionFunctionProviderInterface
{
@ -24,6 +25,17 @@ class TestProvider implements ExpressionFunctionProviderInterface
}, function (array $values, $input) {
return $input;
}),
ExpressionFunction::fromPhp('strtoupper'),
ExpressionFunction::fromPhp('\strtolower'),
ExpressionFunction::fromPhp('Symfony\Component\ExpressionLanguage\Tests\Fixtures\fn_namespaced', 'fn_namespaced'),
);
}
}
function fn_namespaced()
{
return true;
}