diff --git a/Annotation/Context.php b/Annotation/Context.php deleted file mode 100644 index d5c110d2e47..00000000000 --- a/Annotation/Context.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\Component\Serializer\Annotation; - -// do not deprecate in 6.4/7.0, to make it easier for the ecosystem to support 6.4, 7.4 and 8.0 simultaneously - -class_exists(\Symfony\Component\Serializer\Attribute\Context::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\Context} instead - */ - #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] - class Context extends \Symfony\Component\Serializer\Attribute\Context - { - } -} diff --git a/Annotation/DiscriminatorMap.php b/Annotation/DiscriminatorMap.php deleted file mode 100644 index 08849f77acb..00000000000 --- a/Annotation/DiscriminatorMap.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\DiscriminatorMap::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\DiscriminatorMap} instead - */ - #[\Attribute(\Attribute::TARGET_CLASS)] - class DiscriminatorMap extends \Symfony\Component\Serializer\Attribute\DiscriminatorMap - { - } -} diff --git a/Annotation/Groups.php b/Annotation/Groups.php deleted file mode 100644 index bca28df109e..00000000000 --- a/Annotation/Groups.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\Groups::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\Groups} instead - */ - #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_CLASS)] - class Groups extends \Symfony\Component\Serializer\Attribute\Groups - { - } -} diff --git a/Annotation/Ignore.php b/Annotation/Ignore.php deleted file mode 100644 index 32c0a985ca4..00000000000 --- a/Annotation/Ignore.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\Ignore::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\Ignore} instead - */ - #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] - class Ignore extends \Symfony\Component\Serializer\Attribute\Ignore - { - } -} diff --git a/Annotation/MaxDepth.php b/Annotation/MaxDepth.php deleted file mode 100644 index 55b764e499b..00000000000 --- a/Annotation/MaxDepth.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\MaxDepth::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\MaxDepth} instead - */ - #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] - class MaxDepth extends \Symfony\Component\Serializer\Attribute\MaxDepth - { - } -} diff --git a/Annotation/SerializedName.php b/Annotation/SerializedName.php deleted file mode 100644 index 9f897961fb9..00000000000 --- a/Annotation/SerializedName.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\SerializedName::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\SerializedName} instead - */ - #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] - class SerializedName extends \Symfony\Component\Serializer\Attribute\SerializedName - { - } -} diff --git a/Annotation/SerializedPath.php b/Annotation/SerializedPath.php deleted file mode 100644 index 37fffe1cc16..00000000000 --- a/Annotation/SerializedPath.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Annotation; - -class_exists(\Symfony\Component\Serializer\Attribute\SerializedPath::class); - -if (false) { - /** - * @deprecated since Symfony 7.4, use {@see \Symfony\Component\Serializer\Attribute\SerializedPath} instead - */ - #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] - class SerializedPath extends \Symfony\Component\Serializer\Attribute\SerializedPath - { - } -} diff --git a/Attribute/Context.php b/Attribute/Context.php index 25c7011b341..a9d4a17ca5b 100644 --- a/Attribute/Context.php +++ b/Attribute/Context.php @@ -47,32 +47,4 @@ public function __construct( } } } - - #[\Deprecated('Use the "context" property instead', 'symfony/serializer:7.4')] - public function getContext(): array - { - return $this->context; - } - - #[\Deprecated('Use the "normalizationContext" property instead', 'symfony/serializer:7.4')] - public function getNormalizationContext(): array - { - return $this->normalizationContext; - } - - #[\Deprecated('Use the "denormalizationContext" property instead', 'symfony/serializer:7.4')] - public function getDenormalizationContext(): array - { - return $this->denormalizationContext; - } - - #[\Deprecated('Use the "groups" property instead', 'symfony/serializer:7.4')] - public function getGroups(): array - { - return $this->groups; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\Context::class, false)) { - class_alias(Context::class, \Symfony\Component\Serializer\Annotation\Context::class); } diff --git a/Attribute/DiscriminatorMap.php b/Attribute/DiscriminatorMap.php index 2dd10df3662..d3c67b5d93d 100644 --- a/Attribute/DiscriminatorMap.php +++ b/Attribute/DiscriminatorMap.php @@ -43,26 +43,4 @@ public function __construct( throw new InvalidArgumentException(\sprintf('Default type "%s" given to "%s" must be present in "mapping" types.', $this->defaultType, static::class)); } } - - #[\Deprecated('Use the "typeProperty" property instead', 'symfony/serializer:7.4')] - public function getTypeProperty(): string - { - return $this->typeProperty; - } - - #[\Deprecated('Use the "mapping" property instead', 'symfony/serializer:7.4')] - public function getMapping(): array - { - return $this->mapping; - } - - #[\Deprecated('Use the "defaultType" property instead', 'symfony/serializer:7.4')] - public function getDefaultType(): ?string - { - return $this->defaultType; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\DiscriminatorMap::class, false)) { - class_alias(DiscriminatorMap::class, \Symfony\Component\Serializer\Annotation\DiscriminatorMap::class); } diff --git a/Attribute/Groups.php b/Attribute/Groups.php index 4e10f11efe6..2d70c1adccb 100644 --- a/Attribute/Groups.php +++ b/Attribute/Groups.php @@ -41,17 +41,4 @@ public function __construct(string|array $groups) } } } - - /** - * @return string[] - */ - #[\Deprecated('Use the "groups" property instead', 'symfony/serializer:7.4')] - public function getGroups(): array - { - return $this->groups; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\Groups::class, false)) { - class_alias(Groups::class, \Symfony\Component\Serializer\Annotation\Groups::class); } diff --git a/Attribute/Ignore.php b/Attribute/Ignore.php index bfc48b71e9b..7b54d7b9a39 100644 --- a/Attribute/Ignore.php +++ b/Attribute/Ignore.php @@ -18,7 +18,3 @@ class Ignore { } - -if (!class_exists(\Symfony\Component\Serializer\Annotation\Ignore::class, false)) { - class_alias(Ignore::class, \Symfony\Component\Serializer\Annotation\Ignore::class); -} diff --git a/Attribute/MaxDepth.php b/Attribute/MaxDepth.php index 9b2dbf157fa..65a8ba505c5 100644 --- a/Attribute/MaxDepth.php +++ b/Attribute/MaxDepth.php @@ -29,14 +29,4 @@ public function __construct( throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a positive integer.', static::class)); } } - - #[\Deprecated('Use the "maxdepth" property instead', 'symfony/serializer:7.4')] - public function getMaxDepth(): int - { - return $this->maxDepth; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\MaxDepth::class, false)) { - class_alias(MaxDepth::class, \Symfony\Component\Serializer\Annotation\MaxDepth::class); } diff --git a/Attribute/SerializedName.php b/Attribute/SerializedName.php index 4a4362f3238..eb5c451bca8 100644 --- a/Attribute/SerializedName.php +++ b/Attribute/SerializedName.php @@ -29,14 +29,4 @@ public function __construct( throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a non-empty string.', self::class)); } } - - #[\Deprecated('Use the "serializedName" property instead', 'symfony/serializer:7.4')] - public function getSerializedName(): string - { - return $this->serializedName; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\SerializedName::class, false)) { - class_alias(SerializedName::class, \Symfony\Component\Serializer\Annotation\SerializedName::class); } diff --git a/Attribute/SerializedPath.php b/Attribute/SerializedPath.php index 1ab4129108f..cb3466bc282 100644 --- a/Attribute/SerializedPath.php +++ b/Attribute/SerializedPath.php @@ -34,14 +34,4 @@ public function __construct(string $serializedPath) throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a valid property path.', self::class)); } } - - #[\Deprecated('Use the "serializedPath" property instead', 'symfony/serializer:7.4')] - public function getSerializedPath(): PropertyPath - { - return $this->serializedPath; - } -} - -if (!class_exists(\Symfony\Component\Serializer\Annotation\SerializedPath::class, false)) { - class_alias(SerializedPath::class, \Symfony\Component\Serializer\Annotation\SerializedPath::class); } diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a3b97e4051..2392df682c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,32 @@ CHANGELOG ========= +8.0 +--- + + * Remove `CsvEncoder::ESCAPE_CHAR_KEY` constant and escape character functionality + * Remove `CsvEncoderContextBuilder::withEscapeChar()` method + * Remove `AbstractNormalizerContextBuilder::withDefaultContructorArguments()`, use `withDefaultConstructorArguments()` instead + * Change signature of `NameConverterInterface::normalize()` and `NameConverterInterface::denormalize()` methods: + + Before: + + ```php + public function normalize(string $propertyName): string; + public function denormalize(string $propertyName): string; + ``` + + After: + + ```php + public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; + public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; + ``` + * Remove `AdvancedNameConverterInterface`, use `NameConverterInterface` instead + * Remove `ClassMetadataFactoryCompiler`, `CompiledClassMetadataFactory` and `CompiledClassMetadataCacheWarmer` + * Remove class aliases in the `Annotation` namespace, use attributes instead + * Remove getters in attribute classes in favor of public properties + 7.4 --- diff --git a/CacheWarmer/CompiledClassMetadataCacheWarmer.php b/CacheWarmer/CompiledClassMetadataCacheWarmer.php deleted file mode 100644 index 1bd085024d0..00000000000 --- a/CacheWarmer/CompiledClassMetadataCacheWarmer.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\CacheWarmer; - -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryCompiler; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; - -trigger_deprecation('symfony/serializer', '7.3', 'The "%s" class is deprecated.', CompiledClassMetadataCacheWarmer::class); - -/** - * @author Fabien Bourigault - * - * @deprecated since Symfony 7.3 - */ -final class CompiledClassMetadataCacheWarmer implements CacheWarmerInterface -{ - public function __construct( - private readonly array $classesToCompile, - private readonly ClassMetadataFactoryInterface $classMetadataFactory, - private readonly ClassMetadataFactoryCompiler $classMetadataFactoryCompiler, - private readonly Filesystem $filesystem, - ) { - } - - public function warmUp(string $cacheDir, ?string $buildDir = null): array - { - $metadatas = []; - - foreach ($this->classesToCompile as $classToCompile) { - $metadatas[] = $this->classMetadataFactory->getMetadataFor($classToCompile); - } - - $code = $this->classMetadataFactoryCompiler->compile($metadatas); - - $this->filesystem->dumpFile("{$cacheDir}/serializer.class.metadata.php", $code); - - return []; - } - - public function isOptional(): bool - { - return true; - } -} diff --git a/Context/Encoder/CsvEncoderContextBuilder.php b/Context/Encoder/CsvEncoderContextBuilder.php index 9f0d6da6fa0..9f891d8295a 100644 --- a/Context/Encoder/CsvEncoderContextBuilder.php +++ b/Context/Encoder/CsvEncoderContextBuilder.php @@ -57,26 +57,6 @@ public function withEnclosure(?string $enclosure): static return $this->with(CsvEncoder::ENCLOSURE_KEY, $enclosure); } - /** - * Configures the escape character. - * - * Must be empty or a single character. - * - * @deprecated since Symfony 7.2, to be removed in 8.0 - * - * @throws InvalidArgumentException - */ - public function withEscapeChar(?string $escapeChar): static - { - trigger_deprecation('symfony/serializer', '7.2', 'The "%s" method is deprecated. It will be removed in 8.0.', __METHOD__); - - if (null !== $escapeChar && \strlen($escapeChar) > 1) { - throw new InvalidArgumentException(\sprintf('The "%s" escape character must be empty or a single character.', $escapeChar)); - } - - return $this->with(CsvEncoder::ESCAPE_CHAR_KEY, $escapeChar); - } - /** * Configures the key separator when (un)flattening arrays. */ diff --git a/Context/Normalizer/AbstractNormalizerContextBuilder.php b/Context/Normalizer/AbstractNormalizerContextBuilder.php index a63e1a5075f..4c071da3db5 100644 --- a/Context/Normalizer/AbstractNormalizerContextBuilder.php +++ b/Context/Normalizer/AbstractNormalizerContextBuilder.php @@ -103,18 +103,6 @@ public function withAllowExtraAttributes(?bool $allowExtraAttributes): static return $this->with(AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES, $allowExtraAttributes); } - /** - * @deprecated since Symfony 7.1, use withDefaultConstructorArguments(?array $defaultConstructorArguments)" instead - * - * @param array>|null $defaultContructorArguments - */ - public function withDefaultContructorArguments(?array $defaultContructorArguments): static - { - trigger_deprecation('symfony/serializer', '7.1', 'The "%s()" method is deprecated, use "withDefaultConstructorArguments(?array $defaultConstructorArguments)" instead.', __METHOD__); - - return self::withDefaultConstructorArguments($defaultContructorArguments); - } - /** * Configures a hashmap of classes containing hashmaps of constructor argument => default value. * diff --git a/Encoder/CsvEncoder.php b/Encoder/CsvEncoder.php index 188e699a384..824c3be2258 100644 --- a/Encoder/CsvEncoder.php +++ b/Encoder/CsvEncoder.php @@ -25,10 +25,6 @@ class CsvEncoder implements EncoderInterface, DecoderInterface public const FORMAT = 'csv'; public const DELIMITER_KEY = 'csv_delimiter'; public const ENCLOSURE_KEY = 'csv_enclosure'; - /** - * @deprecated since Symfony 7.2, to be removed in 8.0 - */ - public const ESCAPE_CHAR_KEY = 'csv_escape_char'; public const KEY_SEPARATOR_KEY = 'csv_key_separator'; public const HEADERS_KEY = 'csv_headers'; public const ESCAPE_FORMULAS_KEY = 'csv_escape_formulas'; @@ -44,7 +40,6 @@ class CsvEncoder implements EncoderInterface, DecoderInterface private array $defaultContext = [ self::DELIMITER_KEY => ',', self::ENCLOSURE_KEY => '"', - self::ESCAPE_CHAR_KEY => '', self::END_OF_LINE => "\n", self::ESCAPE_FORMULAS_KEY => false, self::HEADERS_KEY => [], @@ -56,10 +51,6 @@ class CsvEncoder implements EncoderInterface, DecoderInterface public function __construct(array $defaultContext = []) { - if (\array_key_exists(self::ESCAPE_CHAR_KEY, $defaultContext)) { - trigger_deprecation('symfony/serializer', '7.2', 'Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.'); - } - $this->defaultContext = array_merge($this->defaultContext, $defaultContext); } @@ -88,7 +79,7 @@ public function encode(mixed $data, string $format, array $context = []): string } } - [$delimiter, $enclosure, $escapeChar, $keySeparator, $headers, $escapeFormulas, $outputBom] = $this->getCsvOptions($context); + [$delimiter, $enclosure, $keySeparator, $headers, $escapeFormulas, $outputBom] = $this->getCsvOptions($context); foreach ($data as &$value) { $flattened = []; @@ -101,7 +92,7 @@ public function encode(mixed $data, string $format, array $context = []): string $endOfLine = $context[self::END_OF_LINE] ?? $this->defaultContext[self::END_OF_LINE]; if (!($context[self::NO_HEADERS_KEY] ?? $this->defaultContext[self::NO_HEADERS_KEY])) { - fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); + fputcsv($handle, $headers, $delimiter, $enclosure, ''); if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) { fwrite($handle, $endOfLine); } @@ -109,7 +100,7 @@ public function encode(mixed $data, string $format, array $context = []): string $headers = array_fill_keys($headers, ''); foreach ($data as $row) { - fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, $escapeChar); + fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, ''); if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) { fwrite($handle, $endOfLine); } @@ -150,9 +141,9 @@ public function decode(string $data, string $format, array $context = []): mixed $headerCount = []; $result = []; - [$delimiter, $enclosure, $escapeChar, $keySeparator, , , , $asCollection] = $this->getCsvOptions($context); + [$delimiter, $enclosure, $keySeparator, , , , $asCollection] = $this->getCsvOptions($context); - while (false !== ($cols = fgetcsv($handle, 0, $delimiter, $enclosure, $escapeChar))) { + while (false !== ($cols = fgetcsv($handle, 0, $delimiter, $enclosure, ''))) { $nbCols = \count($cols); if (null === $headers) { @@ -244,7 +235,6 @@ private function getCsvOptions(array $context): array { $delimiter = $context[self::DELIMITER_KEY] ?? $this->defaultContext[self::DELIMITER_KEY]; $enclosure = $context[self::ENCLOSURE_KEY] ?? $this->defaultContext[self::ENCLOSURE_KEY]; - $escapeChar = $context[self::ESCAPE_CHAR_KEY] ?? $this->defaultContext[self::ESCAPE_CHAR_KEY]; $keySeparator = $context[self::KEY_SEPARATOR_KEY] ?? $this->defaultContext[self::KEY_SEPARATOR_KEY]; $headers = $context[self::HEADERS_KEY] ?? $this->defaultContext[self::HEADERS_KEY]; $escapeFormulas = $context[self::ESCAPE_FORMULAS_KEY] ?? $this->defaultContext[self::ESCAPE_FORMULAS_KEY]; @@ -255,7 +245,7 @@ private function getCsvOptions(array $context): array throw new InvalidArgumentException(\sprintf('The "%s" context variable must be an array or null, given "%s".', self::HEADERS_KEY, get_debug_type($headers))); } - return [$delimiter, $enclosure, $escapeChar, $keySeparator, $headers, $escapeFormulas, $outputBom, $asCollection]; + return [$delimiter, $enclosure, $keySeparator, $headers, $escapeFormulas, $outputBom, $asCollection]; } /** diff --git a/Mapping/AttributeMetadata.php b/Mapping/AttributeMetadata.php index 8abd6a837f2..6c3333373d4 100644 --- a/Mapping/AttributeMetadata.php +++ b/Mapping/AttributeMetadata.php @@ -16,7 +16,7 @@ /** * @author Kévin Dunglas * - * @final since Symfony 7.4 + * @final */ class AttributeMetadata implements AttributeMetadataInterface { @@ -173,13 +173,17 @@ public function merge(AttributeMetadataInterface $attributeMetadata): void } } - /** - * @internal since Symfony 7.4, will be replaced by `__serialize()` in 8.0 - * - * @final since Symfony 7.4, will be replaced by `__serialize()` in 8.0 - */ - public function __sleep(): array + public function __serialize(): array { - return ['name', 'groups', 'maxDepth', 'serializedName', 'serializedPath', 'ignore', 'normalizationContexts', 'denormalizationContexts']; + return [ + 'name' => $this->name, + 'groups' => $this->groups, + 'maxDepth' => $this->maxDepth, + 'serializedName' => $this->serializedName, + 'serializedPath' => $this->serializedPath, + 'ignore' => $this->ignore, + 'normalizationContexts' => $this->normalizationContexts, + 'denormalizationContexts' => $this->denormalizationContexts, + ]; } } diff --git a/Mapping/ClassMetadata.php b/Mapping/ClassMetadata.php index 0bba6661407..d02ba8b283a 100644 --- a/Mapping/ClassMetadata.php +++ b/Mapping/ClassMetadata.php @@ -14,7 +14,7 @@ /** * @author Kévin Dunglas * - * @final since Symfony 7.4 + * @final */ class ClassMetadata implements ClassMetadataInterface { @@ -75,17 +75,12 @@ public function setClassDiscriminatorMapping(?ClassDiscriminatorMapping $mapping $this->classDiscriminatorMapping = $mapping; } - /** - * @internal since Symfony 7.4, will be replaced by `__serialize()` in 8.0 - * - * @final since Symfony 7.4, will be replaced by `__serialize()` in 8.0 - */ - public function __sleep(): array + public function __serialize(): array { return [ - 'name', - 'attributesMetadata', - 'classDiscriminatorMapping', + 'name' => $this->name, + 'attributesMetadata' => $this->attributesMetadata, + 'classDiscriminatorMapping' => $this->classDiscriminatorMapping, ]; } } diff --git a/Mapping/Factory/ClassMetadataFactoryCompiler.php b/Mapping/Factory/ClassMetadataFactoryCompiler.php deleted file mode 100644 index 575019c54d8..00000000000 --- a/Mapping/Factory/ClassMetadataFactoryCompiler.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Mapping\Factory; - -use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; -use Symfony\Component\VarExporter\VarExporter; - -trigger_deprecation('symfony/serializer', '7.4', 'The "%s" class is deprecated.', ClassMetadataFactoryCompiler::class); - -/** - * @author Fabien Bourigault - * - * @deprecated since Symfony 7.4 - */ -final class ClassMetadataFactoryCompiler -{ - /** - * @param ClassMetadataInterface[] $classMetadatas - */ - public function compile(array $classMetadatas): string - { - return <<generateDeclaredClassMetadata($classMetadatas)} - ]; - EOF; - } - - /** - * @param ClassMetadataInterface[] $classMetadatas - */ - private function generateDeclaredClassMetadata(array $classMetadatas): string - { - $compiled = ''; - - foreach ($classMetadatas as $classMetadata) { - $attributesMetadata = []; - foreach ($classMetadata->getAttributesMetadata() as $attributeMetadata) { - $attributesMetadata[$attributeMetadata->getName()] = [ - $attributeMetadata->getGroups(), - $attributeMetadata->getMaxDepth(), - $attributeMetadata->getSerializedName(), - $attributeMetadata->getSerializedPath(), - ]; - } - - $classDiscriminatorMapping = $classMetadata->getClassDiscriminatorMapping() ? [ - $classMetadata->getClassDiscriminatorMapping()->getTypeProperty(), - $classMetadata->getClassDiscriminatorMapping()->getTypesMapping(), - $classMetadata->getClassDiscriminatorMapping()->getDefaultType(), - ] : null; - - $compiled .= \sprintf("\n'%s' => %s,", $classMetadata->getName(), VarExporter::export([ - $attributesMetadata, - $classDiscriminatorMapping, - ])); - } - - return $compiled; - } -} diff --git a/Mapping/Factory/CompiledClassMetadataFactory.php b/Mapping/Factory/CompiledClassMetadataFactory.php deleted file mode 100644 index 71e5900053a..00000000000 --- a/Mapping/Factory/CompiledClassMetadataFactory.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Mapping\Factory; - -use Symfony\Component\Serializer\Mapping\AttributeMetadata; -use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; -use Symfony\Component\Serializer\Mapping\ClassMetadata; -use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; - -trigger_deprecation('symfony/serializer', '7.3', 'The "%s" class is deprecated.', CompiledClassMetadataFactory::class); - -/** - * @author Fabien Bourigault - * - * @deprecated since Symfony 7.3 - */ -final class CompiledClassMetadataFactory implements ClassMetadataFactoryInterface -{ - private array $compiledClassMetadata = []; - - private array $loadedClasses = []; - - public function __construct( - string $compiledClassMetadataFile, - private readonly ClassMetadataFactoryInterface $classMetadataFactory, - ) { - if (!file_exists($compiledClassMetadataFile)) { - throw new \RuntimeException("File \"{$compiledClassMetadataFile}\" could not be found."); - } - - $compiledClassMetadata = require $compiledClassMetadataFile; - if (!\is_array($compiledClassMetadata)) { - throw new \RuntimeException(\sprintf('Compiled metadata must be of the type array, %s given.', \gettype($compiledClassMetadata))); - } - - $this->compiledClassMetadata = $compiledClassMetadata; - } - - public function getMetadataFor(string|object $value): ClassMetadataInterface - { - $className = \is_object($value) ? $value::class : $value; - - if (!isset($this->compiledClassMetadata[$className])) { - return $this->classMetadataFactory->getMetadataFor($value); - } - - if (!isset($this->loadedClasses[$className])) { - $classMetadata = new ClassMetadata($className); - foreach ($this->compiledClassMetadata[$className][0] as $name => $compiledAttributesMetadata) { - $classMetadata->addAttributeMetadata($attributeMetadata = new AttributeMetadata($name)); - foreach ($compiledAttributesMetadata[0] as $group) { - $attributeMetadata->addGroup($group); - } - $attributeMetadata->setMaxDepth($compiledAttributesMetadata[1]); - $attributeMetadata->setSerializedName($compiledAttributesMetadata[2]); - } - $classMetadata->setClassDiscriminatorMapping($this->compiledClassMetadata[$className][1] - ? new ClassDiscriminatorMapping(...$this->compiledClassMetadata[$className][1]) - : null - ); - - $this->loadedClasses[$className] = $classMetadata; - } - - return $this->loadedClasses[$className]; - } - - public function hasMetadataFor(mixed $value): bool - { - $className = \is_object($value) ? $value::class : $value; - - return isset($this->compiledClassMetadata[$className]) || $this->classMetadataFactory->hasMetadataFor($value); - } -} diff --git a/Mapping/Loader/AttributeLoader.php b/Mapping/Loader/AttributeLoader.php index 593d308fd8a..40d809c2f66 100644 --- a/Mapping/Loader/AttributeLoader.php +++ b/Mapping/Loader/AttributeLoader.php @@ -44,14 +44,12 @@ class AttributeLoader implements LoaderInterface ]; /** - * @param bool|null $allowAnyClass Null is allowed for BC with Symfony <= 6 * @param array $mappedClasses */ public function __construct( - private ?bool $allowAnyClass = true, + private bool $allowAnyClass = true, private array $mappedClasses = [], ) { - $this->allowAnyClass ??= true; } /** diff --git a/NameConverter/AdvancedNameConverterInterface.php b/NameConverter/AdvancedNameConverterInterface.php deleted file mode 100644 index 975d28fd34c..00000000000 --- a/NameConverter/AdvancedNameConverterInterface.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\Component\Serializer\NameConverter; - -/** - * Gives access to the class, the format and the context in the property name converters. - * - * @author Kévin Dunglas - * - * @deprecated since Symfony 7.2, use NameConverterInterface instead - */ -interface AdvancedNameConverterInterface extends NameConverterInterface -{ - public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; - - public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; -} diff --git a/NameConverter/CamelCaseToSnakeCaseNameConverter.php b/NameConverter/CamelCaseToSnakeCaseNameConverter.php index 033ec94b798..b82f0748913 100644 --- a/NameConverter/CamelCaseToSnakeCaseNameConverter.php +++ b/NameConverter/CamelCaseToSnakeCaseNameConverter.php @@ -38,10 +38,9 @@ public function __construct( /** * @param class-string|null $class - * @param string|null $format * @param array $context */ - public function normalize(string $propertyName/* , ?string $class = null, ?string $format = null, array $context = [] */): string + public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string { if (null === $this->attributes || \in_array($propertyName, $this->attributes, true)) { return strtolower(preg_replace('/[A-Z]/', '_\\0', lcfirst($propertyName))); @@ -52,10 +51,9 @@ public function normalize(string $propertyName/* , ?string $class = null, ?strin /** * @param class-string|null $class - * @param string|null $format * @param array $context */ - public function denormalize(string $propertyName/* , ?string $class = null, ?string $format = null, array $context = [] */): string + public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string { $class = 1 < \func_num_args() ? func_get_arg(1) : null; $format = 2 < \func_num_args() ? func_get_arg(2) : null; diff --git a/NameConverter/MetadataAwareNameConverter.php b/NameConverter/MetadataAwareNameConverter.php index c72f148eb02..451b72f3451 100644 --- a/NameConverter/MetadataAwareNameConverter.php +++ b/NameConverter/MetadataAwareNameConverter.php @@ -18,7 +18,7 @@ /** * @author Fabien Bourigault */ -final class MetadataAwareNameConverter implements AdvancedNameConverterInterface +final class MetadataAwareNameConverter implements NameConverterInterface { /** * @var array> diff --git a/NameConverter/NameConverterInterface.php b/NameConverter/NameConverterInterface.php index d6bfeceb46c..40edd0cbead 100644 --- a/NameConverter/NameConverterInterface.php +++ b/NameConverter/NameConverterInterface.php @@ -22,17 +22,15 @@ interface NameConverterInterface * Converts a property name to its normalized value. * * @param class-string|null $class - * @param string|null $format * @param array $context */ - public function normalize(string $propertyName/* , ?string $class = null, ?string $format = null, array $context = [] */): string; + public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; /** * Converts a property name to its denormalized value. * * @param class-string|null $class - * @param string|null $format * @param array $context */ - public function denormalize(string $propertyName/* , ?string $class = null, ?string $format = null, array $context = [] */): string; + public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string; } diff --git a/Normalizer/AbstractObjectNormalizer.php b/Normalizer/AbstractObjectNormalizer.php index 21197540b6a..b1ceb69bbfe 100644 --- a/Normalizer/AbstractObjectNormalizer.php +++ b/Normalizer/AbstractObjectNormalizer.php @@ -17,7 +17,6 @@ use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Encoder\CsvEncoder; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; @@ -121,7 +120,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer protected ?ClassDiscriminatorResolverInterface $classDiscriminatorResolver; /** - * @var array|false> + * @var array */ private array $typeCache = []; private array $attributesCache = []; @@ -307,7 +306,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a $this->validateCallbackContext($context); - if (null === $data && isset($context['value_type']) && ($context['value_type'] instanceof Type || $context['value_type'] instanceof LegacyType) && $context['value_type']->isNullable()) { + if (null === $data && isset($context['value_type']) && $context['value_type'] instanceof Type && $context['value_type']->isNullable()) { return null; } @@ -375,13 +374,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a if (null !== $type = $this->getType($resolvedClass, $attribute)) { try { - // BC layer for PropertyTypeExtractorInterface::getTypes(). - // Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - if (\is_array($type)) { - $value = $this->validateAndDenormalizeLegacy($type, $resolvedClass, $attribute, $value, $format, $attributeContext); - } else { - $value = $this->validateAndDenormalize($type, $resolvedClass, $attribute, $value, $format, $attributeContext); - } + $value = $this->validateAndDenormalize($type, $resolvedClass, $attribute, $value, $format, $attributeContext); } catch (NotNormalizableValueException $exception) { if (isset($context['not_normalizable_value_exceptions'])) { $context['not_normalizable_value_exceptions'][] = $exception; @@ -422,234 +415,6 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a abstract protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void; - /** - * Validates the submitted data and denormalizes it. - * - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - * - * @param LegacyType[] $types - * - * @throws NotNormalizableValueException - * @throws ExtraAttributesException - * @throws MissingConstructorArgumentsException - * @throws LogicException - */ - private function validateAndDenormalizeLegacy(array $types, string $currentClass, string $attribute, mixed $data, ?string $format, array $context): mixed - { - $expectedTypes = []; - $isUnionType = \count($types) > 1; - $e = null; - $extraAttributesException = null; - $missingConstructorArgumentsException = null; - $isNullable = false; - foreach ($types as $type) { - if (null === $data && $type->isNullable()) { - return null; - } - - $collectionValueType = $type->isCollection() ? $type->getCollectionValueTypes()[0] ?? null : null; - - // Fix a collection that contains the only one element - // This is special to xml format only - if ('xml' === $format && null !== $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) { - $data = [$data]; - } - - // This try-catch should cover all NotNormalizableValueException (and all return branches after the first - // exception) so we could try denormalizing all types of an union type. If the target type is not an union - // type, we will just re-throw the caught exception. - // In the case of no denormalization succeeds with an union type, it will fall back to the default exception - // with the acceptable types list. - try { - // In XML and CSV all basic datatypes are represented as strings, it is e.g. not possible to determine, - // if a value is meant to be a string, float, int or a boolean value from the serialized representation. - // That's why we have to transform the values, if one of these non-string basic datatypes is expected. - $builtinType = $type->getBuiltinType(); - if (\is_string($data) && (XmlEncoder::FORMAT === $format || CsvEncoder::FORMAT === $format)) { - if ('' === $data) { - if (LegacyType::BUILTIN_TYPE_ARRAY === $builtinType) { - return []; - } - - if (LegacyType::BUILTIN_TYPE_STRING === $builtinType) { - return ''; - } - - // Don't return null yet because Object-types that come first may accept empty-string too - $isNullable = $isNullable ?: $type->isNullable(); - } - - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_BOOL: - // according to https://www.w3.org/TR/xmlschema-2/#boolean, valid representations are "false", "true", "0" and "1" - if ('false' === $data || '0' === $data) { - $data = false; - } elseif ('true' === $data || '1' === $data) { - $data = true; - } else { - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_BOOL], $context['deserialization_path'] ?? null); - } - break; - case LegacyType::BUILTIN_TYPE_INT: - if (ctype_digit(isset($data[0]) && '-' === $data[0] ? substr($data, 1) : $data)) { - $data = (int) $data; - } else { - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_INT], $context['deserialization_path'] ?? null); - } - break; - case LegacyType::BUILTIN_TYPE_FLOAT: - if (is_numeric($data)) { - return (float) $data; - } - - return match ($data) { - 'NaN' => \NAN, - 'INF' => \INF, - '-INF' => -\INF, - default => throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_FLOAT], $context['deserialization_path'] ?? null), - }; - } - } - - if (is_numeric($data) && XmlEncoder::FORMAT === $format) { - // encoder parsed them wrong, so they might need to be transformed back - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_STRING: - return (string) $data; - case LegacyType::BUILTIN_TYPE_FLOAT: - return (float) $data; - case LegacyType::BUILTIN_TYPE_INT: - return (int) $data; - } - } - - if (null !== $collectionValueType && LegacyType::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) { - $builtinType = LegacyType::BUILTIN_TYPE_OBJECT; - $class = $collectionValueType->getClassName().'[]'; - - if (\count($collectionKeyType = $type->getCollectionKeyTypes()) > 0) { - $context['key_type'] = \count($collectionKeyType) > 1 ? $collectionKeyType : $collectionKeyType[0]; - } - - $context['value_type'] = $collectionValueType; - } elseif ($type->isCollection() && \count($collectionValueType = $type->getCollectionValueTypes()) > 0 && LegacyType::BUILTIN_TYPE_ARRAY === $collectionValueType[0]->getBuiltinType()) { - // get inner type for any nested array - [$innerType] = $collectionValueType; - - // note that it will break for any other builtinType - $dimensions = '[]'; - while (\count($innerType->getCollectionValueTypes()) > 0 && LegacyType::BUILTIN_TYPE_ARRAY === $innerType->getBuiltinType()) { - $dimensions .= '[]'; - [$innerType] = $innerType->getCollectionValueTypes(); - } - - if (null !== $innerType->getClassName()) { - // the builtinType is the inner one and the class is the class followed by []...[] - $builtinType = $innerType->getBuiltinType(); - $class = $innerType->getClassName().$dimensions; - } else { - // default fallback (keep it as array) - $builtinType = $type->getBuiltinType(); - $class = $type->getClassName(); - } - } else { - $builtinType = $type->getBuiltinType(); - $class = $type->getClassName(); - } - - $expectedTypes[LegacyType::BUILTIN_TYPE_OBJECT === $builtinType && $class ? $class : $builtinType] = true; - - if (LegacyType::BUILTIN_TYPE_OBJECT === $builtinType && null !== $class) { - if (!$this->serializer instanceof DenormalizerInterface) { - 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, $format); - if ($this->serializer->supportsDenormalization($data, $class, $format, $childContext)) { - return $this->serializer->denormalize($data, $class, $format, $childContext); - } - } - - // JSON only has a Number type corresponding to both int and float PHP types. - // PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert - // floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible). - // PHP's json_decode automatically converts Numbers without a decimal part to integers. - // To circumvent this behavior, integers are converted to floats when denormalizing JSON based formats and when - // a float is expected. - if (LegacyType::BUILTIN_TYPE_FLOAT === $builtinType && \is_int($data) && null !== $format && str_contains($format, JsonEncoder::FORMAT)) { - return (float) $data; - } - - if (LegacyType::BUILTIN_TYPE_BOOL === $builtinType && (\is_string($data) || \is_int($data)) && ($context[self::FILTER_BOOL] ?? false)) { - return filter_var($data, \FILTER_VALIDATE_BOOL, \FILTER_NULL_ON_FAILURE); - } - - if ((LegacyType::BUILTIN_TYPE_FALSE === $builtinType && false === $data) || (LegacyType::BUILTIN_TYPE_TRUE === $builtinType && true === $data)) { - return $data; - } - - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_ARRAY: - case LegacyType::BUILTIN_TYPE_BOOL: - case LegacyType::BUILTIN_TYPE_CALLABLE: - case LegacyType::BUILTIN_TYPE_FLOAT: - case LegacyType::BUILTIN_TYPE_INT: - case LegacyType::BUILTIN_TYPE_ITERABLE: - case LegacyType::BUILTIN_TYPE_NULL: - case LegacyType::BUILTIN_TYPE_OBJECT: - case LegacyType::BUILTIN_TYPE_RESOURCE: - case LegacyType::BUILTIN_TYPE_STRING: - if (('is_'.$builtinType)($data)) { - return $data; - } - - break; - } - } catch (NotNormalizableValueException|InvalidArgumentException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - - $expectedTypes[LegacyType::BUILTIN_TYPE_OBJECT === $builtinType && $class ? $class : $builtinType] = true; - } catch (ExtraAttributesException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - - $extraAttributesException ??= $e; - } catch (MissingConstructorArgumentsException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - - $missingConstructorArgumentsException ??= $e; - } - } - - if ($isNullable) { - return null; - } - - if ($extraAttributesException) { - throw $extraAttributesException; - } - - if ($missingConstructorArgumentsException) { - throw $missingConstructorArgumentsException; - } - - if (!$isUnionType && $e) { - throw $e; - } - - if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { - return $data; - } - - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), get_debug_type($data)), $data, array_keys($expectedTypes), $context['deserialization_path'] ?? $attribute); - } - /** * Validates the submitted data and denormalizes it. * @@ -662,13 +427,6 @@ private function validateAndDenormalize(Type $type, string $currentClass, string { $expectedTypes = []; - // BC layer for type-info < 7.2 - if (method_exists(Type::class, 'asNonNullable')) { - $isUnionType = $type->asNonNullable() instanceof UnionType; - } else { - $isUnionType = $type instanceof UnionType; - } - $e = null; $extraAttributesException = null; $missingConstructorArgumentsException = null; @@ -690,23 +448,14 @@ private function validateAndDenormalize(Type $type, string $currentClass, string $collectionValueType = $t->getCollectionValueType(); } - // BC layer for type-info < 7.2 - if (method_exists(Type::class, 'getBaseType')) { - $t = $t->getBaseType(); - } else { - while ($t instanceof WrappingTypeInterface) { - $t = $t->getWrappedType(); - } + while ($t instanceof WrappingTypeInterface) { + $t = $t->getWrappedType(); } // Fix a collection that contains the only one element // This is special to xml format only - if ('xml' === $format && $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) { - // BC layer for type-info < 7.2 - $isMixedType = method_exists(Type::class, 'isA') ? $collectionValueType->isA(TypeIdentifier::MIXED) : $collectionValueType->isIdentifiedBy(TypeIdentifier::MIXED); - if (!$isMixedType) { - $data = [$data]; - } + if ('xml' === $format && $collectionValueType && (!\is_array($data) || !\is_int(key($data))) && !$collectionValueType->isIdentifiedBy(TypeIdentifier::MIXED)) { + $data = [$data]; } // This try-catch should cover all NotNormalizableValueException (and all return branches after the first @@ -774,17 +523,10 @@ private function validateAndDenormalize(Type $type, string $currentClass, string } } - if ($collectionValueType) { + if ($collectionValueBaseType = $collectionValueType) { try { - $collectionValueBaseType = $collectionValueType; - - // BC layer for type-info < 7.2 - if (!interface_exists(WrappingTypeInterface::class)) { - $collectionValueBaseType = $collectionValueType->getBaseType(); - } else { - while ($collectionValueBaseType instanceof WrappingTypeInterface) { - $collectionValueBaseType = $collectionValueBaseType->getWrappedType(); - } + while ($collectionValueBaseType instanceof WrappingTypeInterface) { + $collectionValueBaseType = $collectionValueBaseType->getWrappedType(); } } catch (TypeInfoLogicException) { $collectionValueBaseType = Type::mixed(); @@ -795,11 +537,7 @@ private function validateAndDenormalize(Type $type, string $currentClass, string $class = $collectionValueBaseType->getClassName().'[]'; $context['key_type'] = $collectionKeyType; $context['value_type'] = $collectionValueType; - } elseif ( - // BC layer for type-info < 7.2 - !class_exists(NullableType::class) && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier() - || $collectionValueBaseType instanceof BuiltinType && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier() - ) { + } elseif ($collectionValueBaseType instanceof BuiltinType && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier()) { // get inner type for any nested array $innerType = $collectionValueType; if ($innerType instanceof NullableType) { @@ -931,15 +669,8 @@ private function validateAndDenormalize(Type $type, string $currentClass, string throw $missingConstructorArgumentsException; } - // BC layer for type-info < 7.2 - if (!class_exists(NullableType::class)) { - if (!$isUnionType && $e) { - throw $e; - } - } else { - if ($e && !($type instanceof UnionType && !$type instanceof NullableType)) { - throw $e; - } + if ($e && !($type instanceof UnionType && !$type instanceof NullableType)) { + throw $e; } if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { @@ -958,23 +689,13 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara return parent::denormalizeParameter($class, $parameter, $parameterName, $parameterData, $context, $format); } - // BC layer for PropertyTypeExtractorInterface::getTypes(). - // Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - if (\is_array($type)) { - $parameterData = $this->validateAndDenormalizeLegacy($type, $class->getName(), $parameterName, $parameterData, $format, $context); - } else { - $parameterData = $this->validateAndDenormalize($type, $class->getName(), $parameterName, $parameterData, $format, $context); - } - + $parameterData = $this->validateAndDenormalize($type, $class->getName(), $parameterName, $parameterData, $format, $context); $parameterData = $this->applyCallbacks($parameterData, $class->getName(), $parameterName, $format, $context); return $this->applyFilterBool($parameter, $parameterData, $context); } - /** - * @return Type|list|null - */ - private function getType(string $currentClass, string $attribute): Type|array|null + private function getType(string $currentClass, string $attribute): ?Type { if (null === $this->propertyTypeExtractor) { return null; @@ -985,7 +706,7 @@ private function getType(string $currentClass, string $attribute): Type|array|nu return false === $this->typeCache[$key] ? null : $this->typeCache[$key]; } - if (null !== $type = $this->getPropertyType($currentClass, $attribute)) { + if (null !== $type = $this->propertyTypeExtractor->getType($currentClass, $attribute)) { return $this->typeCache[$key] = $type; } @@ -995,7 +716,7 @@ private function getType(string $currentClass, string $attribute): Type|array|nu } foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) { - if (null !== $type = $this->getPropertyType($mappedClass, $attribute)) { + if (null !== $type = $this->propertyTypeExtractor->getType($mappedClass, $attribute)) { return $this->typeCache[$key] = $type; } } @@ -1006,21 +727,6 @@ private function getType(string $currentClass, string $attribute): Type|array|nu return null; } - /** - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - * - * @return Type|list|null - */ - private function getPropertyType(string $className, string $property): Type|array|null - { - if (class_exists(Type::class) && method_exists($this->propertyTypeExtractor, 'getType')) { - return $this->propertyTypeExtractor->getType($className, $property); - } - - return $this->propertyTypeExtractor->getTypes($className, $property); - } - /** * Sets an attribute and apply the name converter if necessary. */ diff --git a/Normalizer/ArrayDenormalizer.php b/Normalizer/ArrayDenormalizer.php index 96c4d259cde..4aa7e385239 100644 --- a/Normalizer/ArrayDenormalizer.php +++ b/Normalizer/ArrayDenormalizer.php @@ -11,11 +11,9 @@ namespace Symfony\Component\Serializer\Normalizer; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Exception\BadMethodCallException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; -use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\Type\UnionType; use Symfony\Component\TypeInfo\TypeIdentifier; @@ -55,19 +53,10 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a $typeIdentifiers = []; if (null !== $keyType = ($context['key_type'] ?? null)) { - if ($keyType instanceof Type) { - // BC layer for type-info < 7.2 - if (method_exists(Type::class, 'getBaseType')) { - $typeIdentifiers = array_map(fn (Type $t): string => $t->getBaseType()->getTypeIdentifier()->value, $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]); - } else { - /** @var list|BuiltinType> */ - $keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]; - - $typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes); - } - } else { - $typeIdentifiers = array_map(fn (LegacyType $t): string => $t->getBuiltinType(), \is_array($keyType) ? $keyType : [$keyType]); - } + /** @var list|BuiltinType> */ + $keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]; + + $typeIdentifiers = array_map(fn ($t) => $t->getTypeIdentifier()->value, $keyTypes); } foreach ($data as $key => $value) { diff --git a/Tests/CacheWarmer/CompiledClassMetadataCacheWarmerTest.php b/Tests/CacheWarmer/CompiledClassMetadataCacheWarmerTest.php deleted file mode 100644 index c711ca5f81b..00000000000 --- a/Tests/CacheWarmer/CompiledClassMetadataCacheWarmerTest.php +++ /dev/null @@ -1,71 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Tests\CacheWarmer; - -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; -use Symfony\Component\Serializer\CacheWarmer\CompiledClassMetadataCacheWarmer; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryCompiler; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; - -#[IgnoreDeprecations] -#[Group('legacy')] -final class CompiledClassMetadataCacheWarmerTest extends TestCase -{ - public function testItImplementsCacheWarmerInterface() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $filesystem = $this->createMock(Filesystem::class); - - $compiledClassMetadataCacheWarmer = new CompiledClassMetadataCacheWarmer([], $classMetadataFactory, new ClassMetadataFactoryCompiler(), $filesystem); - - $this->assertInstanceOf(CacheWarmerInterface::class, $compiledClassMetadataCacheWarmer); - } - - public function testItIsAnOptionalCacheWarmer() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $filesystem = $this->createMock(Filesystem::class); - - $compiledClassMetadataCacheWarmer = new CompiledClassMetadataCacheWarmer([], $classMetadataFactory, new ClassMetadataFactoryCompiler(), $filesystem); - - $this->assertTrue($compiledClassMetadataCacheWarmer->isOptional()); - } - - public function testItDumpCompiledClassMetadatas() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - - $code = <<createMock(Filesystem::class); - $filesystem - ->expects($this->once()) - ->method('dumpFile') - ->with('/var/cache/prod/serializer.class.metadata.php', $code) - ; - - $compiledClassMetadataCacheWarmer = new CompiledClassMetadataCacheWarmer([], $classMetadataFactory, new ClassMetadataFactoryCompiler(), $filesystem); - - $compiledClassMetadataCacheWarmer->warmUp('/var/cache/prod'); - } -} diff --git a/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php b/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php index 374bd089a71..a1c1eb3cf15 100644 --- a/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php +++ b/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Serializer\Tests\Context\Encoder; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder; use Symfony\Component\Serializer\Encoder\CsvEncoder; @@ -120,24 +118,4 @@ public function testCannotSetMultipleBytesAsEnclosure() $this->expectException(InvalidArgumentException::class); $this->contextBuilder->withEnclosure('ọ'); } - - #[IgnoreDeprecations] - #[Group('legacy')] - public function testCannotSetMultipleBytesAsEscapeChar() - { - $this->expectUserDeprecationMessage('Since symfony/serializer 7.2: The "Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder::withEscapeChar" method is deprecated. It will be removed in 8.0.'); - - $this->expectException(InvalidArgumentException::class); - $this->contextBuilder->withEscapeChar('ọ'); - } - - #[IgnoreDeprecations] - #[Group('legacy')] - public function testWithEscapeCharIsDeprecated() - { - $this->expectUserDeprecationMessage('Since symfony/serializer 7.2: The "Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder::withEscapeChar" method is deprecated. It will be removed in 8.0.'); - $context = $this->contextBuilder->withEscapeChar('\\'); - - $this->assertSame(['csv_escape_char' => '\\'], $context->toArray()); - } } diff --git a/Tests/Encoder/CsvEncoderTest.php b/Tests/Encoder/CsvEncoderTest.php index eb02b758beb..f4e09caf194 100644 --- a/Tests/Encoder/CsvEncoderTest.php +++ b/Tests/Encoder/CsvEncoderTest.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Serializer\Tests\Encoder; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Encoder\CsvEncoder; use Symfony\Component\Serializer\Exception\UnexpectedValueException; @@ -804,25 +802,4 @@ public static function provideIterable() yield 'iterator aggregate' => [new \IteratorIterator(new \ArrayIterator($data))]; yield 'generator' => [(fn (): \Generator => yield from $data)()]; } - - #[IgnoreDeprecations] - #[Group('legacy')] - public function testPassingNonEmptyEscapeCharIsDeprecated() - { - $this->expectUserDeprecationMessage('Since symfony/serializer 7.2: Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.'); - $encoder = new CsvEncoder(['csv_escape_char' => '@']); - - $this->assertSame( - [[ - 'A, B@"' => 'D', - 'C' => 'E', - ]], - $encoder->decode(<<<'CSV' - "A, B@"", "C" - "D", "E" - CSV, - 'csv' - ) - ); - } } diff --git a/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php b/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php deleted file mode 100644 index 9d45163deb2..00000000000 --- a/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php +++ /dev/null @@ -1,136 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Tests\Mapping\Factory; - -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryCompiler; -use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyFirstChild; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummySecondChild; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyThirdChild; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\MaxDepthDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedNameDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedPathDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedPathInConstructorDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Dummy; - -#[IgnoreDeprecations] -#[Group('legacy')] -final class ClassMetadataFactoryCompilerTest extends TestCase -{ - private string $dumpPath; - - protected function setUp(): void - { - $this->dumpPath = tempnam(sys_get_temp_dir(), 'sf_serializer_metadata_'); - } - - protected function tearDown(): void - { - @unlink($this->dumpPath); - } - - public function testItDumpMetadata() - { - $classMetatadataFactory = new ClassMetadataFactory(new AttributeLoader()); - - $dummyMetadata = $classMetatadataFactory->getMetadataFor(Dummy::class); - $abstractDummyMetadata = $classMetatadataFactory->getMetadataFor(AbstractDummy::class); - $maxDepthDummyMetadata = $classMetatadataFactory->getMetadataFor(MaxDepthDummy::class); - $serializedNameDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedNameDummy::class); - $serializedPathDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedPathDummy::class); - $serializedPathInConstructorDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedPathInConstructorDummy::class); - - $code = (new ClassMetadataFactoryCompiler())->compile([ - $dummyMetadata, - $abstractDummyMetadata, - $maxDepthDummyMetadata, - $serializedNameDummyMetadata, - $serializedPathDummyMetadata, - $serializedPathInConstructorDummyMetadata, - ]); - - file_put_contents($this->dumpPath, $code); - $compiledMetadata = require $this->dumpPath; - - $this->assertCount(6, $compiledMetadata); - - $this->assertArrayHasKey(Dummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'foo' => [[], null, null, null], - 'bar' => [[], null, null, null], - 'baz' => [[], null, null, null], - 'qux' => [[], null, null, null], - ], - null, - ], $compiledMetadata[Dummy::class]); - - $this->assertArrayHasKey(AbstractDummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'foo' => [[], null, null, null], - ], - [ - 'type', - [ - 'first' => AbstractDummyFirstChild::class, - 'second' => AbstractDummySecondChild::class, - 'third' => AbstractDummyThirdChild::class, - ], - 'third', - ], - ], $compiledMetadata[AbstractDummy::class]); - - $this->assertArrayHasKey(MaxDepthDummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'foo' => [[], 2, null, null], - 'bar' => [[], 3, null, null], - 'child' => [[], null, null, null], - ], - null, - ], $compiledMetadata[MaxDepthDummy::class]); - - $this->assertArrayHasKey(SerializedNameDummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'foo' => [[], null, 'baz', null], - 'bar' => [[], null, 'qux', null], - 'quux' => [[], null, null, null], - 'child' => [[], null, null, null], - ], - null, - ], $compiledMetadata[SerializedNameDummy::class]); - - $this->assertArrayHasKey(SerializedPathDummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'three' => [[], null, null, '[one][two]'], - 'seven' => [[], null, null, '[three][four]'], - ], - null, - ], $compiledMetadata[SerializedPathDummy::class]); - - $this->assertArrayHasKey(SerializedPathInConstructorDummy::class, $compiledMetadata); - $this->assertEquals([ - [ - 'three' => [[], null, null, '[one][two]'], - ], - null, - ], $compiledMetadata[SerializedPathInConstructorDummy::class]); - } -} diff --git a/Tests/Mapping/Factory/CompiledClassMetadataFactoryTest.php b/Tests/Mapping/Factory/CompiledClassMetadataFactoryTest.php deleted file mode 100644 index b2b525cadd4..00000000000 --- a/Tests/Mapping/Factory/CompiledClassMetadataFactoryTest.php +++ /dev/null @@ -1,141 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Serializer\Tests\Mapping\Factory; - -use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Serializer\Mapping\AttributeMetadata; -use Symfony\Component\Serializer\Mapping\ClassMetadata; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; -use Symfony\Component\Serializer\Mapping\Factory\CompiledClassMetadataFactory; -use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedNameDummy; -use Symfony\Component\Serializer\Tests\Fixtures\Dummy; - -/** - * @author Fabien Bourigault - */ -#[IgnoreDeprecations] -#[Group('legacy')] -final class CompiledClassMetadataFactoryTest extends TestCase -{ - public function testItImplementsClassMetadataFactoryInterface() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $this->assertInstanceOf(ClassMetadataFactoryInterface::class, $compiledClassMetadataFactory); - } - - public function testItThrowAnExceptionWhenCacheFileIsNotFound() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessageMatches('#File ".*/Fixtures/not-found-serializer.class.metadata.php" could not be found.#'); - - new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/not-found-serializer.class.metadata.php', $classMetadataFactory); - } - - public function testItThrowAnExceptionWhenMetadataIsNotOfTypeArray() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('Compiled metadata must be of the type array, object given.'); - - new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/object-metadata.php', $classMetadataFactory); - } - - #[DataProvider('valueProvider')] - public function testItReturnsTheCompiledMetadata($value) - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $classMetadataFactory - ->expects($this->never()) - ->method('getMetadataFor') - ; - - $expected = new ClassMetadata(Dummy::class); - $expected->addAttributeMetadata(new AttributeMetadata('foo')); - $expected->addAttributeMetadata(new AttributeMetadata('bar')); - $expected->addAttributeMetadata(new AttributeMetadata('baz')); - $expected->addAttributeMetadata(new AttributeMetadata('qux')); - - $this->assertEquals($expected, $compiledClassMetadataFactory->getMetadataFor($value)); - } - - public function testItDelegatesGetMetadataForCall() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $classMetadata = new ClassMetadata(SerializedNameDummy::class); - - $classMetadataFactory - ->expects($this->once()) - ->method('getMetadataFor') - ->with(SerializedNameDummy::class) - ->willReturn($classMetadata) - ; - - $this->assertEquals($classMetadata, $compiledClassMetadataFactory->getMetadataFor(SerializedNameDummy::class)); - } - - public function testItReturnsTheSameInstance() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $this->assertSame($compiledClassMetadataFactory->getMetadataFor(Dummy::class), $compiledClassMetadataFactory->getMetadataFor(Dummy::class)); - } - - #[DataProvider('valueProvider')] - public function testItHasMetadataFor($value) - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $classMetadataFactory - ->expects($this->never()) - ->method('hasMetadataFor') - ; - - $this->assertTrue($compiledClassMetadataFactory->hasMetadataFor($value)); - } - - public function testItDelegatesHasMetadataForCall() - { - $classMetadataFactory = $this->createMock(ClassMetadataFactoryInterface::class); - $compiledClassMetadataFactory = new CompiledClassMetadataFactory(__DIR__.'/../../Fixtures/serializer.class.metadata.php', $classMetadataFactory); - - $classMetadataFactory - ->expects($this->once()) - ->method('hasMetadataFor') - ->with(SerializedNameDummy::class) - ->willReturn(true) - ; - - $this->assertTrue($compiledClassMetadataFactory->hasMetadataFor(SerializedNameDummy::class)); - } - - public static function valueProvider() - { - return [ - [Dummy::class], - [new Dummy()], - ]; - } -} diff --git a/Tests/Normalizer/AbstractObjectNormalizerTest.php b/Tests/Normalizer/AbstractObjectNormalizerTest.php index 89ec73cf347..aff0ab27907 100644 --- a/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -16,9 +16,7 @@ use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; -use Symfony\Component\PropertyInfo\PropertyDocBlockExtractorInterface; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Attribute\Context; use Symfony\Component\Serializer\Attribute\DiscriminatorMap; use Symfony\Component\Serializer\Attribute\SerializedName; @@ -441,20 +439,7 @@ public function testDenormalizeCollectionDecodedFromXmlWithTwoChildren() private function getDenormalizerForDummyCollection() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::list(Type::object(DummyChild::class)), - null, - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('array', false, null, true, new LegacyType('int'), new LegacyType('object', false, DummyChild::class))], - null - ); - } + $extractor->method('getType')->willReturn(Type::list(Type::object(DummyChild::class)), null); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); @@ -505,20 +490,7 @@ public function testDenormalizeNotSerializableObjectToPopulate() private function getDenormalizerForStringCollection() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::list(Type::string()), - null, - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('array', false, null, true, new LegacyType('int'), new LegacyType('string'))], - null - ); - } + $extractor->method('getType')->willReturn(Type::list(Type::string()), null); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); @@ -799,40 +771,21 @@ public function testDenormalizeBasicTypePropertiesFromXml() private function getDenormalizerForObjectWithBasicProperties() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::bool(), - Type::bool(), - Type::bool(), - Type::bool(), - Type::int(), - Type::int(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('int')], - [new LegacyType('int')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')] - ); - } + $extractor->method('getType') + ->willReturn( + Type::bool(), + Type::bool(), + Type::bool(), + Type::bool(), + Type::int(), + Type::int(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + ); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); @@ -1408,10 +1361,6 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string public function testDenormalizeTemplateType() { - if (!interface_exists(PropertyDocBlockExtractorInterface::class)) { - $this->markTestSkipped('The PropertyInfo component before Symfony 7.1 does not support template types.'); - } - $normalizer = new class(classMetadataFactory: new ClassMetadataFactory(new AttributeLoader()), propertyTypeExtractor: new PropertyInfoExtractor(typeExtractors: [new PhpStanExtractor(), new ReflectionExtractor()])) extends AbstractObjectNormalizerDummy { protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool { diff --git a/Tests/Normalizer/NumberNormalizerTest.php b/Tests/Normalizer/NumberNormalizerTest.php index fb49ea22bab..9aa8749c5c4 100644 --- a/Tests/Normalizer/NumberNormalizerTest.php +++ b/Tests/Normalizer/NumberNormalizerTest.php @@ -13,7 +13,6 @@ use BcMath\Number; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\RequiresPhp; use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Exception\InvalidArgumentException; @@ -52,7 +51,6 @@ public static function supportsNormalizationProvider(): iterable yield 'null' => [null, false]; } - #[RequiresPhp('>=8.4')] #[RequiresPhpExtension('bcmath')] #[DataProvider('normalizeGoodBcMathNumberValueProvider')] public function testNormalizeBcMathNumber(Number $data, string $expected) @@ -100,7 +98,6 @@ public static function normalizeBadValueProvider(): iterable yield 'null' => [null]; } - #[RequiresPhp('>=8.4')] #[RequiresPhpExtension('bcmath')] public function testSupportsBcMathNumberDenormalization() { @@ -118,7 +115,6 @@ public function testDoesNotSupportOtherValuesDenormalization() $this->assertFalse($this->normalizer->supportsDenormalization(null, \stdClass::class)); } - #[RequiresPhp('>=8.4')] #[RequiresPhpExtension('bcmath')] #[DataProvider('denormalizeGoodBcMathNumberValueProvider')] public function testDenormalizeBcMathNumber(string|int $data, string $type, Number $expected) @@ -150,7 +146,6 @@ public static function denormalizeGoodGmpValueProvider(): iterable } } - #[RequiresPhp('>=8.4')] #[RequiresPhpExtension('bcmath')] #[DataProvider('denormalizeBadBcMathNumberValueProvider')] public function testDenormalizeBadBcMathNumberValueThrows(mixed $data, string $type, string $expectedException, string $expectedExceptionMessage) diff --git a/Tests/Normalizer/ObjectNormalizerTest.php b/Tests/Normalizer/ObjectNormalizerTest.php index 66904049218..9e7b1fc2014 100644 --- a/Tests/Normalizer/ObjectNormalizerTest.php +++ b/Tests/Normalizer/ObjectNormalizerTest.php @@ -29,9 +29,9 @@ use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; -use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; @@ -376,12 +376,7 @@ public function testConstructorWithNotMatchingUnionTypes() $normalizer = new ObjectNormalizer(new ClassMetadataFactory(new AttributeLoader()), null, null, new PropertyInfoExtractor([], [new ReflectionExtractor()])); $this->expectException(NotNormalizableValueException::class); - - if (class_exists(Type::class) && method_exists(PropertyInfoExtractor::class, 'getType')) { - $this->expectExceptionMessage('The type of the "value" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\DummyWithUnion" must be one of "float", "int" ("string" given).'); - } else { - $this->expectExceptionMessage('The type of the "value" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\DummyWithUnion" must be one of "int", "float" ("string" given).'); - } + $this->expectExceptionMessage('The type of the "value" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\DummyWithUnion" must be one of "float", "int" ("string" given).'); $normalizer->denormalize($data, DummyWithUnion::class, 'xml', [ AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, @@ -782,7 +777,7 @@ public function testAcceptJsonNumber() public function testDoesntHaveIssuesWithUnionConstTypes() { - if (!class_exists(PhpStanExtractor::class) || !class_exists(PhpDocParser::class)) { + if (!class_exists(PhpDocParser::class)) { $this->markTestSkipped('phpstan/phpdoc-parser required for this test'); } @@ -825,9 +820,9 @@ public function testDenormalizeFalsePseudoType() $this->assertFalse($object->canBeFalseOrString); } - public function testAdvancedNameConverter() + public function testNameConverterProperties() { - $nameConverter = new class implements AdvancedNameConverterInterface { + $nameConverter = new class implements NameConverterInterface { public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string { return \sprintf('%s-%s-%s-%s', $propertyName, $class, $format, $context['foo']); diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php index 7d7824615e3..8674c767670 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Serializer\Tests\Normalizer; -use PHPUnit\Framework\Attributes\RequiresPhp; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; @@ -193,7 +192,6 @@ public function testDenormalizeWithReadOnlyClass() $this->assertSame('childProp', $object->childProp); } - #[RequiresPhp('>=8.4')] public function testDenormalizeWithAsymmetricPropertyVisibility() { /** @var SpecialBookDummy $object */ diff --git a/Tests/SerializerTest.php b/Tests/SerializerTest.php index 608bbabc9b5..6f9e65ae04f 100644 --- a/Tests/SerializerTest.php +++ b/Tests/SerializerTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Serializer\Tests; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\RequiresPhp; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyAccess\Exception\InvalidTypeException; use Symfony\Component\PropertyAccess\PropertyAccessor; @@ -1817,7 +1816,6 @@ public function testDenormalizationFailsWithMultipleErrorsInDefaultContext() } } - #[RequiresPhp('>=8.4')] public function testDeserializeObjectWithAsymmetricPropertyVisibility() { $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]); diff --git a/composer.json b/composer.json index 4068792eac0..286337b31f5 100644 --- a/composer.json +++ b/composer.json @@ -16,45 +16,37 @@ } ], "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php84": "^1.30" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^7.2|^8.0", - "symfony/error-handler": "^6.4|^7.0|^8.0", - "symfony/filesystem": "^6.4|^7.0|^8.0", - "symfony/form": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", - "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/property-access": "^6.4|^7.0|^8.0", - "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/type-info": "^7.1.8|^8.0", - "symfony/uid": "^6.4|^7.0|^8.0", - "symfony/validator": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/type-info": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<6.4", - "symfony/property-access": "<6.4", - "symfony/property-info": "<6.4", - "symfony/uid": "<6.4", - "symfony/validator": "<6.4", - "symfony/yaml": "<6.4" + "phpdocumentor/type-resolver": "<1.4.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Serializer\\": "" },