diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/CacheClassMetadataFactory.php b/src/Symfony/Component/Serializer/Mapping/Factory/CacheClassMetadataFactory.php new file mode 100644 index 0000000000000..0b904c14400d0 --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/Factory/CacheClassMetadataFactory.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Factory; + +use Psr\Cache\CacheItemPoolInterface; + +/** + * Caches metadata using a PSR-6 implementation. + * + * @author Kévin Dunglas + */ +class CacheClassMetadataFactory implements ClassMetadataFactoryInterface +{ + use ClassResolverTrait; + + /** + * @var ClassMetadataFactoryInterface + */ + private $decorated; + + /** + * @var CacheItemPoolInterface + */ + private $cacheItemPool; + + public function __construct(ClassMetadataFactoryInterface $decorated, CacheItemPoolInterface $cacheItemPool) + { + $this->decorated = $decorated; + $this->cacheItemPool = $cacheItemPool; + } + + /** + * {@inheritdoc} + */ + public function getMetadataFor($value) + { + $class = $this->getClass($value); + // Key cannot contain backslashes according to PSR-6 + $key = strtr($class, '\\', '_'); + + $item = $this->cacheItemPool->getItem($key); + if ($item->isHit()) { + return $item->get(); + } + + $metadata = $this->decorated->getMetadataFor($value); + $this->cacheItemPool->save($item->set($metadata)); + + return $metadata; + } + + /** + * {@inheritdoc} + */ + public function hasMetadataFor($value) + { + return $this->decorated->hasMetadataFor($value); + } +} diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php index 3a354e354e9e3..00e214fe03d89 100644 --- a/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php +++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php @@ -23,6 +23,8 @@ */ class ClassMetadataFactory implements ClassMetadataFactoryInterface { + use ClassResolverTrait; + /** * @var LoaderInterface */ @@ -44,6 +46,10 @@ public function __construct(LoaderInterface $loader, Cache $cache = null) { $this->loader = $loader; $this->cache = $cache; + + if (null !== $cache) { + @trigger_error(sprintf('Passing a Doctrine Cache instance as 2nd parameter of the "%s" constructor is deprecated. This parameter will be removed in Symfony 4.0. Use the "%s" class instead.', __CLASS__, CacheClassMetadataFactory::class), E_USER_DEPRECATED); + } } /** @@ -52,9 +58,6 @@ public function __construct(LoaderInterface $loader, Cache $cache = null) public function getMetadataFor($value) { $class = $this->getClass($value); - if (!$class) { - throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value))); - } if (isset($this->loadedClasses[$class])) { return $this->loadedClasses[$class]; @@ -64,10 +67,6 @@ public function getMetadataFor($value) return $this->loadedClasses[$class]; } - if (!class_exists($class) && !interface_exists($class)) { - throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $class)); - } - $classMetadata = new ClassMetadata($class); $this->loader->loadClassMetadata($classMetadata); @@ -95,24 +94,14 @@ public function getMetadataFor($value) */ public function hasMetadataFor($value) { - $class = $this->getClass($value); - - return class_exists($class) || interface_exists($class); - } + try { + $this->getClass($value); - /** - * Gets a class name for a given class or instance. - * - * @param mixed $value - * - * @return string|bool - */ - private function getClass($value) - { - if (!is_object($value) && !is_string($value)) { - return false; + return true; + } catch (InvalidArgumentException $invalidArgumentException) { + // Return false in case of exception } - return ltrim(is_object($value) ? get_class($value) : $value, '\\'); + return false; } } diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php new file mode 100644 index 0000000000000..e93277a6be765 --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Factory; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * Resolves a class name. + * + * @internal + * + * @author Kévin Dunglas + */ +trait ClassResolverTrait +{ + /** + * Gets a class name for a given class or instance. + * + * @param mixed $value + * + * @return string + * + * @throws InvalidArgumentException If the class does not exists + */ + private function getClass($value) + { + if (is_string($value)) { + if (!class_exists($value) && !interface_exists($value)) { + throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $value)); + } + + return ltrim($value, '\\'); + } + + if (!is_object($value)) { + throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value))); + } + + return get_class($value); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Factory/CacheMetadataFactoryTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/CacheMetadataFactoryTest.php new file mode 100644 index 0000000000000..a42003f358906 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/CacheMetadataFactoryTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping\Factory; + +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory; + +/** + * @author Kévin Dunglas + */ +class CacheMetadataFactoryTest extends \PHPUnit_Framework_TestCase +{ + public function testGetMetadataFor() + { + $metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\Dummy'); + + $decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface'); + $decorated + ->expects($this->once()) + ->method('getMetadataFor') + ->will($this->returnValue($metadata)) + ; + + $factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter()); + + $this->assertEquals($metadata, $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy')); + // The second call should retrieve the value from the cache + $this->assertEquals($metadata, $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy')); + } + + public function testHasMetadataFor() + { + $decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface'); + $decorated + ->expects($this->once()) + ->method('hasMetadataFor') + ->will($this->returnValue(true)) + ; + + $factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter()); + + $this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy')); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException + */ + public function testInvalidClassThrowsException() + { + $decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface'); + $factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter()); + + $factory->getMetadataFor('Not\Exist'); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php index 2e2ba22dcee0b..a237c32313b12 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php @@ -25,7 +25,7 @@ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase public function testInterface() { $classMetadata = new ClassMetadataFactory(new LoaderChain(array())); - $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', $classMetadata); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface', $classMetadata); } public function testGetMetadataFor() @@ -45,6 +45,9 @@ public function testHasMetadataFor() $this->assertFalse($factory->hasMetadataFor('Dunglas\Entity')); } + /** + * @group legacy + */ public function testCacheExists() { $cache = $this->getMock('Doctrine\Common\Cache\Cache'); @@ -58,17 +61,14 @@ public function testCacheExists() $this->assertEquals('foo', $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy')); } + /** + * @group legacy + */ public function testCacheNotExists() { $cache = $this->getMock('Doctrine\Common\Cache\Cache'); - $cache - ->method('fetch') - ->will($this->returnValue(false)) - ; - - $cache - ->method('save') - ; + $cache->method('fetch')->will($this->returnValue(false)); + $cache->method('save'); $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache); $metadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index acec92f24eb21..f17da4d2aafc0 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -23,16 +23,18 @@ "symfony/config": "~2.8|~3.0", "symfony/property-access": "~2.8|~3.0", "symfony/http-foundation": "~2.8|~3.0", + "symfony/cache": "~3.1", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0" }, "suggest": { - "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", - "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "psr/cache-implementation": "For using the metadata cache.", "symfony/yaml": "For using the default YAML mapping loader.", "symfony/config": "For using the XML mapping loader.", "symfony/property-access": "For using the ObjectNormalizer.", - "symfony/http-foundation": "To use the DataUriNormalizer." + "symfony/http-foundation": "To use the DataUriNormalizer.", + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache." }, "autoload": { "psr-4": { "Symfony\\Component\\Serializer\\": "" }, 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