Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 08f24b0

Browse files
committed
bug #30950 [Serializer] Also validate callbacks when given in the normalizer context (dbu)
This PR was merged into the 4.2 branch. Discussion ---------- [Serializer] Also validate callbacks when given in the normalizer context | Q | A | ------------- | --- | Branch? | 4.2 (callbacks are handled differently in 3.4) | Bug fix? | yes | New feature? | no | BC breaks? | no (unless somebody relied on this bug ignoring `null` as callback | Deprecations? | no | Tests pass? | yes | Fixed tickets | Related to #30888 | License | MIT | Doc PR | - callbacks configuration for the normalizer is validated to be valid callbacks when using setCallbacks or using the callbacks field in the default options. however, it was not validated when using the callbacks field in a context passed to `normalize()` Commits ------- 3789152 [serializer] validate that the specified callbacks and max_depth_handler are actually callable
2 parents ec41d76 + 3789152 commit 08f24b0

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
@@ -815,7 +815,11 @@ private function createNormalizerWithMaxDepthHandler(callable $handler = null, b
815815
$this->normalizer->setMaxDepthHandler($handler);
816816
}
817817
} else {
818-
$this->createNormalizer([ObjectNormalizer::MAX_DEPTH_HANDLER => $handler], $classMetadataFactory);
818+
$context = [];
819+
if (null !== $handler) {
820+
$context[ObjectNormalizer::MAX_DEPTH_HANDLER] = $handler;
821+
}
822+
$this->createNormalizer($context, $classMetadataFactory);
819823
}
820824
$this->serializer = new Serializer([$this->normalizer]);
821825
$this->normalizer->setSerializer($this->serializer);

0 commit comments

Comments
 (0)