Skip to content

Commit 502bf35

Browse files
committed
[serializer] validate that the specified callbacks and max_depth_handler are actually callable
1 parent 0d786d3 commit 502bf35

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,14 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory
9999
$this->nameConverter = $nameConverter;
100100
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
101101

102-
if (\is_array($this->defaultContext[self::CALLBACKS] ?? null)) {
102+
if (isset($this->defaultContext[self::CALLBACKS])) {
103+
if (!\is_array($this->defaultContext[self::CALLBACKS])) {
104+
throw new InvalidArgumentException(sprintf('The "%s" default context option must be an array of callables.', self::CALLBACKS));
105+
}
106+
103107
foreach ($this->defaultContext[self::CALLBACKS] as $attribute => $callback) {
104108
if (!\is_callable($callback)) {
105-
throw new InvalidArgumentException(sprintf('The given callback for attribute "%s" is not callable.', $attribute));
109+
throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s" default context option.', $attribute, self::CALLBACKS));
106110
}
107111
}
108112
}

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
5959
public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = [])
6060
{
6161
parent::__construct($classMetadataFactory, $nameConverter, $defaultContext);
62+
63+
if (isset($this->defaultContext[self::MAX_DEPTH_HANDLER]) && !\is_callable($this->defaultContext[self::MAX_DEPTH_HANDLER])) {
64+
throw new InvalidArgumentException(sprintf('The "%s" given in the default context is not callable.', self::MAX_DEPTH_HANDLER));
65+
}
66+
6267
$this->defaultContext[self::EXCLUDE_FROM_CACHE_KEY] = [self::CIRCULAR_REFERENCE_LIMIT_COUNTERS];
6368

6469
$this->propertyTypeExtractor = $propertyTypeExtractor;
@@ -87,6 +92,18 @@ public function normalize($object, $format = null, array $context = [])
8792
$context['cache_key'] = $this->getCacheKey($format, $context);
8893
}
8994

95+
if (isset($context[self::CALLBACKS])) {
96+
if (!\is_array($context[self::CALLBACKS])) {
97+
throw new InvalidArgumentException(sprintf('The "%s" context option must be an array of callables.', self::CALLBACKS));
98+
}
99+
100+
foreach ($context[self::CALLBACKS] as $attribute => $callback) {
101+
if (!\is_callable($callback)) {
102+
throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s" context option.', $attribute, self::CALLBACKS));
103+
}
104+
}
105+
}
106+
90107
if ($this->isCircularReference($object, $context)) {
91108
return $this->handleCircularReference($object, $format, $context);
92109
}
@@ -96,7 +113,15 @@ public function normalize($object, $format = null, array $context = [])
96113
$attributes = $this->getAttributes($object, $format, $context);
97114
$class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object);
98115
$attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null;
99-
$maxDepthHandler = $context[self::MAX_DEPTH_HANDLER] ?? $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler;
116+
if (isset($context[self::MAX_DEPTH_HANDLER])) {
117+
$maxDepthHandler = $context[self::MAX_DEPTH_HANDLER];
118+
if (!\is_callable($maxDepthHandler)) {
119+
throw new InvalidArgumentException(sprintf('The "%s" given in the context is not callable.', self::MAX_DEPTH_HANDLER));
120+
}
121+
} else {
122+
// already validated in constructor resp by type declaration of setMaxDepthHandler
123+
$maxDepthHandler = $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler;
124+
}
100125

101126
foreach ($attributes as $attribute) {
102127
$maxDepthReached = false;

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,11 @@ private function createNormalizerWithMaxDepthHandler(callable $handler = null, b
781781
$this->normalizer->setMaxDepthHandler($handler);
782782
}
783783
} else {
784-
$this->createNormalizer([ObjectNormalizer::MAX_DEPTH_HANDLER => $handler], $classMetadataFactory);
784+
$context = [];
785+
if (null !== $handler) {
786+
$context[ObjectNormalizer::MAX_DEPTH_HANDLER] = $handler;
787+
}
788+
$this->createNormalizer($context, $classMetadataFactory);
785789
}
786790
$this->serializer = new Serializer([$this->normalizer]);
787791
$this->normalizer->setSerializer($this->serializer);

0 commit comments

Comments
 (0)