Permalink
Browse files

Add the serializer service

  • Loading branch information...
1 parent bd53382 commit b4e4844235563eb078212b8ecc4981cde30141ec @humandb humandb committed Jan 20, 2013
@@ -4,6 +4,7 @@ CHANGELOG
2.3.0
-----
+ * added possibility to load the serializer component in the service container
* added route debug information when using the `router:match` command
* added `TimedPhpEngine`
* added `--clean` option the the `translation:update` command
@@ -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')) {
@schmittjoh

schmittjoh Nov 25, 2014

Contributor

You might want to check for the actual class of that service as someone might define his own serializer service, and not use the Symfony component.

As a workaround something like this is currently necessary:

services:
    serializer: @my_serializer
    my_serializer:
        public: false
        class: SomeClass
+ return;
+ }
+
+ // Looks for all the services tagged "serializer.normalizer" and adds them to the Serializer service
+ $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);
@Taluu

Taluu Nov 25, 2014

Contributor

You should check if $sortedServices[$priority] is set (otherwise you may trigger a notice)

@stof

stof Jan 3, 2015

Member

no it won't. This is a write context, not a read one. So there is no notice.

+ }
+ }
+
+ krsort($sortedServices);
+
+ // Flatten the array
+ return call_user_func_array('array_merge', $sortedServices);
+ }
+}
@@ -67,6 +67,7 @@ public function getConfigTreeBuilder()
$this->addTranslatorSection($rootNode);
$this->addValidationSection($rootNode);
$this->addAnnotationsSection($rootNode);
+ $this->addSerializerSection($rootNode);
return $treeBuilder;
}
@@ -382,4 +383,16 @@ private function addAnnotationsSection(ArrayNodeDefinition $rootNode)
->end()
;
}
+
+ private function addSerializerSection(ArrayNodeDefinition $rootNode)
+ {
+ $rootNode
+ ->children()
+ ->arrayNode('serializer')
+ ->info('serializer configuration')
+ ->canBeEnabled()
+ ->end()
+ ->end()
+ ;
+ }
}
@@ -100,6 +100,10 @@ public function load(array $configs, ContainerBuilder $container)
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
+ if (isset($config['serializer']) && $config['serializer']['enabled']) {
+ $loader->load('serializer.xml');
+ }
+
$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\ParameterBag',
'Symfony\\Component\\HttpFoundation\\HeaderBag',
@@ -26,6 +26,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FragmentRendererPass;
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\HttpFoundation\Request;
@@ -66,6 +67,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new TranslationExtractorPass());
$container->addCompilerPass(new TranslationDumperPass());
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
+ $container->addCompilerPass(new SerializerPass());
if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
@@ -0,0 +1,26 @@
+<?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>
+ </parameters>
+
+ <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>
+ </services>
+</container>
@@ -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
+{
+
+ 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);
+ }
+}
@@ -124,6 +124,9 @@ protected static function getBundleDefaultConfig()
'file_cache_dir' => '%kernel.cache_dir%/annotations',
'debug' => '%kernel.debug%',
),
+ 'serializer' => array(
+ 'enabled' => false
+ )
);
}
}

0 comments on commit b4e4844

Please sign in to comment.