From adb4493886fadec4f98f6b20c0d0d93580b22ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 9 Dec 2015 08:14:29 +0100 Subject: [PATCH 1/6] [PropertyInfo] Cache support --- .../PropertyInfo/PropertyInfoExtractor.php | 34 +++++++++++++++++-- .../Tests/PropertyInfoExtractorTest.php | 10 ++++++ .../Component/PropertyInfo/composer.json | 4 ++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php index 942318af605d8..1cb960ab66945 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php @@ -11,6 +11,8 @@ namespace Symfony\Component\PropertyInfo; +use Doctrine\Common\Cache\Cache; + /** * Default {@see PropertyInfoExtractorInterface} implementation. * @@ -38,18 +40,30 @@ class PropertyInfoExtractor implements PropertyInfoExtractorInterface */ private $accessExtractors; + /** + * @var Cache + */ + private $cache; + + /** + * @var array + */ + private $arrayCache = array(); + /** * @param PropertyListExtractorInterface[] $listExtractors * @param PropertyTypeExtractorInterface[] $typeExtractors * @param PropertyDescriptionExtractorInterface[] $descriptionExtractors * @param PropertyAccessExtractorInterface[] $accessExtractors + * @param Cache|null $cache */ - public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) + public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array(), Cache $cache = null) { $this->listExtractors = $listExtractors; $this->typeExtractors = $typeExtractors; $this->descriptionExtractors = $descriptionExtractors; $this->accessExtractors = $accessExtractors; + $this->cache = $cache; } /** @@ -111,11 +125,27 @@ public function isWritable($class, $property, array $context = array()) */ private function extract(array $extractors, $method, array $arguments) { + $key = $method.serialize($arguments); + + if (isset($this->arrayCache[$key])) { + return $this->arrayCache[$key]; + } + + if ($this->cache && $value = $this->cache->fetch($key)) { + return $this->arrayCache[$key] = $value; + } + foreach ($extractors as $extractor) { $value = call_user_func_array(array($extractor, $method), $arguments); if (null !== $value) { - return $value; + break; } } + + if ($this->cache) { + $this->cache->save($key, $value); + } + + return $this->arrayCache[$key] = $value; } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php index c7375d3006e0b..844fb7ba83d5d 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\PropertyInfo\Tests; +use Doctrine\Common\Cache\ArrayCache; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\NullExtractor; @@ -69,4 +70,13 @@ public function testGetProperties() { $this->assertEquals(array('a', 'b'), $this->propertyInfo->getProperties('Foo')); } + + public function testCache() + { + $extractors = array(new NullExtractor(), new DummyExtractor()); + $this->propertyInfo = new PropertyInfoExtractor($extractors, $extractors, $extractors, $extractors, new ArrayCache()); + + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + } } diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index b730caad9cf31..4a34abb5eb33c 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -28,12 +28,14 @@ "require-dev": { "symfony/serializer": "~2.8|~3.0", "phpdocumentor/reflection": "^1.0.7", - "doctrine/annotations": "~1.0" + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0" }, "conflict": { "phpdocumentor/reflection": "<1.0.7" }, "suggest": { + "doctrine/cache": "To cache results", "symfony/doctrine-bridge": "To use Doctrine metadata", "phpdocumentor/reflection": "To use the PHPDoc", "symfony/serializer": "To use Serializer metadata" From 6cc44455fbf792f71dbcb2afe308066025f4dfef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 9 Dec 2015 22:17:46 +0100 Subject: [PATCH 2/6] [PropertyInfo] Cache Decorator --- .../PropertyInfo/PropertyInfoExtractor.php | 34 +---- .../PropertyInfoExtractorCacheDecorator.php | 117 ++++++++++++++++++ .../AbstractPropertyInfoExtractorTest.php | 72 +++++++++++ .../Extractors/SerializerExtractorTest.php | 2 +- ...ropertyInfoExtractorCacheDecoratorTest.php | 34 +++++ .../Tests/PropertyInfoExtractorTest.php | 65 +--------- 6 files changed, 227 insertions(+), 97 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php index 1cb960ab66945..942318af605d8 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php @@ -11,8 +11,6 @@ namespace Symfony\Component\PropertyInfo; -use Doctrine\Common\Cache\Cache; - /** * Default {@see PropertyInfoExtractorInterface} implementation. * @@ -40,30 +38,18 @@ class PropertyInfoExtractor implements PropertyInfoExtractorInterface */ private $accessExtractors; - /** - * @var Cache - */ - private $cache; - - /** - * @var array - */ - private $arrayCache = array(); - /** * @param PropertyListExtractorInterface[] $listExtractors * @param PropertyTypeExtractorInterface[] $typeExtractors * @param PropertyDescriptionExtractorInterface[] $descriptionExtractors * @param PropertyAccessExtractorInterface[] $accessExtractors - * @param Cache|null $cache */ - public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array(), Cache $cache = null) + public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) { $this->listExtractors = $listExtractors; $this->typeExtractors = $typeExtractors; $this->descriptionExtractors = $descriptionExtractors; $this->accessExtractors = $accessExtractors; - $this->cache = $cache; } /** @@ -125,27 +111,11 @@ public function isWritable($class, $property, array $context = array()) */ private function extract(array $extractors, $method, array $arguments) { - $key = $method.serialize($arguments); - - if (isset($this->arrayCache[$key])) { - return $this->arrayCache[$key]; - } - - if ($this->cache && $value = $this->cache->fetch($key)) { - return $this->arrayCache[$key] = $value; - } - foreach ($extractors as $extractor) { $value = call_user_func_array(array($extractor, $method), $arguments); if (null !== $value) { - break; + return $value; } } - - if ($this->cache) { - $this->cache->save($key, $value); - } - - return $this->arrayCache[$key] = $value; } } diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php new file mode 100644 index 0000000000000..0b75940fce12a --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +use Doctrine\Common\Cache\Cache; + +/** + * Adds a cache layer on top of an extractor. + * + * @author Kévin Dunglas + */ +class PropertyInfoExtractorCacheDecorator implements PropertyInfoExtractorInterface +{ + /** + * @var PropertyInfoExtractorInterface + */ + private $propertyInfoExtractor; + + /** + * @var Cache + */ + private $cache; + + /** + * @var array + */ + private $arrayCache = array(); + + public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, Cache $cache) + { + $this->propertyInfoExtractor = $propertyInfoExtractor; + $this->cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function isReadable($class, $property, array $context = array()) + { + return $this->extract('isReadable', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function isWritable($class, $property, array $context = array()) + { + return $this->extract('isWritable', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function getShortDescription($class, $property, array $context = array()) + { + return $this->extract('getShortDescription', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function getLongDescription($class, $property, array $context = array()) + { + return $this->extract('getLongDescription', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + return $this->extract('getProperties', array($class, $context)); + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + return $this->extract('getTypes', array($class, $context)); + } + + /** + * Retrieves the cached data if applicable or delegates to the decorated extractor. + * + * @param string $method + * @param array $arguments + * + * @return mixed + */ + private function extract($method, array $arguments) + { + $key = $method.serialize($arguments); + + if (isset($this->arrayCache[$key])) { + return $this->arrayCache[$key]; + } + + if ($value = $this->cache->fetch($key)) { + return $this->arrayCache[$key] = $value; + } + + $value = call_user_func_array(array($this->propertyInfoExtractor, $method), $arguments); + $this->cache->save($key, $value); + + return $this->arrayCache[$key] = $value; + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php new file mode 100644 index 0000000000000..dd65e308781eb --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests; + +use Symfony\Component\PropertyInfo\PropertyInfoExtractor; +use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; +use Symfony\Component\PropertyInfo\Tests\Fixtures\NullExtractor; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class AbstractPropertyInfoExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var PropertyInfoExtractor + */ + protected $propertyInfo; + + public function setUp() + { + $extractors = array(new NullExtractor(), new DummyExtractor()); + $this->propertyInfo = new PropertyInfoExtractor($extractors, $extractors, $extractors, $extractors); + } + + public function testInstanceOf() + { + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface', $this->propertyInfo); + } + + public function testGetShortDescription() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + } + + public function testGetLongDescription() + { + $this->assertSame('long', $this->propertyInfo->getLongDescription('Foo', 'bar', array())); + } + + public function testGetTypes() + { + $this->assertEquals(array(new Type(Type::BUILTIN_TYPE_INT)), $this->propertyInfo->getTypes('Foo', 'bar', array())); + } + + public function testIsReadable() + { + $this->assertTrue($this->propertyInfo->isReadable('Foo', 'bar', array())); + } + + public function testIsWritable() + { + $this->assertTrue($this->propertyInfo->isWritable('Foo', 'bar', array())); + } + + public function testGetProperties() + { + $this->assertEquals(array('a', 'b'), $this->propertyInfo->getProperties('Foo')); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php index c170f2237add9..267dd21a11db5 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\PropertyInfo\PropertyInfo\Tests\Extractors; +namespace Symfony\Component\PropertyInfo\Tests\Extractors; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor; diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php new file mode 100644 index 0000000000000..0112dde217141 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests; + +use Doctrine\Common\Cache\ArrayCache; +use Symfony\Component\PropertyInfo\PropertyInfoExtractorCacheDecorator; + +/** + * @author Kévin Dunglas + */ +class PropertyInfoExtractorCacheDecoratorTest extends AbstractPropertyInfoExtractorTest +{ + public function setUp() + { + parent::setUp(); + + $this->propertyInfo = new PropertyInfoExtractorCacheDecorator($this->propertyInfo, new ArrayCache()); + } + + public function testCache() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php index 844fb7ba83d5d..53c1b1d8a5c22 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php @@ -11,72 +11,9 @@ namespace Symfony\Component\PropertyInfo\Tests; -use Doctrine\Common\Cache\ArrayCache; -use Symfony\Component\PropertyInfo\PropertyInfoExtractor; -use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; -use Symfony\Component\PropertyInfo\Tests\Fixtures\NullExtractor; -use Symfony\Component\PropertyInfo\Type; - /** * @author Kévin Dunglas */ -class PropertyInfoExtractorTest extends \PHPUnit_Framework_TestCase +class PropertyInfoExtractorTest extends AbstractPropertyInfoExtractorTest { - /** - * @var PropertyInfoExtractor - */ - private $propertyInfo; - - public function setUp() - { - $extractors = array(new NullExtractor(), new DummyExtractor()); - $this->propertyInfo = new PropertyInfoExtractor($extractors, $extractors, $extractors, $extractors); - } - - public function testInstanceOf() - { - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface', $this->propertyInfo); - } - - public function testGetShortDescription() - { - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); - } - - public function testGetLongDescription() - { - $this->assertSame('long', $this->propertyInfo->getLongDescription('Foo', 'bar', array())); - } - - public function testGetTypes() - { - $this->assertEquals(array(new Type(Type::BUILTIN_TYPE_INT)), $this->propertyInfo->getTypes('Foo', 'bar', array())); - } - - public function testIsReadable() - { - $this->assertTrue($this->propertyInfo->isReadable('Foo', 'bar', array())); - } - - public function testIsWritable() - { - $this->assertTrue($this->propertyInfo->isWritable('Foo', 'bar', array())); - } - - public function testGetProperties() - { - $this->assertEquals(array('a', 'b'), $this->propertyInfo->getProperties('Foo')); - } - - public function testCache() - { - $extractors = array(new NullExtractor(), new DummyExtractor()); - $this->propertyInfo = new PropertyInfoExtractor($extractors, $extractors, $extractors, $extractors, new ArrayCache()); - - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); - } } From 681bc86f47c8eb221c98c1cc53b6513dd5529559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 31 Dec 2015 11:30:57 +0100 Subject: [PATCH 3/6] [PropertyInfo] Deal with not serializable context --- .../PropertyInfo/PropertyInfoExtractorCacheDecorator.php | 9 ++++++++- .../Tests/PropertyInfoExtractorCacheDecoratorTest.php | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php index 0b75940fce12a..479954b008f67 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php @@ -99,7 +99,14 @@ public function getTypes($class, $property, array $context = array()) */ private function extract($method, array $arguments) { - $key = $method.serialize($arguments); + try { + $serializedArguments = serialize($arguments); + } catch (\Exception $exception) { + // If arguments are not serializable, skip the cache + return call_user_func_array(array($this->propertyInfoExtractor, $method), $arguments); + } + + $key = $method.$serializedArguments; if (isset($this->arrayCache[$key])) { return $this->arrayCache[$key]; diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php index 0112dde217141..213242aef3e8d 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php @@ -31,4 +31,9 @@ public function testCache() $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); } + + public function testNotSerializableContext() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array('foo' => function () {}))); + } } From 40081309ab0dbc62c1bcb08b8f31c16ff3324137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 26 Jan 2016 12:16:37 +0100 Subject: [PATCH 4/6] wip --- ...tor.php => PropertyInfoCacheExtractor.php} | 29 ++++++---- .../Tests/PropertyInfoCacheExtractorTest.php | 53 +++++++++++++++++++ ...ropertyInfoExtractorCacheDecoratorTest.php | 39 -------------- 3 files changed, 72 insertions(+), 49 deletions(-) rename src/Symfony/Component/PropertyInfo/{PropertyInfoExtractorCacheDecorator.php => PropertyInfoCacheExtractor.php} (78%) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php delete mode 100644 src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php similarity index 78% rename from src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php rename to src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php index 479954b008f67..46979e2104009 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorCacheDecorator.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php @@ -11,14 +11,14 @@ namespace Symfony\Component\PropertyInfo; -use Doctrine\Common\Cache\Cache; +use Psr\Cache\CacheItemPoolInterface; /** - * Adds a cache layer on top of an extractor. + * Adds a PSR-6 cache layer on top of an extractor. * * @author Kévin Dunglas */ -class PropertyInfoExtractorCacheDecorator implements PropertyInfoExtractorInterface +class PropertyInfoCacheExtractor implements PropertyInfoExtractorInterface { /** * @var PropertyInfoExtractorInterface @@ -26,19 +26,19 @@ class PropertyInfoExtractorCacheDecorator implements PropertyInfoExtractorInterf private $propertyInfoExtractor; /** - * @var Cache + * @var CacheItemPoolInterface */ - private $cache; + private $cacheItemPool; /** * @var array */ private $arrayCache = array(); - public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, Cache $cache) + public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, CacheItemPoolInterface $cacheItemPool) { $this->propertyInfoExtractor = $propertyInfoExtractor; - $this->cache = $cache; + $this->cacheItemPool = $cacheItemPool; } /** @@ -106,19 +106,28 @@ private function extract($method, array $arguments) return call_user_func_array(array($this->propertyInfoExtractor, $method), $arguments); } - $key = $method.$serializedArguments; + $key = $this->escape($method.'.'.$serializedArguments); if (isset($this->arrayCache[$key])) { return $this->arrayCache[$key]; } - if ($value = $this->cache->fetch($key)) { + if ($value = $this->cacheItemPool->getItem($key)) { return $this->arrayCache[$key] = $value; } $value = call_user_func_array(array($this->propertyInfoExtractor, $method), $arguments); - $this->cache->save($key, $value); + $this->cacheItemPool->save($key, $value); return $this->arrayCache[$key] = $value; } + + private function escape($key) + { + str_replace( + array('_', '{', '}', '(', ')', '/', '\\', '@', ':'), + array('_95', '_123', '_125', '_40', '_41', '_47', '_92', '_64', '_58'), + $key + ); + } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php new file mode 100644 index 0000000000000..9c0c6b62c1931 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests; + +use Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor; + +/** + * @author Kévin Dunglas + */ +class PropertyInfoCacheExtractorTest extends AbstractPropertyInfoExtractorTest +{ + public function setUp() + { + parent::setUp(); + + $this->propertyInfo = new PropertyInfoCacheExtractor($this->propertyInfo, new ArrayCac); + } + + public function testCache() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + } + + public function testNotSerializableContext() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array('foo' => function () {}))); + } + + public function testEscape() + { + $reflectionMethod = new \ReflectionMethod($this->propertyInfo, 'escape'); + $reflectionMethod->setAccessible(true); + + $this->assertSame('foo_bar', $this->propertyInfo->escape('foo_95bar')); + $this->assertSame('foo_95bar', $this->propertyInfo->escape('foo_9595bar')); + $this->assertSame('foo{bar}', $this->propertyInfo->escape('foo_123bar_125')); + $this->assertSame('foo(bar)', $this->propertyInfo->escape('foo_40bar_41')); + $this->assertSame('foo/bar', $this->propertyInfo->escape('foo_47bar')); + $this->assertSame('foo\bar', $this->propertyInfo->escape('foo_92bar')); + $this->assertSame('foo@bar', $this->propertyInfo->escape('foo_64bar')); + $this->assertSame('foo:bar', $this->propertyInfo->escape('foo_58bar')); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php deleted file mode 100644 index 213242aef3e8d..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorCacheDecoratorTest.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo\Tests; - -use Doctrine\Common\Cache\ArrayCache; -use Symfony\Component\PropertyInfo\PropertyInfoExtractorCacheDecorator; - -/** - * @author Kévin Dunglas - */ -class PropertyInfoExtractorCacheDecoratorTest extends AbstractPropertyInfoExtractorTest -{ - public function setUp() - { - parent::setUp(); - - $this->propertyInfo = new PropertyInfoExtractorCacheDecorator($this->propertyInfo, new ArrayCache()); - } - - public function testCache() - { - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); - } - - public function testNotSerializableContext() - { - $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array('foo' => function () {}))); - } -} From 9396a19843e4a793d4b91a9e3cf3851a4ebba3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 26 Jan 2016 13:05:31 +0100 Subject: [PATCH 5/6] [PropertyInfo] PSR-6 cache --- .../PropertyInfoCacheExtractor.php | 35 ++++++++++++++----- .../Tests/PropertyInfoCacheExtractorTest.php | 31 ++++++++++------ .../Component/PropertyInfo/composer.json | 6 ++-- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php index 46979e2104009..b7d5c6d372ca6 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php @@ -112,22 +112,41 @@ private function extract($method, array $arguments) return $this->arrayCache[$key]; } - if ($value = $this->cacheItemPool->getItem($key)) { - return $this->arrayCache[$key] = $value; + $item = $this->cacheItemPool->getItem($key); + + if ($item->isHit()) { + return $this->arrayCache[$key] = $item->get(); } $value = call_user_func_array(array($this->propertyInfoExtractor, $method), $arguments); - $this->cacheItemPool->save($key, $value); + $item->set($value); + $this->cacheItemPool->save($item); return $this->arrayCache[$key] = $value; } + /** + * Escapes a key according to PSR-6. + * + * Replaces characters forbidden by PSR-6 and the _ char by the _ char followed by the ASCII + * code of the escaped char. + * + * @param string $key + * + * @return string + */ private function escape($key) { - str_replace( - array('_', '{', '}', '(', ')', '/', '\\', '@', ':'), - array('_95', '_123', '_125', '_40', '_41', '_47', '_92', '_64', '_58'), - $key - ); + return strtr($key, array( + '{' => '_123', + '}' => '_125', + '(' => '_40', + ')' => '_41', + '/' => '_47', + '\\' => '_92', + '@' => '_64', + ':' => '_58', + '_' => '_95', + )); } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php index 9c0c6b62c1931..5f09fb041a986 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\PropertyInfo\Tests; +use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor; /** @@ -22,7 +23,7 @@ public function setUp() { parent::setUp(); - $this->propertyInfo = new PropertyInfoCacheExtractor($this->propertyInfo, new ArrayCac); + $this->propertyInfo = new PropertyInfoCacheExtractor($this->propertyInfo, new ArrayAdapter()); } public function testCache() @@ -36,18 +37,28 @@ public function testNotSerializableContext() $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array('foo' => function () {}))); } - public function testEscape() + /** + * @dataProvider escapeDataProvider + */ + public function testEscape($toEscape, $expected) { $reflectionMethod = new \ReflectionMethod($this->propertyInfo, 'escape'); $reflectionMethod->setAccessible(true); - $this->assertSame('foo_bar', $this->propertyInfo->escape('foo_95bar')); - $this->assertSame('foo_95bar', $this->propertyInfo->escape('foo_9595bar')); - $this->assertSame('foo{bar}', $this->propertyInfo->escape('foo_123bar_125')); - $this->assertSame('foo(bar)', $this->propertyInfo->escape('foo_40bar_41')); - $this->assertSame('foo/bar', $this->propertyInfo->escape('foo_47bar')); - $this->assertSame('foo\bar', $this->propertyInfo->escape('foo_92bar')); - $this->assertSame('foo@bar', $this->propertyInfo->escape('foo_64bar')); - $this->assertSame('foo:bar', $this->propertyInfo->escape('foo_58bar')); + $this->assertSame($expected, $reflectionMethod->invoke($this->propertyInfo, $toEscape)); + } + + public function escapeDataProvider() + { + return array( + array('foo_bar', 'foo_95bar'), + array('foo_95bar', 'foo_9595bar'), + array('foo{bar}', 'foo_123bar_125'), + array('foo(bar)', 'foo_40bar_41'), + array('foo/bar', 'foo_47bar'), + array('foo\bar', 'foo_92bar'), + array('foo@bar', 'foo_64bar'), + array('foo:bar', 'foo_58bar'), + ); } } diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index 4a34abb5eb33c..fa7c72b0d9f81 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -27,15 +27,15 @@ }, "require-dev": { "symfony/serializer": "~2.8|~3.0", + "symfony/cache": "~3.1", "phpdocumentor/reflection": "^1.0.7", - "doctrine/annotations": "~1.0", - "doctrine/cache": "~1.0" + "doctrine/annotations": "~1.0" }, "conflict": { "phpdocumentor/reflection": "<1.0.7" }, "suggest": { - "doctrine/cache": "To cache results", + "symfony/cache": "To cache results", "symfony/doctrine-bridge": "To use Doctrine metadata", "phpdocumentor/reflection": "To use the PHPDoc", "symfony/serializer": "To use Serializer metadata" From 43f344652705e010011382a9b092d85b8be1f5b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 26 Jan 2016 18:46:58 +0100 Subject: [PATCH 6/6] Replace symfony/cache by psr/cache-implementation in suggest --- src/Symfony/Component/PropertyInfo/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index fa7c72b0d9f81..b484a6fe3c626 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -35,7 +35,7 @@ "phpdocumentor/reflection": "<1.0.7" }, "suggest": { - "symfony/cache": "To cache results", + "psr/cache-implementation": "To cache results", "symfony/doctrine-bridge": "To use Doctrine metadata", "phpdocumentor/reflection": "To use the PHPDoc", "symfony/serializer": "To use Serializer metadata" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy