diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index f1d0046ef48..bbc4e2e3dfe 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -10,6 +10,7 @@ namespace Drupal\Core; use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterNestedMatchersPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -126,10 +127,17 @@ class CoreBundle extends Bundle ->setFactoryClass('Drupal\Core\ExceptionController') ->setFactoryMethod('getExceptionListener'); + // Add Serializer with arguments to be replaced in the compiler pass. + $container->register('serializer', 'Symfony\Component\Serializer\Serializer') + ->addArgument(array()) + ->addArgument(array()); + $container->addCompilerPass(new RegisterMatchersPass()); $container->addCompilerPass(new RegisterNestedMatchersPass()); // Add a compiler pass for registering event subscribers. $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING); + // Add a compiler pass for adding Normalizers and Encoders to Serializer. + $container->addCompilerPass(new RegisterSerializationClassesPass()); } } diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterSerializationClassesPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterSerializationClassesPass.php new file mode 100644 index 00000000000..6ed101b896f --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterSerializationClassesPass.php @@ -0,0 +1,72 @@ +getDefinition('serializer'); + + // Retrieve registered Normalizers and Encoders from the container. + foreach ($container->findTaggedServiceIds('normalizer') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $normalizers[$priority][] = new Reference($id); + } + foreach ($container->findTaggedServiceIds('encoder') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $encoders[$priority][] = new Reference($id); + } + + // Add the registered Normalizers and Encoders to the Serializer. + if (!empty($normalizers)) { + $definition->replaceArgument(0, $this->sort($normalizers)); + } + if (!empty($encoders)) { + $definition->replaceArgument(1, $this->sort($encoders)); + } + } + + /** + * Sorts by priority. + * + * Order services from highest priority number to lowest (reverse sorting). + * + * @param array $services + * A nested array keyed on priority number. For each priority number, the + * value is an array of Symfony\Component\DependencyInjection\Reference + * objects, each a reference to a normalizer or encoder service. + * + * @return array + * A flattened array of Reference objects from $services, ordered from high + * to low priority. + */ + protected function sort($services) { + $sorted = array(); + krsort($services); + + // Flatten the array. + foreach ($services as $a) { + $sorted = array_merge($sorted, $a); + } + + return $sorted; + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Serialization/SerializationTest.php b/core/modules/system/lib/Drupal/system/Tests/Serialization/SerializationTest.php new file mode 100644 index 00000000000..cf766ec564b --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Serialization/SerializationTest.php @@ -0,0 +1,61 @@ + 'Serialization tests', + 'description' => 'Funtional tests for serialization system.', + 'group' => 'Serialization', + ); + } + + protected function setUp() { + parent::setUp(); + $this->serializer = drupal_container()->get('serializer'); + } + + /** + * Confirms that modules can register normalizers and encoders. + */ + public function testSerializerComponentRegistration() { + $object = new \stdClass(); + $format = 'serialization_test'; + $expected = 'Normalized by SerializationTestNormalizer, Encoded by SerializationTestEncoder'; + + // Ensure the serialization invokes the expected normalizer and encoder. + $this->assertIdentical($this->serializer->serialize($object, $format), $expected); + + // Ensure the serialization fails for an unsupported format. + try { + $this->serializer->serialize($object, 'unsupported_format'); + $this->fail('The serializer was expected to throw an exception for an unsupported format, but did not.'); + } + catch (UnexpectedValueException $e) { + } + } +} diff --git a/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestBundle.php b/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestBundle.php new file mode 100644 index 00000000000..1acb3f26ad7 --- /dev/null +++ b/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestBundle.php @@ -0,0 +1,26 @@ +register('serializer.normalizer.serialization_test', 'Drupal\serialization_test\SerializationTestNormalizer')->addTag('normalizer'); + $container->register('serializer.encoder.serialization_test', 'Drupal\serialization_test\SerializationTestEncoder')->addTag('encoder'); + } +} diff --git a/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestEncoder.php b/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestEncoder.php new file mode 100644 index 00000000000..bf1a755d13d --- /dev/null +++ b/core/modules/system/tests/modules/serilization_test/lib/Drupal/serialization_test/SerializationTestEncoder.php @@ -0,0 +1,49 @@ +