2013-09-01 20:41:49 +01:00
< ? 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 ;
2016-08-26 08:29:50 +01:00
use Psr\Cache\CacheItemPoolInterface ;
use Symfony\Component\Cache\Adapter\ArrayAdapter ;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter ;
2013-09-23 00:48:20 +01:00
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface ;
2013-09-06 07:52:21 +01:00
2013-09-01 20:41:49 +01:00
/**
* Allows to compile and evaluate expressions written in your own DSL .
*
* @ author Fabien Potencier < fabien @ symfony . com >
*/
class ExpressionLanguage
{
2013-09-23 00:48:20 +01:00
/**
2016-08-26 08:29:50 +01:00
* @ var CacheItemPoolInterface
2013-09-23 00:48:20 +01:00
*/
2013-09-23 11:22:40 +01:00
private $cache ;
2013-09-01 20:41:49 +01:00
private $lexer ;
private $parser ;
private $compiler ;
2013-11-10 17:06:47 +00:00
protected $functions = array ();
2013-09-01 20:41:49 +01:00
2014-09-23 16:21:31 +01:00
/**
2016-08-26 08:29:50 +01:00
* @ param CacheItemPoolInterface $cache
2014-09-23 16:21:31 +01:00
* @ param ExpressionFunctionProviderInterface [] $providers
*/
2016-08-26 08:29:50 +01:00
public function __construct ( $cache = null , array $providers = array ())
2013-09-01 20:41:49 +01:00
{
2016-08-26 08:29:50 +01:00
if ( null !== $cache ) {
if ( $cache instanceof ParserCacheInterface ) {
@ trigger_error ( sprintf ( 'Passing an instance of %s as constructor argument for %s is deprecated as of 3.2 and will be removed in 4.0. Pass an instance of %s instead.' , ParserCacheInterface :: class , self :: class , CacheItemPoolInterface :: class ), E_USER_DEPRECATED );
$cache = new ParserCacheAdapter ( $cache );
} elseif ( ! $cache instanceof CacheItemPoolInterface ) {
throw new \InvalidArgumentException ( sprintf ( 'Cache argument has to implement %s.' , CacheItemPoolInterface :: class ));
}
}
$this -> cache = $cache ? : new ArrayAdapter ();
2013-09-01 20:41:49 +01:00
$this -> registerFunctions ();
2014-09-23 16:21:31 +01:00
foreach ( $providers as $provider ) {
$this -> registerProvider ( $provider );
}
2013-09-01 20:41:49 +01:00
}
/**
* Compiles an expression source code .
*
2013-09-20 14:35:54 +01:00
* @ param Expression | string $expression The expression to compile
* @ param array $names An array of valid names
2013-09-01 20:41:49 +01:00
*
* @ return string The compiled PHP source code
*/
public function compile ( $expression , $names = array ())
{
2013-09-20 14:35:54 +01:00
return $this -> getCompiler () -> compile ( $this -> parse ( $expression , $names ) -> getNodes ()) -> getSource ();
2013-09-01 20:41:49 +01:00
}
2013-09-06 07:52:21 +01:00
/**
* Evaluate an expression .
*
* @ param Expression | string $expression The expression to compile
* @ param array $values An array of values
*
* @ return string The result of the evaluation of the expression
*/
2013-09-01 20:41:49 +01:00
public function evaluate ( $expression , $values = array ())
{
2013-09-20 14:35:54 +01:00
return $this -> parse ( $expression , array_keys ( $values )) -> getNodes () -> evaluate ( $this -> functions , $values );
2013-09-06 07:52:21 +01:00
}
/**
* Parses an expression .
*
* @ param Expression | string $expression The expression to parse
2013-11-16 15:13:54 +00:00
* @ param array $names An array of valid names
2013-09-06 07:52:21 +01:00
*
2013-09-20 14:35:54 +01:00
* @ return ParsedExpression A ParsedExpression instance
2013-09-06 07:52:21 +01:00
*/
public function parse ( $expression , $names )
{
2013-09-20 14:35:54 +01:00
if ( $expression instanceof ParsedExpression ) {
return $expression ;
}
2015-08-14 13:56:24 +01:00
asort ( $names );
$cacheKeyItems = array ();
foreach ( $names as $nameKey => $name ) {
$cacheKeyItems [] = is_int ( $nameKey ) ? $name : $nameKey . ':' . $name ;
}
2016-08-26 08:29:50 +01:00
$cacheItem = $this -> cache -> getItem ( rawurlencode ( $expression . '//' . implode ( '|' , $cacheKeyItems )));
2013-09-06 07:52:21 +01:00
2016-08-26 08:29:50 +01:00
if ( null === $parsedExpression = $cacheItem -> get ()) {
2013-09-20 14:35:54 +01:00
$nodes = $this -> getParser () -> parse ( $this -> getLexer () -> tokenize (( string ) $expression ), $names );
2013-09-23 00:48:20 +01:00
$parsedExpression = new ParsedExpression (( string ) $expression , $nodes );
2016-08-26 08:29:50 +01:00
$cacheItem -> set ( $parsedExpression );
$this -> cache -> save ( $cacheItem );
2013-09-06 07:52:21 +01:00
}
2013-09-23 00:48:20 +01:00
return $parsedExpression ;
2013-09-01 20:41:49 +01:00
}
2013-09-20 15:16:44 +01:00
/**
* 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
2014-09-23 16:21:31 +01:00
*
* @ see ExpressionFunction
2013-09-20 15:16:44 +01:00
*/
2015-10-05 17:52:37 +01:00
public function register ( $name , callable $compiler , callable $evaluator )
2013-09-01 20:41:49 +01:00
{
$this -> functions [ $name ] = array ( 'compiler' => $compiler , 'evaluator' => $evaluator );
}
2014-09-23 16:21:31 +01:00
public function addFunction ( ExpressionFunction $function )
{
$this -> register ( $function -> getName (), $function -> getCompiler (), $function -> getEvaluator ());
}
public function registerProvider ( ExpressionFunctionProviderInterface $provider )
{
foreach ( $provider -> getFunctions () as $function ) {
$this -> addFunction ( $function );
}
}
2013-09-01 20:41:49 +01:00
protected function registerFunctions ()
{
2013-09-20 15:16:44 +01:00
$this -> register ( 'constant' , function ( $constant ) {
2013-09-01 20:41:49 +01:00
return sprintf ( 'constant(%s)' , $constant );
}, function ( array $values , $constant ) {
return constant ( $constant );
});
}
private function getLexer ()
{
if ( null === $this -> lexer ) {
$this -> lexer = new Lexer ();
}
return $this -> lexer ;
}
private function getParser ()
{
if ( null === $this -> parser ) {
$this -> parser = new Parser ( $this -> functions );
}
return $this -> parser ;
}
private function getCompiler ()
{
if ( null === $this -> compiler ) {
$this -> compiler = new Compiler ( $this -> functions );
}
return $this -> compiler -> reset ();
}
}