-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[2.2] [FrameworkBundle] [Serializer] Loads the Serializer component as a service in the Framework Bundle #5347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ca250b0
0b51471
7b791fe
fb1685c
881e9a6
0278df8
e579aac
91812e2
4d6fdc0
5e24f74
d164806
b343488
4ef485a
75d7ed9
8ccb530
299c03e
c6253ce
5fd4e90
1ddcba4
b46d4e9
377aa31
731a05e
627b69c
122ac5c
2fbd210
8cb0564
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* Adds all services with the tags "serializer.encoder" and "serializer.normalizer" as | ||
* encoders and normalizers to the Serializer service. | ||
* | ||
* @author Javier Lopez <f12loalf@gmail.com> | ||
*/ | ||
class SerializerPass implements CompilerPassInterface | ||
{ | ||
public function process(ContainerBuilder $container) | ||
{ | ||
if (!$container->hasDefinition('serializer')) { | ||
return; | ||
} | ||
|
||
// Looks for all the services tagged "serializer.normalizer" and adds them to the Serializer service | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you execute the whole same code twice maybe factorize it inside a loop or a method ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I´ve reduced the length of this code so I think there is no need to refactor it anymore. |
||
$normalizers = $this->findAndSortTaggedServices('serializer.normalizer', $container); | ||
$container->getDefinition('serializer')->replaceArgument(0, $normalizers); | ||
|
||
// Looks for all the services tagged "serializer.encoders" and adds them to the Serializer service | ||
$encoders = $this->findAndSortTaggedServices('serializer.encoder', $container); | ||
$container->getDefinition('serializer')->replaceArgument(1, $encoders); | ||
} | ||
|
||
private function findAndSortTaggedServices($tagName, ContainerBuilder $container) | ||
{ | ||
$services = $container->findTaggedServiceIds($tagName); | ||
|
||
if (empty($services)) { | ||
throw new \RuntimeException(sprintf('You must tag at least one service as "%s" to use the Serializer service', $tagName)); | ||
} | ||
|
||
$sortedServices = array(); | ||
foreach ($services as $serviceId => $tags) { | ||
foreach ($tags as $tag) { | ||
$priority = isset($tag['priority']) ? $tag['priority'] : 0; | ||
$sortedServices[$priority][] = new Reference($serviceId); | ||
} | ||
} | ||
|
||
krsort($sortedServices); | ||
|
||
// Flatten the array | ||
return call_user_func_array('array_merge', $sortedServices); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,6 +80,7 @@ public function getConfigTreeBuilder() | |
$this->addTranslatorSection($rootNode); | ||
$this->addValidationSection($rootNode); | ||
$this->addAnnotationsSection($rootNode); | ||
$this->addSerializerSection($rootNode); | ||
|
||
return $treeBuilder; | ||
} | ||
|
@@ -393,4 +394,17 @@ private function addAnnotationsSection(ArrayNodeDefinition $rootNode) | |
->end() | ||
; | ||
} | ||
|
||
private function addSerializerSection(ArrayNodeDefinition $rootNode) | ||
{ | ||
$rootNode | ||
->children() | ||
->arrayNode('serializer') | ||
->info('serializer configuration') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Serialized with a capital letter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the other "info" messages are lowercase, are you sure you want it to be capitalized? |
||
->canBeDisabled() | ||
->end() | ||
->end() | ||
; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This blank line should be removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't see a duplicate blank line cause there should be one blank line between "{" and "private ... ", shouldn't it? |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" ?> | ||
|
||
<container xmlns="http://symfony.com/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
|
||
<parameters> | ||
<parameter key="serializer.class">Symfony\Component\Serializer\Serializer</parameter> | ||
<parameter key="serializer.encoder.xml.class">Symfony\Component\Serializer\Encoder\XmlEncoder</parameter> | ||
<parameter key="serializer.encoder.json.class">Symfony\Component\Serializer\Encoder\JsonEncoder</parameter> | ||
|
||
<services> | ||
<service id="serializer" class="%serializer.class%" > | ||
<argument type="collection" /> | ||
<argument type="collection" /> | ||
</service> | ||
<!-- Encoders --> | ||
<service id="serializer.encoder.xml" class="%serializer.encoder.xml.class%" public="false" > | ||
<tag name="serializer.encoder" /> | ||
</service> | ||
<service id="serializer.encoder.json" class="%serializer.encoder.json.class%" public="false" > | ||
<tag name="serializer.encoder" /> | ||
</service> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Registering this one should be optional. The GetSetMethodNormalizer is broken (by design) as soon as you have a cyclic object graph (you have an infinite loop when calling getters), so forcing to register it is a bad idea (expecially as many people tend to use bidirectional relations in their entities apparently) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for this service, you should add the tag conditionally in the DI extension according to a configuration, to allow disabling it. and it should have a negative priority rather that a high priority IMO, so that custom normalizers registered with the default priority can be checked first (the GetSetNormalizer will accept any input) |
||
</services> | ||
</container> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?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\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass; | ||
|
||
/** | ||
* Tests for the SerializerPass class | ||
* | ||
* @author Javier Lopez <f12loalf@gmail.com> | ||
*/ | ||
class SerializerPassTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those blank lines should be removed |
||
public function testThrowExceptionWhenNoNormalizers() | ||
{ | ||
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); | ||
|
||
$container->expects($this->once()) | ||
->method('hasDefinition') | ||
->with('serializer') | ||
->will($this->returnValue(true)); | ||
|
||
$container->expects($this->once()) | ||
->method('findTaggedServiceIds') | ||
->with('serializer.normalizer') | ||
->will($this->returnValue(array())); | ||
|
||
$this->setExpectedException('RuntimeException'); | ||
|
||
$serializerPass = new SerializerPass(); | ||
$serializerPass->process($container); | ||
} | ||
|
||
public function testThrowExceptionWhenNoEncoders() | ||
{ | ||
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); | ||
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); | ||
|
||
$container->expects($this->once()) | ||
->method('hasDefinition') | ||
->with('serializer') | ||
->will($this->returnValue(true)); | ||
|
||
$container->expects($this->any()) | ||
->method('findTaggedServiceIds') | ||
->will($this->onConsecutiveCalls( | ||
array('n' => array('serializer.normalizer')), | ||
array() | ||
)); | ||
|
||
$container->expects($this->once()) | ||
->method('getDefinition') | ||
->will($this->returnValue($definition)); | ||
|
||
$this->setExpectedException('RuntimeException'); | ||
|
||
$serializerPass = new SerializerPass(); | ||
$serializerPass->process($container); | ||
} | ||
|
||
public function testServicesAreOrderedAccordingToPriority() | ||
{ | ||
$services = array( | ||
'n3' => array('tag' => array()), | ||
'n1' => array('tag' => array('priority' => 200)), | ||
'n2' => array('tag' => array('priority' => 100)) | ||
); | ||
|
||
$expected = array( | ||
new Reference('n1'), | ||
new Reference('n2'), | ||
new Reference('n3') | ||
); | ||
|
||
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); | ||
|
||
$container->expects($this->atLeastOnce()) | ||
->method('findTaggedServiceIds') | ||
->will($this->returnValue($services)); | ||
|
||
$serializerPass = new SerializerPass(); | ||
|
||
$method = new \ReflectionMethod( | ||
'Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass', | ||
'findAndSortTaggedServices' | ||
); | ||
$method->setAccessible(TRUE); | ||
|
||
$actual = $method->invoke($serializerPass, 'tag', $container); | ||
|
||
$this->assertEquals($expected, $actual); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line is needed here