-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Handling array properties during denormalization #51261
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
Comments
cc-ing @tucksaun and @nicolas-grekas as I've seen that you've worked on the |
@X-Coder264 /**
* @var FooDummy[]
*/
public $foo; So it makes strict comparision <?php
declare(strict_types=1);
namespace App\Serializer\Normalizer;
use App\Entity\Prop\CornerOfTheWorld;
use App\Serializer\Type\ImportableEnum;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final readonly class ImportableEnumNormalizer implements NormalizerInterface, DenormalizerInterface
{
public function getSupportedTypes(?string $format): array
{
if ('csv' === $format) {
return [
ImportableEnum::class => true,
ImportableEnum::class . '[]' => true,
CornerOfTheWorld::class . '[]' => true,
'native-array' => true,
];
} else {
return [];
}
}
/**
* @param class-string<ImportableEnum> $type
* @param int|string $data
*/
public function denormalize(mixed $data, string $type, string $format = null, array $context = []): null|ImportableEnum|array
{
$className = \rtrim($type, '[]');
if (!\is_subclass_of($className, ImportableEnum::class)) {
throw new \InvalidArgumentException(\sprintf('Expected type "%s". "%s" given.', ImportableEnum::class . '|' . ImportableEnum::class . '[]', $type));
}
if ($isCollectionType = \strpos($type, '[]')) {
$data = \explode(',', $data);
}
if (empty($data)) {
return $isCollectionType ? [] : null;
}
$enumFrom = static function(string $value) use ($className): ImportableEnum {
$value = \trim($value);
try {
$enumValue = \array_flip($className::getExcelMap())[$value] ?? throw new NotNormalizableValueException(\sprintf('"%s" is not valid backing value for "%s"', $value, $className));
return $className::from($enumValue);
} catch (\TypeError $e) {
throw new NotNormalizableValueException(\sprintf('Failed converting %s "%s" to "%s"', \get_debug_type($value), $value, $className), previous: $e);
}
};
8000
if (!$isCollectionType) {
return $enumFrom($data);
}
return \array_map($enumFrom, $data);
}
public function supportsDenormalization(mixed $data, string $type, string $format = null): bool
{
return \is_subclass_of($type, ImportableEnum::class) || \is_subclass_of(\rtrim($type, '[]'), ImportableEnum::class) && 'csv' === $format;
}
public function normalize(mixed $object, string $format = null, array $context = []): string
{
$isCollectionType = \is_array($object);
if (!\is_object($object) && false === $isCollectionType) {
throw new \InvalidArgumentException(\sprintf('Expected object or array of objects. "%s" given.', \get_debug_type($object)));
}
$checkType = static function($value) {
if (!$value instanceof ImportableEnum) {
throw new \InvalidArgumentException(\sprintf('Object must implement "%s".', ImportableEnum::class));
}
};
$map = static function (ImportableEnum $value): string {
return $value->getExcelMap()[$value->value];
};
$isCollectionType ? \array_walk($object, $checkType) : $checkType($object);
return $isCollectionType ? \implode(',', \array_map($map, $object)) : $map($object);
}
public function supportsNormalization(mixed $data, string $format = null): bool
{
return ($data instanceof ImportableEnum || (\is_array($data) && \count(\array_filter($data, static fn ($el) => $el instanceof ImportableEnum)))) && 'csv' === $format;
}
} Apart from the fact that |
@andersmateusz I've had a bit of time so I've sent a PR with the fix for denormalization -> #51369 |
Uh oh!
There was an error while loading. Please reload this page.
Symfony version(s) affected
6.3
Description
Updating from Serializer 5.4 to 6.3 breaks our testsuite as the denormalizer which is supposed to denormalize an array property does not get executed anymore as it does implement the
getSupportedTypes
method and in the serializer code path that handles thegetSupportedTypes
logic it no longer calls thesupportsDenormalization
method on that denormalizer (the concrete example can be seen under the steps to reproduce). I'm not entirely familiar with the Serializer component so maybe I'm just doing something wrong.How to reproduce
The interfaces/classes needed to reproduce this:
interface FooBaseDummy { }
The test that I expect to pass but currently does not with Serializer 6.3:
The test passes when using Serializer 5.4
Removing the
getSupportedTypes
method from theFooBaseDummyDenormalizer
when using Serializer 6.3 makes the test pass again (but with a deprecation). TheFooBaseDummyDenormalizer
is a simplified equivalent of a class from a bundle we use in our app.When we use Serializer 5.4 the serializer calls
$normalizer->supportsDenormalization
which returns true and everything works fine ->symfony/src/Symfony/Component/Serializer/Serializer.php
Line 315 in b39fcef
When we use Serializer 6.3 it skips that code path as the denormalizer has the
getSupportedTypes
method so it enters thisif
statement which just does acontinue
->symfony/src/Symfony/Component/Serializer/Serializer.php
Lines 363 to 367 in bbb5f5c
$supportedType
here isSymfony\Component\Serializer\Tests\Fixtures\FooBaseDummy[]
,$class
isSymfony\Component\Serializer\Tests\Fixtures\FooDummy[]
and$genericType
is*
Possible Solution
No response
Additional Context
No response
The text was updated successfully, but these errors were encountered: