Skip to content

[Serializer] Allow filtering "object" when using "getSupportedTypes()" #49735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,7 @@ public function setDenormalizer(DenormalizerInterface $denormalizer): void

public function getSupportedTypes(?string $format): array
{
// @deprecated remove condition in 7.0
if (!method_exists($this->denormalizer, 'getSupportedTypes')) {
return ['*' => $this->denormalizer instanceof CacheableSupportsMethodInterface && $this->denormalizer->hasCacheableSupportsMethod()];
}

return $this->denormalizer->getSupportedTypes($format);
return ['object' => null, '*' => false];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
/**
* Checks whether the given class is supported for denormalization by this normalizer.
*
* Since Symfony 6.3, this method will only be called if the type is
* included in the supported types returned by getSupportedTypes().
*
* @see getSupportedTypes()
*
* @param mixed $data Data to denormalize from
* @param string $type The class to which the data should be denormalized
* @param string|null $format The format being deserialized from
Expand All @@ -72,12 +67,13 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
* returned as keys, and each type should be mapped to a boolean indicating
* if the result of supportsDenormalization() can be cached or not
* (a result cannot be cached when it depends on the context or on the data.)
* A null value means that the denormalizer does not support the corresponding
* type.
*
* The special type '*' can be used to indicate that the denormalizer might
* support any types. A null value means that the denormalizer does not support
* the corresponding type.
* Use type "object" to match any classes or interfaces,
* and type "*" to match any types.
*
* @return array<class-string|'*'|string, bool|null>
* @return array<class-string|'*'|'object'|string, bool|null>
*/
/* public function getSupportedTypes(?string $format): array; */
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class GetSetMethodNormalizer extends AbstractObjectNormalizer

public function getSupportedTypes(?string $format): array
{
return ['*' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
return ['object' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ public function normalize(mixed $object, string $format = null, array $context =
/**
* Checks whether the given class is supported for normalization by this normalizer.
*
* Since Symfony 6.3, this method will only be called if the $data type is
* included in the supported types returned by getSupportedTypes().
*
* @see getSupportedTypes()
*
* @param mixed $data Data to normalize
* @param string|null $format The format being (de-)serialized from or into
* @param array $context Context options for the normalizer
Expand All @@ -63,12 +58,13 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar
* returned as keys, and each type should be mapped to a boolean indicating
* if the result of supportsNormalization() can be cached or not
* (a result cannot be cached when it depends on the context or on the data.)
* A null value means that the normalizer does not support the corresponding
* type.
*
* The special type '*' can be used to indicate that the normalizer might
* support any types. A null value means that the normalizer does not support
* the corresponding type.
* Use type "object" to match any classes or interfaces,
* and type "*" to match any types.
*
* @return array<class-string|'*'|string, bool|null>
* @return array<class-string|'*'|'object'|string, bool|null>
*/
/* public function getSupportedTypes(?string $format): array; */
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory

public function getSupportedTypes(?string $format): array
{
return ['*' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
return ['object' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory

public function getSupportedTypes(?string $format): array
{
return ['*' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
return ['object' => __CLASS__ === static::class || $this->hasCacheableSupportsMethod()];
}

/**
Expand Down
25 changes: 18 additions & 7 deletions src/Symfony/Component/Serializer/Serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,13 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
*/
private function getNormalizer(mixed $data, ?string $format, array $context): ?NormalizerInterface
{
$type = \is_object($data) ? $data::class : 'native-'.\gettype($data);
if (\is_object($data)) {
$type = $data::class;
$genericType = 'object';
} else {
$type = 'native-'.\gettype($data);
$genericType = '*';
}

if (!isset($this->normalizerCache[$format][$type])) {
$this->normalizerCache[$format][$type] = [];
Expand All @@ -277,20 +283,22 @@ private function getNormalizer(mixed $data, ?string $format, array $context): ?N
$supportedTypes = $normalizer->getSupportedTypes($format);

foreach ($supportedTypes as $supportedType => $isCacheable) {
if ('*' === $supportedType || $type !== $supportedType && !is_subclass_of($type, $supportedType, true)) {
if (\in_array($supportedType, ['*', 'object'], true)
|| $type !== $supportedType && ('object' !== $genericType || !is_subclass_of($type, $supportedType))
) {
continue;
}

if (null === $isCacheable) {
unset($supportedTypes['*']);
unset($supportedTypes['*'], $supportedTypes['object']);
} elseif ($this->normalizerCache[$format][$type][$k] = $isCacheable && $normalizer->supportsNormalization($data, $format, $context)) {
break 2;
}

break;
}

if (null === $isCacheable = $supportedTypes['*'] ?? null) {
if (null === $isCacheable = $supportedTypes[\array_key_exists($genericType, $supportedTypes) ? $genericType : '*'] ?? null) {
continue;
}

Expand Down Expand Up @@ -322,6 +330,7 @@ private function getDenormalizer(mixed $data, string $class, ?string $format, ar
{
if (!isset($this->denormalizerCache[$format][$class])) {
$this->denormalizerCache[$format][$class] = [];
$genericType = class_exists($class) || interface_exists($class, false) ? 'object' : '*';

foreach ($this->normalizers as $k => $normalizer) {
if (!$normalizer instanceof DenormalizerInterface) {
Expand All @@ -344,20 +353,22 @@ private function getDenormalizer(mixed $data, string $class, ?string $format, ar
$supportedTypes = $normalizer->getSupportedTypes($format);

foreach ($supportedTypes as $supportedType => $isCacheable) {
if ('*' === $supportedType || $class !== $supportedType && !is_subclass_of($class, $supportedType, true)) {
if (\in_array($supportedType, ['*', 'object'], true)
|| $class !== $supportedType && ('object' !== $genericType || !is_subclass_of($class, $supportedType))
) {
continue;
}

if (null === $isCacheable) {
unset($supportedTypes['*']);
unset($supportedTypes['*'], $supportedTypes['object']);
} elseif ($this->denormalizerCache[$format][$class][$k] = $isCacheable && $normalizer->supportsDenormalization(null, $class, $format, $context)) {
break 2;
}

break;
}

if (null === $isCacheable = $supportedTypes['*'] ?? null) {
if (null === $isCacheable = $supportedTypes[\array_key_exists($genericType, $supportedTypes) ? $genericType : '*'] ?? null) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
namespace Symfony\Component\Serializer\Tests\Fixtures\Annotations;

use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface;
use Symfony\Component\Serializer\Tests\Fixtures\ChildOfGroupsAnnotationDummy;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
<?php

namespace Symfony\Component\Serializer\Tests\Fixtures;
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
namespace Symfony\Component\Serializer\Tests\Fixtures;

class DummyObjectWithEnumConstructor
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ final class Php74Full
public $anotherCollection;
}


final class Php74FullWithConstructor
{
public function __construct($constructorArgument)
Expand Down
3 changes: 0 additions & 3 deletions src/Symfony/Component/Serializer/Tests/SerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -49,7 +47,6 @@
use Symfony\Component\Serializer\Normalizer\UidNormalizer;
use Symfony\Component\Serializer\Normalizer\UnwrappingDenormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummyFirstChild;
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummySecondChild;
Expand Down