Skip to content

Commit 98f30b0

Browse files
committed
Add the serializer service
1 parent 64763da commit 98f30b0

File tree

8 files changed

+216
-0
lines changed

8 files changed

+216
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
2.3.0
55
-----
66

7+
* added possibility to load the serializer component in the service container
78
* added route debug information when using the `router:match` command
89
* added `TimedPhpEngine`
910
* added `--clean` option the the `translation:update` command
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
use Symfony\Component\DependencyInjection\Reference;
17+
18+
/**
19+
* Adds all services with the tags "serializer.encoder" and "serializer.normalizer" as
20+
* encoders and normalizers to the Serializer service.
21+
*
22+
* @author Javier Lopez <[email protected]>
23+
*/
24+
class SerializerPass implements CompilerPassInterface
25+
{
26+
public function process(ContainerBuilder $container)
27+
{
28+
if (!$container->hasDefinition('serializer')) {
29+
return;
30+
}
31+
32+
// Looks for all the services tagged "serializer.normalizer" and adds them to the Serializer service
33+
$normalizers = $this->findAndSortTaggedServices('serializer.normalizer', $container);
34+
$container->getDefinition('serializer')->replaceArgument(0, $normalizers);
35+
36+
// Looks for all the services tagged "serializer.encoders" and adds them to the Serializer service
37+
$encoders = $this->findAndSortTaggedServices('serializer.encoder', $container);
38+
$container->getDefinition('serializer')->replaceArgument(1, $encoders);
39+
}
40+
41+
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
42+
{
43+
$services = $container->findTaggedServiceIds($tagName);
44+
45+
if (empty($services)) {
46+
throw new \RuntimeException(sprintf('You must tag at least one service as "%s" to use the Serializer service', $tagName));
47+
}
48+
49+
$sortedServices = array();
50+
foreach ($services as $serviceId => $tags) {
51+
foreach ($tags as $tag) {
52+
$priority = isset($tag['priority']) ? $tag['priority'] : 0;
53+
$sortedServices[$priority][] = new Reference($serviceId);
54+
}
55+
}
56+
57+
krsort($sortedServices);
58+
59+
// Flatten the array
60+
return call_user_func_array('array_merge', $sortedServices);
61+
}
62+
}

DependencyInjection/Configuration.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public function getConfigTreeBuilder()
6767
$this->addTranslatorSection($rootNode);
6868
$this->addValidationSection($rootNode);
6969
$this->addAnnotationsSection($rootNode);
70+
$this->addSerializerSection($rootNode);
7071

7172
return $treeBuilder;
7273
}
@@ -382,4 +383,16 @@ private function addAnnotationsSection(ArrayNodeDefinition $rootNode)
382383
->end()
383384
;
384385
}
386+
387+
private function addSerializerSection(ArrayNodeDefinition $rootNode)
388+
{
389+
$rootNode
390+
->children()
391+
->arrayNode('serializer')
392+
->info('serializer configuration')
393+
->canBeEnabled()
394+
->end()
395+
->end()
396+
;
397+
}
385398
}

DependencyInjection/FrameworkExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ public function load(array $configs, ContainerBuilder $container)
100100

101101
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
102102

