From c8e679970e658d3dbb0802f6ed3efdbbf2e337ee Mon Sep 17 00:00:00 2001 From: Adrien Brault Date: Sun, 22 Sep 2013 16:48:20 -0700 Subject: [PATCH] [ExpressionLanguage] Introduce a ParserCacheInterface with array/doctrine implementations --- .../DoctrineParserCache.php | 48 +++++++++++++++++++ .../DoctrineParserCacheTest.php | 38 +++++++++++++++ .../ExpressionLanguage/ExpressionLanguage.php | 20 +++++--- .../ParserCache/ArrayParserCache.php | 41 ++++++++++++++++ .../ParserCache/ParserCacheInterface.php | 32 +++++++++++++ .../Tests/ExpressionLanguageTest.php | 39 +++++++++++++++ 6 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/ExpressionLanguage/DoctrineParserCache.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/ExpressionLanguage/DoctrineParserCacheTest.php create mode 100644 src/Symfony/Component/ExpressionLanguage/ParserCache/ArrayParserCache.php create mode 100644 src/Symfony/Component/ExpressionLanguage/ParserCache/ParserCacheInterface.php create mode 100644 src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php diff --git a/src/Symfony/Bridge/Doctrine/ExpressionLanguage/DoctrineParserCache.php b/src/Symfony/Bridge/Doctrine/ExpressionLanguage/DoctrineParserCache.php new file mode 100644 index 0000000000..cd8b2487a0 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/ExpressionLanguage/DoctrineParserCache.php @@ -0,0 +1,48 @@ + + * + * 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 + */ +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); + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/ExpressionLanguage/DoctrineParserCacheTest.php b/src/Symfony/Bridge/Doctrine/Tests/ExpressionLanguage/DoctrineParserCacheTest.php new file mode 100644 index 0000000000..11d8084a57 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/ExpressionLanguage/DoctrineParserCacheTest.php @@ -0,0 +1,38 @@ +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); + } +} diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php index b5cd15e0de..dbab8ba08f 100644 --- a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php +++ b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php @@ -11,7 +11,8 @@ 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. @@ -20,15 +21,20 @@ use Symfony\Component\ExpressionLanguage\Node\Node; */ class ExpressionLanguage { + /** + * @var ParserCacheInterface + */ + private $parserCache; + private $lexer; private $parser; private $compiler; - private $cache; protected $functions; - public function __construct() + public function __construct(ParserCacheInterface $parserCache = null) { + $this->parserCache = $parserCache ?: new ArrayParserCache(); $this->functions = array(); $this->registerFunctions(); } @@ -74,12 +80,14 @@ class ExpressionLanguage $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); - $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; } /** diff --git a/src/Symfony/Component/ExpressionLanguage/ParserCache/ArrayParserCache.php b/src/Symfony/Component/ExpressionLanguage/ParserCache/ArrayParserCache.php new file mode 100644 index 0000000000..1d2aedb514 --- /dev/null +++ b/src/Symfony/Component/ExpressionLanguage/ParserCache/ArrayParserCache.php @@ -0,0 +1,41 @@ + + * + * 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 + */ +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; + } +} diff --git a/src/Symfony/Component/ExpressionLanguage/ParserCache/ParserCacheInterface.php b/src/Symfony/Component/ExpressionLanguage/ParserCache/ParserCacheInterface.php new file mode 100644 index 0000000000..888b522645 --- /dev/null +++ b/src/Symfony/Component/ExpressionLanguage/ParserCache/ParserCacheInterface.php @@ -0,0 +1,32 @@ + + * + * 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 + */ +interface ParserCacheInterface +{ + /** + * @param string $key + * @param ParsedExpression $data + */ + public function save($key, ParsedExpression $expression); + + /** + * @param string $key + * @return ParsedExpression|null + */ + public function fetch($key); +} diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php new file mode 100644 index 0000000000..0ef42bb0ca --- /dev/null +++ b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php @@ -0,0 +1,39 @@ +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); + } +}