Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cb16bff

Browse filesBrowse files
committed
feature #17446 [Serializer] Add PSR-6 adapter (dunglas)
This PR was squashed before being merged into the 3.1-dev branch (closes #17446). Discussion ---------- [Serializer] Add PSR-6 adapter | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | todo - [x] Add tests Commits ------- 4bf9d05 [Serializer] Add PSR-6 adapter
2 parents 127538e + 4bf9d05 commit cb16bff
Copy full SHA for cb16bff

File tree

6 files changed

+209
-35
lines changed
Filter options

6 files changed

+209
-35
lines changed
+68Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Mapping\Factory;
13+
14+
use Psr\Cache\CacheItemPoolInterface;
15+
16+
/**
17+
* Caches metadata using a PSR-6 implementation.
18+
*
19+
* @author Kévin Dunglas <dunglas@gmail.com>
20+
*/
21+
class CacheClassMetadataFactory implements ClassMetadataFactoryInterface
22+
{
23+
use ClassResolverTrait;
24+
25+
/**
26+
* @var ClassMetadataFactoryInterface
27+
*/
28+
private $decorated;
29+
30+
/**
31+
* @var CacheItemPoolInterface
32+
*/
33+
private $cacheItemPool;
34+
35+
public function __construct(ClassMetadataFactoryInterface $decorated, CacheItemPoolInterface $cacheItemPool)
36+
{
37+
$this->decorated = $decorated;
38+
$this->cacheItemPool = $cacheItemPool;
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function getMetadataFor($value)
45+
{
46+
$class = $this->getClass($value);
47+
// Key cannot contain backslashes according to PSR-6
48+
$key = strtr($class, '\\', '_');
49+
50+
$item = $this->cacheItemPool->getItem($key);
51+
if ($item->isHit()) {
52+
return $item->get();
53+
}
54+
55+
$metadata = $this->decorated->getMetadataFor($value);
56+
$this->cacheItemPool->save($item->set($metadata));
57+
58+
return $metadata;
59+
}
60+
61+
/**
62+
* {@inheritdoc}
63+
*/
64+
public function hasMetadataFor($value)
65+
{
66+
return $this->decorated->hasMetadataFor($value);
67+
}
68+
}

‎src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php
+12-23Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*/
2424
class ClassMetadataFactory implements ClassMetadataFactoryInterface
2525
{
26+
use ClassResolverTrait;
27+
2628
/**
2729
* @var LoaderInterface
2830
*/
@@ -44,6 +46,10 @@ public function __construct(LoaderInterface $loader, Cache $cache = null)
4446
{
4547
$this->loader = $loader;
4648
$this->cache = $cache;
49+
50+
if (null !== $cache) {
51+
@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+
}
4753
}
4854

4955
/**
@@ -52,9 +58,6 @@ public function __construct(LoaderInterface $loader, Cache $cache = null)
5258
public function getMetadataFor($value)
5359
{
5460
$class = $this->getClass($value);
55-
if (!$class) {
56-
throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value)));
57-
}
5861

5962
if (isset($this->loadedClasses[$class])) {
6063
return $this->loadedClasses[$class];
@@ -64,10 +67,6 @@ public function getMetadataFor($value)
6467
return $this->loadedClasses[$class];
6568
}
6669

67-
if (!class_exists($class) && !interface_exists($class)) {
68-
throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $class));
69-
}
70-
7170
$classMetadata = new ClassMetadata($class);
7271
$this->loader->loadClassMetadata($classMetadata);
7372

@@ -95,24 +94,14 @@ public function getMetadataFor($value)
9594
*/
9695
public function hasMetadataFor($value)
9796
{
98-
$class = $this->getClass($value);
99-
100-
return class_exists($class) || interface_exists($class);
101-
}
97+
try {
98+
$this->getClass($value);
10299

103-
/**
104-
* Gets a class name for a given class or instance.
105-
*
106-
* @param mixed $value
107-
*
108-
* @return string|bool
109-
*/
110-
private function getClass($value)
111-
{
112-
if (!is_object($value) && !is_string($value)) {
113-
return false;
100+
return true;
101+
} catch (InvalidArgumentException $invalidArgumentException) {
102+
// Return false in case of exception
114103
}
115104

116-
return ltrim(is_object($value) ? get_class($value) : $value, '\\');
105+
return false;
117106
}
118107
}
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Mapping\Factory;
13+
14+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
15+
16+
/**
17+
* Resolves a class name.
18+
*
19+
* @internal
20+
*
21+
* @author Kévin Dunglas <dunglas@gmail.com>
22+
*/
23+
trait ClassResolverTrait
24+
{
25+
/**
26+
* Gets a class name for a given class or instance.
27+
*
28+
* @param mixed $value
29+
*
30+
* @return string
31+
*
32+
* @throws InvalidArgumentException If the class does not exists
33+
*/
34+
private function getClass($value)
35+
{
36+
if (is_string($value)) {
37+
if (!class_exists($value) && !interface_exists($value)) {
38+
throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $value));
39+
}
40+
41+
return ltrim($value, '\\');
42+
}
43+
44+
if (!is_object($value)) {
45+
throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value)));
46+
}
47+
48+
return get_class($value);
49+
}
50+
}
+65Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Mapping\Factory;
13+
14+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
15+
use Symfony\Component\Serializer\Mapping\ClassMetadata;
16+
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
17+
18+
/**
19+
* @author Kévin Dunglas <dunglas@gmail.com>
20+
*/
21+
class CacheMetadataFactoryTest extends \PHPUnit_Framework_TestCase
22+
{
23+
public function testGetMetadataFor()
24+
{
25+
$metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\Dummy');
26+
27+
$decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface');
28+
$decorated
29+
->expects($this->once())
30+
->method('getMetadataFor')
31+
->will($this->returnValue($metadata))
32+
;
33+
34+
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
35+
36+
$this->assertEquals($metadata, $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy'));
37+
// The second call should retrieve the value from the cache
38+
$this->assertEquals($metadata, $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy'));
39+
}
40+
41+
public function testHasMetadataFor()
42+
{
43+
$decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface');
44+
$decorated
45+
->expects($this->once())
46+
->method('hasMetadataFor')
47+
->will($this->returnValue(true))
48+
;
49+
50+
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
51+
52+
$this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\Dummy'));
53+
}
54+
55+
/**
56+
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
57+
*/
58+
public function testInvalidClassThrowsException()
59+
{
60+
$decorated = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface');
61+
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
62+
63+
$factory->getMetadataFor('Not\Exist');
64+
}
65+
}

‎src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php
+9-9Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase
2525
public function testInterface()
2626
{
2727
$classMetadata = new ClassMetadataFactory(new LoaderChain(array()));
28-
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', $classMetadata);
28+
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface', $classMetadata);
2929
}
3030

3131
public function testGetMetadataFor()
@@ -45,6 +45,9 @@ public function testHasMetadataFor()
4545
$this->assertFalse($factory->hasMetadataFor('Dunglas\Entity'));
4646
}
4747

48+
/**
49+
* @group legacy
50+
*/
4851
public function testCacheExists()
4952
{
5053
$cache = $this->getMock('Doctrine\Common\Cache\Cache');
@@ -58,17 +61,14 @@ public function testCacheExists()
5861
$this->assertEquals('foo', $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'));
5962
}
6063

64+
/**
65+
* @group legacy
66+
*/
6167
public function testCacheNotExists()
6268
{
6369
$cache = $this->getMock('Doctrine\Common\Cache\Cache');
64-
$cache
65-
->method('fetch')
66-
->will($this->returnValue(false))
67-
;
68-
69-
$cache
70-
->method('save')
71-
;
70+
$cache->method('fetch')->will($this->returnValue(false));
71+
$cache->method('save');
7272

7373
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache);
7474
$metadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');

‎src/Symfony/Component/Serializer/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/composer.json
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,18 @@
2323
"symfony/config": "~2.8|~3.0",
2424
"symfony/property-access": "~2.8|~3.0",
2525
"symfony/http-foundation": "~2.8|~3.0",
26+
"symfony/cache": "~3.1",
2627
"doctrine/annotations": "~1.0",
2728
"doctrine/cache": "~1.0"
2829
},
2930
"suggest": {
30-
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
31-
"doctrine/cache": "For using the default cached annotation reader and metadata cache.",
31+
"psr/cache-implementation": "For using the metadata cache.",
3232
"symfony/yaml": "For using the default YAML mapping loader.",
3333
"symfony/config": "For using the XML mapping loader.",
3434
"symfony/property-access": "For using the ObjectNormalizer.",
35-
"symfony/http-foundation": "To use the DataUriNormalizer."
35+
"symfony/http-foundation": "To use the DataUriNormalizer.",
36+
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
37+
"doctrine/cache": "For using the default cached annotation reader and metadata cache."
3638
},
3739
"autoload": {
3840
"psr-4": { "Symfony\\Component\\Serializer\\": "" },

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.