Skip to content

[ExpressionLanguage] Create an ExpressionFunction from a PHP function name #21122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
37 changes: 37 additions & 0 deletions src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,41 @@ public function getEvaluator()
{
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,7 @@ public function registerProvider(ExpressionFunctionProviderInterface $provider)

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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,20 @@ public function testConstantFunction()
$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()
{
$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()'));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\ExpressionLanguage\ExpressionPhpFunction;

class TestProvider implements ExpressionFunctionProviderInterface
{
Expand All @@ -24,6 +25,17 @@ public function getFunctions()
}, 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;
}