merged branch adrienbrault/expression-cache (PR #9095)
This PR was squashed before being merged into the master branch (closes #9095).
Discussion
----------
[ExpressionLanguage] Introduce a ParserCacheInterface with array/doctrine implementations
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | N/A
| License | MIT
| Doc PR | N/A
Commits
-------
c8e6799
[ExpressionLanguage] Introduce a ParserCacheInterface with array/doctrine implementations
This commit is contained in:
commit
db00c3f510
@ -0,0 +1,48 @@
|
|||||||
|
<?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\Bridge\Doctrine\ExpressionLanguage;
|
||||||
|
|
||||||
|
use Doctrine\Common\Cache\Cache;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParsedExpression;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrien Brault <adrien.brault@gmail.com>
|
||||||
|
*/
|
||||||
|
class DoctrineParserCache implements ParserCacheInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Cache
|
||||||
|
*/
|
||||||
|
private $cache;
|
||||||
|
|
||||||
|
public function __construct(Cache $cache)
|
||||||
|
{
|
||||||
|
$this->cache = $cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function fetch($key)
|
||||||
|
{
|
||||||
|
return $this->cache->fetch($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function save($key, ParsedExpression $expression)
|
||||||
|
{
|
||||||
|
$this->cache->save($key, $expression);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Doctrine\Tests\ExpressionLanguage;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Doctrine\ExpressionLanguage\DoctrineParserCache;
|
||||||
|
|
||||||
|
class DoctrineParserCacheTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testFetch()
|
||||||
|
{
|
||||||
|
$doctrineCacheMock = $this->getMock('Doctrine\Common\Cache\Cache');
|
||||||
|
$parserCache = new DoctrineParserCache($doctrineCacheMock);
|
||||||
|
|
||||||
|
$doctrineCacheMock->expects($this->once())
|
||||||
|
->method('fetch')
|
||||||
|
->will($this->returnValue('bar'));
|
||||||
|
|
||||||
|
$result = $parserCache->fetch('foo');
|
||||||
|
|
||||||
|
$this->assertEquals('bar', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSave()
|
||||||
|
{
|
||||||
|
$doctrineCacheMock = $this->getMock('Doctrine\Common\Cache\Cache');
|
||||||
|
$parserCache = new DoctrineParserCache($doctrineCacheMock);
|
||||||
|
|
||||||
|
$expression = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParsedExpression')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$doctrineCacheMock->expects($this->once())
|
||||||
|
->method('save')
|
||||||
|
->with('foo', $expression);
|
||||||
|
|
||||||
|
$parserCache->save('foo', $expression);
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\ExpressionLanguage;
|
namespace Symfony\Component\ExpressionLanguage;
|
||||||
|
|
||||||
use Symfony\Component\ExpressionLanguage\Node\Node;
|
use Symfony\Component\ExpressionLanguage\ParserCache\ArrayParserCache;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to compile and evaluate expressions written in your own DSL.
|
* Allows to compile and evaluate expressions written in your own DSL.
|
||||||
@ -20,15 +21,20 @@ use Symfony\Component\ExpressionLanguage\Node\Node;
|
|||||||
*/
|
*/
|
||||||
class ExpressionLanguage
|
class ExpressionLanguage
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var ParserCacheInterface
|
||||||
|
*/
|
||||||
|
private $parserCache;
|
||||||
|
|
||||||
private $lexer;
|
private $lexer;
|
||||||
private $parser;
|
private $parser;
|
||||||
private $compiler;
|
private $compiler;
|
||||||
private $cache;
|
|
||||||
|
|
||||||
protected $functions;
|
protected $functions;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(ParserCacheInterface $parserCache = null)
|
||||||
{
|
{
|
||||||
|
$this->parserCache = $parserCache ?: new ArrayParserCache();
|
||||||
$this->functions = array();
|
$this->functions = array();
|
||||||
$this->registerFunctions();
|
$this->registerFunctions();
|
||||||
}
|
}
|
||||||
@ -74,12 +80,14 @@ class ExpressionLanguage
|
|||||||
|
|
||||||
$key = $expression.'//'.implode('-', $names);
|
$key = $expression.'//'.implode('-', $names);
|
||||||
|
|
||||||
if (!isset($this->cache[$key])) {
|
if (null === $parsedExpression = $this->parserCache->fetch($key)) {
|
||||||
$nodes = $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);
|
$parsedExpression = new ParsedExpression((string) $expression, $nodes);
|
||||||
|
|
||||||
|
$this->parserCache->save($key, $parsedExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->cache[$key];
|
return $parsedExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
<?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\ParserCache;
|
||||||
|
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParsedExpression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrien Brault <adrien.brault@gmail.com>
|
||||||
|
*/
|
||||||
|
class ArrayParserCache implements ParserCacheInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $cache = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function fetch($key)
|
||||||
|
{
|
||||||
|
return isset($this->cache[$key]) ? $this->cache[$key] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function save($key, ParsedExpression $expression)
|
||||||
|
{
|
||||||
|
$this->cache[$key] = $expression;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?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\ParserCache;
|
||||||
|
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParsedExpression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrien Brault <adrien.brault@gmail.com>
|
||||||
|
*/
|
||||||
|
interface ParserCacheInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param ParsedExpression $data
|
||||||
|
*/
|
||||||
|
public function save($key, ParsedExpression $expression);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @return ParsedExpression|null
|
||||||
|
*/
|
||||||
|
public function fetch($key);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\ExpressionLanguage\Tests;
|
||||||
|
|
||||||
|
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ParsedExpression;
|
||||||
|
|
||||||
|
class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testCachedParse()
|
||||||
|
{
|
||||||
|
$cacheMock = $this->getMock('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface');
|
||||||
|
$savedParsedExpression = null;
|
||||||
|
$expressionLanguage = new ExpressionLanguage($cacheMock);
|
||||||
|
|
||||||
|
$cacheMock
|
||||||
|
->expects($this->exactly(2))
|
||||||
|
->method('fetch')
|
||||||
|
->with('1 + 1//')
|
||||||
|
->will($this->returnCallback(function () use (&$savedParsedExpression) {
|
||||||
|
return $savedParsedExpression;
|
||||||
|
}))
|
||||||
|
;
|
||||||
|
$cacheMock
|
||||||
|
->expects($this->exactly(1))
|
||||||
|
->method('save')
|
||||||
|
->with('1 + 1//', $this->isInstanceOf('Symfony\Component\ExpressionLanguage\ParsedExpression'))
|
||||||
|
->will($this->returnCallback(function ($key, $expression) use (&$savedParsedExpression) {
|
||||||
|
$savedParsedExpression = $expression;
|
||||||
|
}))
|
||||||
|
;
|
||||||
|
|
||||||
|
$parsedExpression = $expressionLanguage->parse('1 + 1', array());
|
||||||
|
$this->assertSame($savedParsedExpression, $parsedExpression);
|
||||||
|
|
||||||
|
$parsedExpression = $expressionLanguage->parse('1 + 1', array());
|
||||||
|
$this->assertSame($savedParsedExpression, $parsedExpression);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user