103+
if (isset($config['serializer']) && $config['serializer']['enabled']) {
104+
$loader->load('serializer.xml');
105+
}
106+
103107
$this->addClassesToCompile(array(
104108
'Symfony\\Component\\HttpFoundation\\ParameterBag',
105109
'Symfony\\Component\\HttpFoundation\\HeaderBag',

FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass;
2727
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass;
2828
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FragmentRendererPass;
29+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass;
2930
use Symfony\Component\DependencyInjection\ContainerBuilder;
3031
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
3132
use Symfony\Component\HttpFoundation\Request;
@@ -66,6 +67,7 @@ public function build(ContainerBuilder $container)
6667
$container->addCompilerPass(new TranslationExtractorPass());
6768
$container->addCompilerPass(new TranslationDumperPass());
6869
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
70+
$container->addCompilerPass(new SerializerPass());
6971

7072
if ($container->getParameter('kernel.debug')) {
7173
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);

Resources/config/serializer.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<parameters>
8+
<parameter key="serializer.class">Symfony\Component\Serializer\Serializer</parameter>
9+
<parameter key="serializer.encoder.xml.class">Symfony\Component\Serializer\Encoder\XmlEncoder</parameter>
10+
<parameter key="serializer.encoder.json.class">Symfony\Component\Serializer\Encoder\JsonEncoder</parameter>
11+
</parameters>
12+
13+
<services>
14+
<service id="serializer" class="%serializer.class%" >
15+
<argument type="collection" />
16+
<argument type="collection" />
17+
</service>
18+
<!-- Encoders -->
19+
<service id="serializer.encoder.xml" class="%serializer.encoder.xml.class%" public="false" >
20+
<tag name="serializer.encoder" />
21+
</service>
22+
<service id="serializer.encoder.json" class="%serializer.encoder.json.class%" public="false" >
23+
<tag name="serializer.encoder" />
24+
</service>
25+
</services>
26+
</container>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Reference;
16+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass;
17+
18+
/**
19+
* Tests for the SerializerPass class
20+
*
21+
* @author Javier Lopez <[email protected]>
22+
*/
23+
class SerializerPassTest extends \PHPUnit_Framework_TestCase
24+
{
25+
26+
public function testThrowExceptionWhenNoNormalizers()
27+
{
28+
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
29+
30+
$container->expects($this->once())
31+
->method('hasDefinition')
32+
->with('serializer')
33+
->will($this->returnValue(true));
34+
35+
$container->expects($this->once())
36+
->method('findTaggedServiceIds')
37+
->with('serializer.normalizer')
38+
->will($this->returnValue(array()));
39+
40+
$this->setExpectedException('RuntimeException');
41+
42+
$serializerPass = new SerializerPass();
43+
$serializerPass->process($container);
44+
}
45+
46+
public function testThrowExceptionWhenNoEncoders()
47+
{
48+
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
49+
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
50+
51+
$container->expects($this->once())
52+
->method('hasDefinition')
53+
->with('serializer')
54+
->will($this->returnValue(true));
55+
56+
$container->expects($this->any())
57+
->method('findTaggedServiceIds')
58+
->will($this->onConsecutiveCalls(
59+
array('n' => array('serializer.normalizer')),
60+
array()
61+
));
62+
63+
$container->expects($this->once())
64+
->method('getDefinition')
65+
->will($this->returnValue($definition));
66+
67+
$this->setExpectedException('RuntimeException');
68+
69+
$serializerPass = new SerializerPass();
70+
$serializerPass->process($container);
71+
}
72+
73+
public function testServicesAreOrderedAccordingToPriority()
74+
{
75+
$services = array(
76+
'n3' => array('tag' => array()),
77+
'n1' => array('tag' => array('priority' => 200)),
78+
'n2' => array('tag' => array('priority' => 100))
79+
);
80+
81+
$expected = array(
82+
new Reference('n1'),
83+
new Reference('n2'),
84+
new Reference('n3')
85+
);
86+
87+
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
88+
89+
$container->expects($this->atLeastOnce())
90+
->method('findTaggedServiceIds')
91+
->will($this->returnValue($services));
92+
93+
$serializerPass = new SerializerPass();
94+
95+
$method = new \ReflectionMethod(
96+
'Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass',
97+
'findAndSortTaggedServices'
98+
);
99+
$method->setAccessible(TRUE);
100+
101+
$actual = $method->invoke($serializerPass, 'tag', $container);
102+
103+
$this->assertEquals($expected, $actual);
104+
}
105+
}

Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ protected static function getBundleDefaultConfig()
124124
'file_cache_dir' => '%kernel.cache_dir%/annotations',
125125
'debug' => '%kernel.debug%',
126126
),
127+
'serializer' => array(
128+
'enabled' => false
129+
)
127130
);
128131
}
129132
}

0 commit comments

Comments
 (0)