diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 53abbb23fa31..4eea195b99d2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -731,6 +731,7 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode) ->booleanNode('enable_annotations')->{!class_exists(FullStack::class) && class_exists(Annotation::class) ? 'defaultTrue' : 'defaultFalse'}()->end() ->scalarNode('name_converter')->end() ->scalarNode('circular_reference_handler')->end() + ->scalarNode('max_depth_handler')->end() ->arrayNode('mapping') ->addDefaultsIfNotSet() ->fixXmlConfig('path') diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 413d61719384..cd144afdcef9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1273,6 +1273,10 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) { $container->getDefinition('serializer.normalizer.object')->addMethodCall('setCircularReferenceHandler', array(new Reference($config['circular_reference_handler']))); } + + if ($config['max_depth_handler'] ?? false) { + $container->getDefinition('serializer.normalizer.object')->addMethodCall('setMaxDepthHandler', array(new Reference($config['max_depth_handler']))); + } } private function registerPropertyInfoConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 653cf52f7c3c..17a09665007a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -239,6 +239,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php index a97daeef1d13..3fdd11425595 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -68,6 +68,7 @@ 'enabled' => true, 'enable_annotations' => true, 'name_converter' => 'serializer.name_converter.camel_case_to_snake_case', + 'max_depth_handler' => 'my.max.depth.handler', ), 'property_info' => true, 'ide' => 'file%%link%%format', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 6920efebed32..779078f9cb66 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -41,7 +41,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 3194a0fab2e1..9df691f21ada 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -54,6 +54,7 @@ framework: enabled: true enable_annotations: true name_converter: serializer.name_converter.camel_case_to_snake_case + max_depth_handler: my.max.depth.handler property_info: ~ ide: file%%link%%format request: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 4269cf131115..80e7a76fa173 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -804,6 +804,7 @@ public function testSerializerEnabled() $this->assertNull($container->getDefinition('serializer.mapping.class_metadata_factory')->getArgument(1)); $this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.normalizer.object')->getArgument(1)); $this->assertEquals(new Reference('property_info', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), $container->getDefinition('serializer.normalizer.object')->getArgument(3)); + $this->assertEquals(array('setMaxDepthHandler', array(new Reference('my.max.depth.handler'))), $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[0]); } public function testRegisterSerializerExtractor() diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index c680a19b1657..a4e8bf499f5c 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -9,6 +9,8 @@ CHANGELOG * added an optional `default_constructor_arguments` option of context to specify a default data in case the object is not initializable by its constructor because of data missing * added optional `bool $escapeFormulas = false` argument to `CsvEncoder::__construct` +* added `AbstractObjectNormalizer::setMaxDepthHandler` to set a handler to call when the configured + maximum depth is reached 4.0.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index bd812d289de3..644985fce727 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -41,6 +41,11 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer private $attributesCache = array(); private $cache = array(); + /** + * @var callable|null + */ + private $maxDepthHandler; + /** * @var ClassDiscriminatorResolverInterface|null */ @@ -86,11 +91,15 @@ public function normalize($object, $format = null, array $context = array()) $attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null; foreach ($attributes as $attribute) { - if (null !== $attributesMetadata && $this->isMaxDepthReached($attributesMetadata, $class, $attribute, $context)) { + $maxDepthReached = false; + if (null !== $attributesMetadata && ($maxDepthReached = $this->isMaxDepthReached($attributesMetadata, $class, $attribute, $context)) && !$this->maxDepthHandler) { continue; } $attributeValue = $this->getAttributeValue($object, $attribute, $format, $context); + if ($maxDepthReached) { + $attributeValue = \call_user_func($this->maxDepthHandler, $attributeValue); + } if (isset($this->callbacks[$attribute])) { $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue); @@ -204,6 +213,14 @@ abstract protected function extractAttributes($object, $format = null, array $co */ abstract protected function getAttributeValue($object, $attribute, $format = null, array $context = array()); + /** + * Sets an handler function that will be called when the max depth is reached. + */ + public function setMaxDepthHandler(?callable $handler): void + { + $this->maxDepthHandler = $handler; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 333f48779dc2..d5d9885f7f67 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -613,6 +613,27 @@ public function testMaxDepth() ); $this->assertEquals($expected, $result); + + $expected = array( + 'bar' => null, + 'foo' => 'level1', + 'child' => array( + 'bar' => null, + 'foo' => 'level2', + 'child' => array( + 'bar' => null, + 'child' => null, + 'foo' => 'handler', + ), + ), + ); + + $this->normalizer->setMaxDepthHandler(function ($obj) { + return 'handler'; + }); + + $result = $serializer->normalize($level1, null, array(ObjectNormalizer::ENABLE_MAX_DEPTH => true)); + $this->assertEquals($expected, $result); } /**