diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV5.php b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV5.php index d4b5ea26d8..95dcb1e554 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV5.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV5.php @@ -23,6 +23,24 @@ class CommandForV5 extends \PHPUnit_TextUI_Command */ protected function createRunner() { - return new TestRunnerForV5($this->arguments['loader']); + $listener = new SymfonyTestsListenerForV5(); + + $this->arguments['listeners'] = isset($this->arguments['listeners']) ? $this->arguments['listeners'] : array(); + + $registeredLocally = false; + + foreach ($this->arguments['listeners'] as $registeredListener) { + if ($registeredListener instanceof SymfonyTestsListenerForV5) { + $registeredListener->globalListenerDisabled(); + $registeredLocally = true; + break; + } + } + + if (!$registeredLocally) { + $this->arguments['listeners'][] = $listener; + } + + return parent::createRunner(); } } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php index fc717ef415..f8f75bb09a 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php @@ -13,7 +13,7 @@ namespace Symfony\Bridge\PhpUnit\Legacy; use PHPUnit\TextUI\Command as BaseCommand; use PHPUnit\TextUI\TestRunner as BaseRunner; -use Symfony\Bridge\PhpUnit\TextUI\TestRunner; +use Symfony\Bridge\PhpUnit\SymfonyTestsListener; /** * {@inheritdoc} @@ -27,6 +27,24 @@ class CommandForV6 extends BaseCommand */ protected function createRunner(): BaseRunner { - return new TestRunner($this->arguments['loader']); + $listener = new SymfonyTestsListener(); + + $this->arguments['listeners'] = isset($this->arguments['listeners']) ? $this->arguments['listeners'] : []; + + $registeredLocally = false; + + foreach ($this->arguments['listeners'] as $registeredListener) { + if ($registeredListener instanceof SymfonyTestsListener) { + $registeredListener->globalListenerDisabled(); + $registeredLocally = true; + break; + } + } + + if (!$registeredLocally) { + $this->arguments['listeners'][] = $listener; + } + + return parent::createRunner(); } } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV5.php b/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV5.php deleted file mode 100644 index 7897861cf5..0000000000 --- a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV5.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit\Legacy; - -/** - * {@inheritdoc} - * - * @internal - */ -class TestRunnerForV5 extends \PHPUnit_TextUI_TestRunner -{ - /** - * {@inheritdoc} - */ - protected function handleConfiguration(array &$arguments) - { - $listener = new SymfonyTestsListenerForV5(); - - $result = parent::handleConfiguration($arguments); - - $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array(); - - $registeredLocally = false; - - foreach ($arguments['listeners'] as $registeredListener) { - if ($registeredListener instanceof SymfonyTestsListenerForV5) { - $registeredListener->globalListenerDisabled(); - $registeredLocally = true; - break; - } - } - - if (!$registeredLocally) { - $arguments['listeners'][] = $listener; - } - - return $result; - } -} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV6.php b/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV6.php deleted file mode 100644 index 6da7c65448..0000000000 --- a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV6.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit\Legacy; - -use PHPUnit\TextUI\TestRunner as BaseRunner; -use Symfony\Bridge\PhpUnit\SymfonyTestsListener; - -/** - * {@inheritdoc} - * - * @internal - */ -class TestRunnerForV6 extends BaseRunner -{ - /** - * {@inheritdoc} - */ - protected function handleConfiguration(array &$arguments) - { - $listener = new SymfonyTestsListener(); - - parent::handleConfiguration($arguments); - - $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array(); - - $registeredLocally = false; - - foreach ($arguments['listeners'] as $registeredListener) { - if ($registeredListener instanceof SymfonyTestsListener) { - $registeredListener->globalListenerDisabled(); - $registeredLocally = true; - break; - } - } - - if (!$registeredLocally) { - $arguments['listeners'][] = $listener; - } - } -} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV7.php b/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV7.php deleted file mode 100644 index a175fb65d7..0000000000 --- a/src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV7.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit\Legacy; - -use PHPUnit\TextUI\TestRunner as BaseRunner; -use Symfony\Bridge\PhpUnit\SymfonyTestsListener; - -/** - * {@inheritdoc} - * - * @internal - */ -class TestRunnerForV7 extends BaseRunner -{ - /** - * {@inheritdoc} - */ - protected function handleConfiguration(array &$arguments): void - { - $listener = new SymfonyTestsListener(); - - parent::handleConfiguration($arguments); - - $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array(); - - $registeredLocally = false; - - foreach ($arguments['listeners'] as $registeredListener) { - if ($registeredListener instanceof SymfonyTestsListener) { - $registeredListener->globalListenerDisabled(); - $registeredLocally = true; - break; - } - } - - if (!$registeredLocally) { - $arguments['listeners'][] = $listener; - } - } -} diff --git a/src/Symfony/Bridge/PhpUnit/TextUI/TestRunner.php b/src/Symfony/Bridge/PhpUnit/TextUI/TestRunner.php deleted file mode 100644 index cda5920979..0000000000 --- a/src/Symfony/Bridge/PhpUnit/TextUI/TestRunner.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit\TextUI; - -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { - class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunnerForV5', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner'); -} elseif (version_compare(\PHPUnit\Runner\Version::id(), '7.0.0', '<')) { - class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunnerForV6', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner'); -} else { - class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunnerForV7', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner'); -} - -if (false) { - class TestRunner - { - } -} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig index faef05d963..779f1259ed 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig @@ -58,6 +58,7 @@ .message-item tbody.sf-toggle-content.sf-toggle-visible { display: table-row-group; } td.message-bus-dispatch-caller { background: #f1f2f3; } + .theme-dark td.message-bus-dispatch-caller { background: var(--base-1); } {% endblock %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 34ef0a51cb..d737ab0e06 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -1011,6 +1011,8 @@ table.logs .metadata { display: block; font-size: 12px; } +.theme-dark tr.status-error td, +.theme-dark tr.status-warning td { border-bottom: unset; border-top: unset; } {# Doctrine panel ========================================================================= #} diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 07eddd0ee9..efbe2a81fd 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -48,6 +48,14 @@ class ApplicationTest extends TestCase $this->colSize = getenv('COLUMNS'); } + protected function tearDown() + { + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); + putenv('SHELL_VERBOSITY'); + unset($_ENV['SHELL_VERBOSITY']); + unset($_SERVER['SHELL_VERBOSITY']); + } + public static function setUpBeforeClass() { self::$fixturesPath = realpath(__DIR__.'/Fixtures/'); @@ -1749,14 +1757,6 @@ class ApplicationTest extends TestCase $tester = new ApplicationTester($application); $tester->run(['command' => 'foo']); } - - protected function tearDown() - { - putenv($this->colSize ? 'COLUMNS' : 'COLUMNS='.$this->colSize); - putenv('SHELL_VERBOSITY'); - unset($_ENV['SHELL_VERBOSITY']); - unset($_SERVER['SHELL_VERBOSITY']); - } } class CustomApplication extends Application diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index fb3e68e081..8d37d3af04 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -33,7 +33,7 @@ class ProgressBarTest extends TestCase protected function tearDown() { - putenv($this->colSize ? 'COLUMNS' : 'COLUMNS='.$this->colSize); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } public function testMultipleStart() diff --git a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php index a6feb122a1..88d00c8a99 100644 --- a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php +++ b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php @@ -38,7 +38,7 @@ class SymfonyStyleTest extends TestCase protected function tearDown() { - putenv($this->colSize ? 'COLUMNS' : 'COLUMNS='.$this->colSize); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); $this->command = null; $this->tester = null; } diff --git a/src/Symfony/Component/Console/Tests/TerminalTest.php b/src/Symfony/Component/Console/Tests/TerminalTest.php index ca3b874374..93b8c44a78 100644 --- a/src/Symfony/Component/Console/Tests/TerminalTest.php +++ b/src/Symfony/Component/Console/Tests/TerminalTest.php @@ -25,6 +25,12 @@ class TerminalTest extends TestCase $this->lineSize = getenv('LINES'); } + protected function tearDown() + { + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); + putenv($this->lineSize ? 'LINES' : 'LINES='.$this->lineSize); + } + public function test() { putenv('COLUMNS=100'); @@ -40,12 +46,6 @@ class TerminalTest extends TestCase $this->assertSame(60, $terminal->getHeight()); } - protected function tearDown() - { - putenv($this->colSize ? 'COLUMNS' : 'COLUMNS='.$this->colSize); - putenv($this->lineSize ? 'LINES' : 'LINES='.$this->lineSize); - } - public function test_zero_values() { putenv('COLUMNS=0'); diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index aac72010da..79e18b7fc3 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -99,10 +99,14 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn $this->nameConverter = $nameConverter; $this->defaultContext = array_merge($this->defaultContext, $defaultContext); - if (\is_array($this->defaultContext[self::CALLBACKS] ?? null)) { + if (isset($this->defaultContext[self::CALLBACKS])) { + if (!\is_array($this->defaultContext[self::CALLBACKS])) { + throw new InvalidArgumentException(sprintf('The "%s" default context option must be an array of callables.', self::CALLBACKS)); + } + foreach ($this->defaultContext[self::CALLBACKS] as $attribute => $callback) { if (!\is_callable($callback)) { - throw new InvalidArgumentException(sprintf('The given callback for attribute "%s" is not callable.', $attribute)); + throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s" default context option.', $attribute, self::CALLBACKS)); } } } @@ -385,6 +389,8 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn return $object; } + // clean up even if no match + unset($context[static::OBJECT_TO_POPULATE]); $constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes); if ($constructor) { @@ -453,7 +459,7 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $parameter->getClass(), self::class)); } $parameterClass = $parameter->getClass()->getName(); - $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName)); + $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName, $format)); } } catch (\ReflectionException $e) { throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e); @@ -468,14 +474,15 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn } /** - * @param array $parentContext - * @param string $attribute + * @param array $parentContext + * @param string $attribute Attribute name + * @param string|null $format * * @return array * * @internal */ - protected function createChildContext(array $parentContext, $attribute) + protected function createChildContext(array $parentContext, $attribute/*, string $format = null */) { if (isset($parentContext[self::ATTRIBUTES][$attribute])) { $parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute]; diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 599f503e42..cb92412ecc 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -61,6 +61,11 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) { parent::__construct($classMetadataFactory, $nameConverter, $defaultContext); + + if (isset($this->defaultContext[self::MAX_DEPTH_HANDLER]) && !\is_callable($this->defaultContext[self::MAX_DEPTH_HANDLER])) { + throw new InvalidArgumentException(sprintf('The "%s" given in the default context is not callable.', self::MAX_DEPTH_HANDLER)); + } + $this->defaultContext[self::EXCLUDE_FROM_CACHE_KEY] = [self::CIRCULAR_REFERENCE_LIMIT_COUNTERS]; $this->propertyTypeExtractor = $propertyTypeExtractor; @@ -89,6 +94,18 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer $context['cache_key'] = $this->getCacheKey($format, $context); } + if (isset($context[self::CALLBACKS])) { + if (!\is_array($context[self::CALLBACKS])) { + throw new InvalidArgumentException(sprintf('The "%s" context option must be an array of callables.', self::CALLBACKS)); + } + + foreach ($context[self::CALLBACKS] as $attribute => $callback) { + if (!\is_callable($callback)) { + throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s" context option.', $attribute, self::CALLBACKS)); + } + } + } + if ($this->isCircularReference($object, $context)) { return $this->handleCircularReference($object, $format, $context); } @@ -98,7 +115,15 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer $attributes = $this->getAttributes($object, $format, $context); $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); $attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null; - $maxDepthHandler = $context[self::MAX_DEPTH_HANDLER] ?? $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler; + if (isset($context[self::MAX_DEPTH_HANDLER])) { + $maxDepthHandler = $context[self::MAX_DEPTH_HANDLER]; + if (!\is_callable($maxDepthHandler)) { + throw new InvalidArgumentException(sprintf('The "%s" given in the context is not callable.', self::MAX_DEPTH_HANDLER)); + } + } else { + // already validated in constructor resp by type declaration of setMaxDepthHandler + $maxDepthHandler = $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler; + } foreach ($attributes as $attribute) { $maxDepthReached = false; @@ -131,7 +156,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer throw new LogicException(sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer', $attribute)); } - $data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)), $class, $format, $context); + $data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute, $format)), $class, $format, $context); } return $data; @@ -187,21 +212,17 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer return $allowedAttributes; } - if ($context[self::ATTRIBUTES] ?? $this->defaultContext[self::ATTRIBUTES] ?? false) { - return $this->extractAttributes($object, $format, $context); - } - - if (isset($this->attributesCache[$class])) { - return $this->attributesCache[$class]; - } - $attributes = $this->extractAttributes($object, $format, $context); if ($this->classDiscriminatorResolver && $mapping = $this->classDiscriminatorResolver->getMappingForMappedObject($object)) { array_unshift($attributes, $mapping->getTypeProperty()); } - return $this->attributesCache[$class] = $attributes; + if ($context['cache_key']) { + $this->attributesCache[$key] = $attributes; + } + + return $attributes; } /** @@ -356,7 +377,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer throw new LogicException(sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer', $attribute, $class)); } - $childContext = $this->createChildContext($context, $attribute); + $childContext = $this->createChildContext($context, $attribute, $format); if ($this->serializer->supportsDenormalization($data, $class, $format, $childContext)) { return $this->serializer->denormalize($data, $class, $format, $childContext); } @@ -486,7 +507,32 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer } /** - * Gets the cache key to use. + * Overwritten to update the cache key for the child. + * + * We must not mix up the attribute cache between parent and children. + * + * {@inheritdoc} + */ + protected function createChildContext(array $parentContext, $attribute/*, string $format = null */) + { + if (\func_num_args() >= 3) { + $format = \func_get_arg(2); + } else { + // will be deprecated in version 4 + $format = null; + } + + $context = parent::createChildContext($parentContext, $attribute, $format); + // format is already included in the cache_key of the parent. + $context['cache_key'] = $this->getCacheKey($format, $context); + + return $context; + } + + /** + * Builds the cache key for the attributes cache. + * + * The key must be different for every option in the context that could change which attributes should be handled. * * @return bool|string */ @@ -496,9 +542,14 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer unset($context[$key]); } unset($context[self::EXCLUDE_FROM_CACHE_KEY]); + unset($context['cache_key']); // avoid artificially different keys try { - return md5($format.serialize($context)); + return md5($format.serialize([ + 'context' => $context, + 'ignored' => $this->ignoredAttributes, + 'camelized' => $this->camelizedAttributes, + ])); } catch (\Exception $exception) { // The context cannot be serialized, skip the cache return false; diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index b4e0805281..0edf6f38aa 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -394,6 +394,30 @@ class ObjectNormalizerTest extends TestCase ); } + public function testObjectToPopulateNoMatch() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new PhpDocExtractor()); + new Serializer([$this->normalizer]); + + $objectToPopulate = new ObjectInner(); + $objectToPopulate->foo = 'foo'; + + $outer = $this->normalizer->denormalize([ + 'foo' => 'foo', + 'inner' => [ + 'bar' => 'bar', + ], + ], ObjectOuter::class, null, [ObjectNormalizer::OBJECT_TO_POPULATE => $objectToPopulate]); + + $this->assertInstanceOf(ObjectOuter::class, $outer); + $inner = $outer->getInner(); + $this->assertInstanceOf(ObjectInner::class, $inner); + $this->assertNotSame($objectToPopulate, $inner); + $this->assertSame('bar', $inner->bar); + $this->assertNull($inner->foo); + } + /** * @dataProvider provideCallbacks */ @@ -472,6 +496,16 @@ class ObjectNormalizerTest extends TestCase ['fooBar' => 'foobar'], $this->normalizer->normalize($obj, 'any') ); + + $this->normalizer->setIgnoredAttributes(['foo', 'baz', 'camelCase', 'object']); + + $this->assertEquals( + [ + 'fooBar' => 'foobar', + 'bar' => 'bar', + ], + $this->normalizer->normalize($obj, 'any') + ); } public function testIgnoredAttributesDenormalize() @@ -781,7 +815,11 @@ class ObjectNormalizerTest extends TestCase $this->normalizer->setMaxDepthHandler($handler); } } else { - $this->createNormalizer([ObjectNormalizer::MAX_DEPTH_HANDLER => $handler], $classMetadataFactory); + $context = []; + if (null !== $handler) { + $context[ObjectNormalizer::MAX_DEPTH_HANDLER] = $handler; + } + $this->createNormalizer($context, $classMetadataFactory); } $this->serializer = new Serializer([$this->normalizer]); $this->normalizer->setSerializer($this->serializer); @@ -1208,6 +1246,9 @@ class ObjectOuter { public $foo; public $bar; + /** + * @var ObjectInner + */ private $inner; private $date;