diff --git a/Attribute/Context.php b/Attribute/Context.php
index 5ea2d2eb5..892af481a 100644
--- a/Attribute/Context.php
+++ b/Attribute/Context.php
@@ -36,14 +36,14 @@ public function __construct(
string|array $groups = [],
) {
if (!$context && !$normalizationContext && !$denormalizationContext) {
- throw new InvalidArgumentException(sprintf('At least one of the "context", "normalizationContext", or "denormalizationContext" options must be provided as a non-empty array to "%s".', static::class));
+ throw new InvalidArgumentException(\sprintf('At least one of the "context", "normalizationContext", or "denormalizationContext" options must be provided as a non-empty array to "%s".', static::class));
}
$this->groups = (array) $groups;
foreach ($this->groups as $group) {
if (!\is_string($group)) {
- throw new InvalidArgumentException(sprintf('Parameter "groups" given to "%s" must be a string or an array of strings, "%s" given.', static::class, get_debug_type($group)));
+ throw new InvalidArgumentException(\sprintf('Parameter "groups" given to "%s" must be a string or an array of strings, "%s" given.', static::class, get_debug_type($group)));
}
}
}
diff --git a/Attribute/DiscriminatorMap.php b/Attribute/DiscriminatorMap.php
index a77fc2984..48d0842aa 100644
--- a/Attribute/DiscriminatorMap.php
+++ b/Attribute/DiscriminatorMap.php
@@ -30,11 +30,11 @@ public function __construct(
private readonly array $mapping,
) {
if (!$typeProperty) {
- throw new InvalidArgumentException(sprintf('Parameter "typeProperty" given to "%s" cannot be empty.', static::class));
+ throw new InvalidArgumentException(\sprintf('Parameter "typeProperty" given to "%s" cannot be empty.', static::class));
}
if (!$mapping) {
- throw new InvalidArgumentException(sprintf('Parameter "mapping" given to "%s" cannot be empty.', static::class));
+ throw new InvalidArgumentException(\sprintf('Parameter "mapping" given to "%s" cannot be empty.', static::class));
}
}
diff --git a/Attribute/Groups.php b/Attribute/Groups.php
index 39914f971..8747949a4 100644
--- a/Attribute/Groups.php
+++ b/Attribute/Groups.php
@@ -32,12 +32,12 @@ public function __construct(string|array $groups)
$this->groups = (array) $groups;
if (!$this->groups) {
- throw new InvalidArgumentException(sprintf('Parameter given to "%s" cannot be empty.', static::class));
+ throw new InvalidArgumentException(\sprintf('Parameter given to "%s" cannot be empty.', static::class));
}
foreach ($this->groups as $group) {
if (!\is_string($group) || '' === $group) {
- throw new InvalidArgumentException(sprintf('Parameter given to "%s" must be a string or an array of non-empty strings.', static::class));
+ throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a string or an array of non-empty strings.', static::class));
}
}
}
diff --git a/Attribute/MaxDepth.php b/Attribute/MaxDepth.php
index 17562b6c2..16d6a8120 100644
--- a/Attribute/MaxDepth.php
+++ b/Attribute/MaxDepth.php
@@ -25,7 +25,7 @@ class MaxDepth
public function __construct(private readonly int $maxDepth)
{
if ($maxDepth <= 0) {
- throw new InvalidArgumentException(sprintf('Parameter given to "%s" must be a positive integer.', static::class));
+ throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a positive integer.', static::class));
}
}
diff --git a/Attribute/SerializedName.php b/Attribute/SerializedName.php
index 6acbebd03..f1c6cefe2 100644
--- a/Attribute/SerializedName.php
+++ b/Attribute/SerializedName.php
@@ -25,7 +25,7 @@ class SerializedName
public function __construct(private readonly string $serializedName)
{
if ('' === $serializedName) {
- throw new InvalidArgumentException(sprintf('Parameter given to "%s" must be a non-empty string.', self::class));
+ throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a non-empty string.', self::class));
}
}
diff --git a/Attribute/SerializedPath.php b/Attribute/SerializedPath.php
index 118e3adbe..71254bfb9 100644
--- a/Attribute/SerializedPath.php
+++ b/Attribute/SerializedPath.php
@@ -31,7 +31,7 @@ public function __construct(string $serializedPath)
try {
$this->serializedPath = new PropertyPath($serializedPath);
} catch (InvalidPropertyPathException $pathException) {
- throw new InvalidArgumentException(sprintf('Parameter given to "%s" must be a valid property path.', self::class));
+ throw new InvalidArgumentException(\sprintf('Parameter given to "%s" must be a valid property path.', self::class));
}
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 463572046..4c36d5885 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,19 @@
CHANGELOG
=========
+7.2
+---
+
+ * Deprecate the `csv_escape_char` context option of `CsvEncoder`, the `CsvEncoder::ESCAPE_CHAR_KEY` constant
+ and the `CsvEncoderContextBuilder::withEscapeChar()` method, following its deprecation in PHP 8.4
+ * Add `SnakeCaseToCamelCaseNameConverter`
+ * Support subclasses of `\DateTime` and `\DateTimeImmutable` for denormalization
+ * Add the `UidNormalizer::NORMALIZATION_FORMAT_RFC9562` constant
+ * Add support for configuring multiple serializer instances with different
+ default contexts, name converters, sets of normalizers and encoders
+ * Add support for collection profiles of multiple serializer instances
+ * Deprecate `AdvancedNameConverterInterface`, use `NameConverterInterface` instead
+
7.1
---
diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php
index c85ee213e..7df4d6bc8 100644
--- a/Command/DebugCommand.php
+++ b/Command/DebugCommand.php
@@ -49,7 +49,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if (!class_exists($class)) {
$io = new SymfonyStyle($input, $output);
- $io->error(sprintf('Class "%s" was not found.', $class));
+ $io->error(\sprintf('Class "%s" was not found.', $class));
return Command::FAILURE;
}
@@ -62,7 +62,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
private function dumpSerializerDataForClass(InputInterface $input, OutputInterface $output, string $class): void
{
$io = new SymfonyStyle($input, $output);
- $title = sprintf('%s', $class);
+ $title = \sprintf('%s', $class);
$rows = [];
$dump = new Dumper($output);
@@ -75,15 +75,14 @@ private function dumpSerializerDataForClass(InputInterface $input, OutputInterfa
];
}
+ $io->section($title);
+
if (!$rows) {
- $io->section($title);
$io->text('No Serializer data were found for this class.');
return;
}
- $io->section($title);
-
$table = new Table($output);
$table->setHeaders(['Property', 'Options']);
$table->setRows($rows);
diff --git a/Context/Encoder/CsvEncoderContextBuilder.php b/Context/Encoder/CsvEncoderContextBuilder.php
index f75759031..9f0d6da6f 100644
--- a/Context/Encoder/CsvEncoderContextBuilder.php
+++ b/Context/Encoder/CsvEncoderContextBuilder.php
@@ -35,7 +35,7 @@ final class CsvEncoderContextBuilder implements ContextBuilderInterface
public function withDelimiter(?string $delimiter): static
{
if (null !== $delimiter && 1 !== \strlen($delimiter)) {
- throw new InvalidArgumentException(sprintf('The "%s" delimiter must be a single character.', $delimiter));
+ throw new InvalidArgumentException(\sprintf('The "%s" delimiter must be a single character.', $delimiter));
}
return $this->with(CsvEncoder::DELIMITER_KEY, $delimiter);
@@ -51,7 +51,7 @@ public function withDelimiter(?string $delimiter): static
public function withEnclosure(?string $enclosure): static
{
if (null !== $enclosure && 1 !== \strlen($enclosure)) {
- throw new InvalidArgumentException(sprintf('The "%s" enclosure must be a single character.', $enclosure));
+ throw new InvalidArgumentException(\sprintf('The "%s" enclosure must be a single character.', $enclosure));
}
return $this->with(CsvEncoder::ENCLOSURE_KEY, $enclosure);
@@ -62,12 +62,16 @@ public function withEnclosure(?string $enclosure): static
*
* 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));
+ throw new InvalidArgumentException(\sprintf('The "%s" escape character must be empty or a single character.', $escapeChar));
}
return $this->with(CsvEncoder::ESCAPE_CHAR_KEY, $escapeChar);
diff --git a/Context/Normalizer/AbstractNormalizerContextBuilder.php b/Context/Normalizer/AbstractNormalizerContextBuilder.php
index cb5b0544d..a63e1a507 100644
--- a/Context/Normalizer/AbstractNormalizerContextBuilder.php
+++ b/Context/Normalizer/AbstractNormalizerContextBuilder.php
@@ -87,7 +87,7 @@ public function withAttributes(?array $attributes): static
foreach ($it as $attribute) {
if (!\is_string($attribute)) {
- throw new InvalidArgumentException(sprintf('Each attribute must be a string, "%s" given.', get_debug_type($attribute)));
+ throw new InvalidArgumentException(\sprintf('Each attribute must be a string, "%s" given.', get_debug_type($attribute)));
}
}
diff --git a/Context/Normalizer/AbstractObjectNormalizerContextBuilder.php b/Context/Normalizer/AbstractObjectNormalizerContextBuilder.php
index a27f00c5b..45b47bc1b 100644
--- a/Context/Normalizer/AbstractObjectNormalizerContextBuilder.php
+++ b/Context/Normalizer/AbstractObjectNormalizerContextBuilder.php
@@ -47,7 +47,7 @@ public function withDepthKeyPattern(?string $depthKeyPattern): static
preg_match_all('/(?[a-z])/', $depthKeyPattern, $matches);
if (2 !== \count($matches['specifier']) || 's' !== $matches['specifier'][0] || 's' !== $matches['specifier'][1]) {
- throw new InvalidArgumentException(sprintf('The depth key pattern "%s" is not valid. You must set exactly two string placeholders.', $depthKeyPattern));
+ throw new InvalidArgumentException(\sprintf('The depth key pattern "%s" is not valid. You must set exactly two string placeholders.', $depthKeyPattern));
}
return $this->with(AbstractObjectNormalizer::DEPTH_KEY_PATTERN, $depthKeyPattern);
diff --git a/Context/Normalizer/DateTimeNormalizerContextBuilder.php b/Context/Normalizer/DateTimeNormalizerContextBuilder.php
index e2d289e60..de83b1245 100644
--- a/Context/Normalizer/DateTimeNormalizerContextBuilder.php
+++ b/Context/Normalizer/DateTimeNormalizerContextBuilder.php
@@ -55,7 +55,7 @@ public function withTimezone(\DateTimeZone|string|null $timezone): static
try {
$timezone = new \DateTimeZone($timezone);
} catch (\Exception $e) {
- throw new InvalidArgumentException(sprintf('The "%s" timezone is invalid.', $timezone), previous: $e);
+ throw new InvalidArgumentException(\sprintf('The "%s" timezone is invalid.', $timezone), previous: $e);
}
}
diff --git a/Context/Normalizer/UidNormalizerContextBuilder.php b/Context/Normalizer/UidNormalizerContextBuilder.php
index 1d889e502..b809fe3eb 100644
--- a/Context/Normalizer/UidNormalizerContextBuilder.php
+++ b/Context/Normalizer/UidNormalizerContextBuilder.php
@@ -33,7 +33,7 @@ final class UidNormalizerContextBuilder implements ContextBuilderInterface
public function withNormalizationFormat(?string $normalizationFormat): static
{
if (null !== $normalizationFormat && !\in_array($normalizationFormat, UidNormalizer::NORMALIZATION_FORMATS, true)) {
- throw new InvalidArgumentException(sprintf('The "%s" normalization format is not valid.', $normalizationFormat));
+ throw new InvalidArgumentException(\sprintf('The "%s" normalization format is not valid.', $normalizationFormat));
}
return $this->with(UidNormalizer::NORMALIZATION_FORMAT_KEY, $normalizationFormat);
diff --git a/Context/Normalizer/UnwrappingDenormalizerContextBuilder.php b/Context/Normalizer/UnwrappingDenormalizerContextBuilder.php
index 5beb4e984..2945cb961 100644
--- a/Context/Normalizer/UnwrappingDenormalizerContextBuilder.php
+++ b/Context/Normalizer/UnwrappingDenormalizerContextBuilder.php
@@ -45,7 +45,7 @@ public function withUnwrapPath(?string $unwrapPath): static
try {
new PropertyPath($unwrapPath);
} catch (InvalidPropertyPathException $e) {
- throw new InvalidArgumentException(sprintf('The "%s" property path is not valid.', $unwrapPath), previous: $e);
+ throw new InvalidArgumentException(\sprintf('The "%s" property path is not valid.', $unwrapPath), previous: $e);
}
return $this->with(UnwrappingDenormalizer::UNWRAP_PATH, $unwrapPath);
diff --git a/DataCollector/SerializerDataCollector.php b/DataCollector/SerializerDataCollector.php
index 2880dea37..e87c51ca1 100644
--- a/DataCollector/SerializerDataCollector.php
+++ b/DataCollector/SerializerDataCollector.php
@@ -25,11 +25,22 @@
*/
class SerializerDataCollector extends DataCollector implements LateDataCollectorInterface
{
+ private const DATA_TEMPLATE = [
+ 'serialize' => [],
+ 'deserialize' => [],
+ 'normalize' => [],
+ 'denormalize' => [],
+ 'encode' => [],
+ 'decode' => [],
+ ];
+
+ private array $dataGroupedByName;
private array $collected = [];
public function reset(): void
{
$this->data = [];
+ unset($this->dataGroupedByName);
$this->collected = [];
}
@@ -43,14 +54,14 @@ public function getName(): string
return 'serializer';
}
- public function getData(): Data|array
+ public function getData(?string $name = null): Data|array
{
- return $this->data;
+ return null === $name ? $this->data : $this->getDataGroupedByName()[$name];
}
- public function getHandledCount(): int
+ public function getHandledCount(?string $name = null): int
{
- return array_sum(array_map('count', $this->data));
+ return array_sum(array_map('count', $this->getData($name)));
}
public function getTotalTime(): float
@@ -64,110 +75,108 @@ public function getTotalTime(): float
return $totalTime;
}
- public function collectSerialize(string $traceId, mixed $data, string $format, array $context, float $time, array $caller): void
+ public function getSerializerNames(): array
+ {
+ return array_keys($this->getDataGroupedByName());
+ }
+
+ public function collectSerialize(string $traceId, mixed $data, string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'context', 'time', 'caller'),
+ compact('data', 'format', 'context', 'time', 'caller', 'name'),
['method' => 'serialize'],
);
}
- public function collectDeserialize(string $traceId, mixed $data, string $type, string $format, array $context, float $time, array $caller): void
+ public function collectDeserialize(string $traceId, mixed $data, string $type, string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'type', 'context', 'time', 'caller'),
+ compact('data', 'format', 'type', 'context', 'time', 'caller', 'name'),
['method' => 'deserialize'],
);
}
- public function collectNormalize(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller): void
+ public function collectNormalize(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'context', 'time', 'caller'),
+ compact('data', 'format', 'context', 'time', 'caller', 'name'),
['method' => 'normalize'],
);
}
- public function collectDenormalize(string $traceId, mixed $data, string $type, ?string $format, array $context, float $time, array $caller): void
+ public function collectDenormalize(string $traceId, mixed $data, string $type, ?string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'type', 'context', 'time', 'caller'),
+ compact('data', 'format', 'type', 'context', 'time', 'caller', 'name'),
['method' => 'denormalize'],
);
}
- public function collectEncode(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller): void
+ public function collectEncode(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'context', 'time', 'caller'),
+ compact('data', 'format', 'context', 'time', 'caller', 'name'),
['method' => 'encode'],
);
}
- public function collectDecode(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller): void
+ public function collectDecode(string $traceId, mixed $data, ?string $format, array $context, float $time, array $caller, string $name): void
{
unset($context[TraceableSerializer::DEBUG_TRACE_ID]);
$this->collected[$traceId] = array_merge(
$this->collected[$traceId] ?? [],
- compact('data', 'format', 'context', 'time', 'caller'),
+ compact('data', 'format', 'context', 'time', 'caller', 'name'),
['method' => 'decode'],
);
}
- public function collectNormalization(string $traceId, string $normalizer, float $time): void
+ public function collectNormalization(string $traceId, string $normalizer, float $time, string $name): void
{
$method = 'normalize';
- $this->collected[$traceId]['normalization'][] = compact('normalizer', 'method', 'time');
+ $this->collected[$traceId]['normalization'][] = compact('normalizer', 'method', 'time', 'name');
}
- public function collectDenormalization(string $traceId, string $normalizer, float $time): void
+ public function collectDenormalization(string $traceId, string $normalizer, float $time, string $name): void
{
$method = 'denormalize';
- $this->collected[$traceId]['normalization'][] = compact('normalizer', 'method', 'time');
+ $this->collected[$traceId]['normalization'][] = compact('normalizer', 'method', 'time', 'name');
}
- public function collectEncoding(string $traceId, string $encoder, float $time): void
+ public function collectEncoding(string $traceId, string $encoder, float $time, string $name): void
{
$method = 'encode';
- $this->collected[$traceId]['encoding'][] = compact('encoder', 'method', 'time');
+ $this->collected[$traceId]['encoding'][] = compact('encoder', 'method', 'time', 'name');
}
- public function collectDecoding(string $traceId, string $encoder, float $time): void
+ public function collectDecoding(string $traceId, string $encoder, float $time, string $name): void
{
$method = 'decode';
- $this->collected[$traceId]['encoding'][] = compact('encoder', 'method', 'time');
+ $this->collected[$traceId]['encoding'][] = compact('encoder', 'method', 'time', 'name');
}
public function lateCollect(): void
{
- $this->data = [
- 'serialize' => [],
- 'deserialize' => [],
- 'normalize' => [],
- 'denormalize' => [],
- 'encode' => [],
- 'decode' => [],
- ];
+ $this->data = self::DATA_TEMPLATE;
foreach ($this->collected as $collected) {
if (!isset($collected['data'])) {
@@ -184,6 +193,7 @@ public function lateCollect(): void
'normalization' => [],
'encoding' => [],
'caller' => $collected['caller'] ?? null,
+ 'name' => $collected['name'],
];
if (isset($collected['normalization'])) {
@@ -220,6 +230,22 @@ public function lateCollect(): void
}
}
+ private function getDataGroupedByName(): array
+ {
+ if (!isset($this->dataGroupedByName)) {
+ $this->dataGroupedByName = [];
+
+ foreach ($this->data as $method => $items) {
+ foreach ($items as $item) {
+ $this->dataGroupedByName[$item['name']] ??= self::DATA_TEMPLATE;
+ $this->dataGroupedByName[$item['name']][$method][] = $item;
+ }
+ }
+ }
+
+ return $this->dataGroupedByName;
+ }
+
private function getMethodLocation(string $class, string $method): array
{
$reflection = new \ReflectionClass($class);
diff --git a/Debug/TraceableEncoder.php b/Debug/TraceableEncoder.php
index afefee0ee..39e75e34f 100644
--- a/Debug/TraceableEncoder.php
+++ b/Debug/TraceableEncoder.php
@@ -30,13 +30,14 @@ class TraceableEncoder implements EncoderInterface, DecoderInterface, Serializer
public function __construct(
private EncoderInterface|DecoderInterface $encoder,
private SerializerDataCollector $dataCollector,
+ private readonly string $serializerName = 'default',
) {
}
public function encode(mixed $data, string $format, array $context = []): string
{
if (!$this->encoder instanceof EncoderInterface) {
- throw new \BadMethodCallException(sprintf('The "%s()" method cannot be called as nested encoder doesn\'t implements "%s".', __METHOD__, EncoderInterface::class));
+ throw new \BadMethodCallException(\sprintf('The "%s()" method cannot be called as nested encoder doesn\'t implements "%s".', __METHOD__, EncoderInterface::class));
}
$startTime = microtime(true);
@@ -44,7 +45,7 @@ public function encode(mixed $data, string $format, array $context = []): string
$time = microtime(true) - $startTime;
if ($traceId = ($context[TraceableSerializer::DEBUG_TRACE_ID] ?? null)) {
- $this->dataCollector->collectEncoding($traceId, $this->encoder::class, $time);
+ $this->dataCollector->collectEncoding($traceId, $this->encoder::class, $time, $this->serializerName);
}
return $encoded;
@@ -62,7 +63,7 @@ public function supportsEncoding(string $format, array $context = []): bool
public function decode(string $data, string $format, array $context = []): mixed
{
if (!$this->encoder instanceof DecoderInterface) {
- throw new \BadMethodCallException(sprintf('The "%s()" method cannot be called as nested encoder doesn\'t implements "%s".', __METHOD__, DecoderInterface::class));
+ throw new \BadMethodCallException(\sprintf('The "%s()" method cannot be called as nested encoder doesn\'t implements "%s".', __METHOD__, DecoderInterface::class));
}
$startTime = microtime(true);
@@ -70,7 +71,7 @@ public function decode(string $data, string $format, array $context = []): mixed
$time = microtime(true) - $startTime;
if ($traceId = ($context[TraceableSerializer::DEBUG_TRACE_ID] ?? null)) {
- $this->dataCollector->collectDecoding($traceId, $this->encoder::class, $time);
+ $this->dataCollector->collectDecoding($traceId, $this->encoder::class, $time, $this->serializerName);
}
return $encoded;
diff --git a/Debug/TraceableNormalizer.php b/Debug/TraceableNormalizer.php
index 1aa788049..1b143e295 100644
--- a/Debug/TraceableNormalizer.php
+++ b/Debug/TraceableNormalizer.php
@@ -31,6 +31,7 @@ class TraceableNormalizer implements NormalizerInterface, DenormalizerInterface,
public function __construct(
private NormalizerInterface|DenormalizerInterface $normalizer,
private SerializerDataCollector $dataCollector,
+ private readonly string $serializerName = 'default',
) {
}
@@ -42,7 +43,7 @@ public function getSupportedTypes(?string $format): array
public function normalize(mixed $object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
{
if (!$this->normalizer instanceof NormalizerInterface) {
- throw new \BadMethodCallException(sprintf('The "%s()" method cannot be called as nested normalizer doesn\'t implements "%s".', __METHOD__, NormalizerInterface::class));
+ throw new \BadMethodCallException(\sprintf('The "%s()" method cannot be called as nested normalizer doesn\'t implements "%s".', __METHOD__, NormalizerInterface::class));
}
$startTime = microtime(true);
@@ -50,7 +51,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
$time = microtime(true) - $startTime;
if ($traceId = ($context[TraceableSerializer::DEBUG_TRACE_ID] ?? null)) {
- $this->dataCollector->collectNormalization($traceId, $this->normalizer::class, $time);
+ $this->dataCollector->collectNormalization($traceId, $this->normalizer::class, $time, $this->serializerName);
}
return $normalized;
@@ -68,7 +69,7 @@ public function supportsNormalization(mixed $data, ?string $format = null, array
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
{
if (!$this->normalizer instanceof DenormalizerInterface) {
- throw new \BadMethodCallException(sprintf('The "%s()" method cannot be called as nested normalizer doesn\'t implements "%s".', __METHOD__, DenormalizerInterface::class));
+ throw new \BadMethodCallException(\sprintf('The "%s()" method cannot be called as nested normalizer doesn\'t implements "%s".', __METHOD__, DenormalizerInterface::class));
}
$startTime = microtime(true);
@@ -76,7 +77,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
$time = microtime(true) - $startTime;
if ($traceId = ($context[TraceableSerializer::DEBUG_TRACE_ID] ?? null)) {
- $this->dataCollector->collectDenormalization($traceId, $this->normalizer::class, $time);
+ $this->dataCollector->collectDenormalization($traceId, $this->normalizer::class, $time, $this->serializerName);
}
return $denormalized;
diff --git a/Debug/TraceableSerializer.php b/Debug/TraceableSerializer.php
index 898e89560..a05bf4bf8 100644
--- a/Debug/TraceableSerializer.php
+++ b/Debug/TraceableSerializer.php
@@ -32,12 +32,13 @@ class TraceableSerializer implements SerializerInterface, NormalizerInterface, D
public function __construct(
private SerializerInterface&NormalizerInterface&DenormalizerInterface&EncoderInterface&DecoderInterface $serializer,
private SerializerDataCollector $dataCollector,
+ private readonly string $serializerName = 'default',
) {
}
public function serialize(mixed $data, string $format, array $context = []): string
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->serialize($data, $format, $context);
@@ -45,14 +46,14 @@ public function serialize(mixed $data, string $format, array $context = []): str
$caller = $this->getCaller(__FUNCTION__, SerializerInterface::class);
- $this->dataCollector->collectSerialize($traceId, $data, $format, $context, $time, $caller);
+ $this->dataCollector->collectSerialize($traceId, $data, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
public function deserialize(mixed $data, string $type, string $format, array $context = []): mixed
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->deserialize($data, $type, $format, $context);
@@ -60,14 +61,14 @@ public function deserialize(mixed $data, string $type, string $format, array $co
$caller = $this->getCaller(__FUNCTION__, SerializerInterface::class);
- $this->dataCollector->collectDeserialize($traceId, $data, $type, $format, $context, $time, $caller);
+ $this->dataCollector->collectDeserialize($traceId, $data, $type, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
public function normalize(mixed $object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->normalize($object, $format, $context);
@@ -75,14 +76,14 @@ public function normalize(mixed $object, ?string $format = null, array $context
$caller = $this->getCaller(__FUNCTION__, NormalizerInterface::class);
- $this->dataCollector->collectNormalize($traceId, $object, $format, $context, $time, $caller);
+ $this->dataCollector->collectNormalize($traceId, $object, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->denormalize($data, $type, $format, $context);
@@ -90,14 +91,14 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
$caller = $this->getCaller(__FUNCTION__, DenormalizerInterface::class);
- $this->dataCollector->collectDenormalize($traceId, $data, $type, $format, $context, $time, $caller);
+ $this->dataCollector->collectDenormalize($traceId, $data, $type, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
public function encode(mixed $data, string $format, array $context = []): string
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->encode($data, $format, $context);
@@ -105,14 +106,14 @@ public function encode(mixed $data, string $format, array $context = []): string
$caller = $this->getCaller(__FUNCTION__, EncoderInterface::class);
- $this->dataCollector->collectEncode($traceId, $data, $format, $context, $time, $caller);
+ $this->dataCollector->collectEncode($traceId, $data, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
public function decode(string $data, string $format, array $context = []): mixed
{
- $context[self::DEBUG_TRACE_ID] = $traceId = uniqid('', true);
+ $context[self::DEBUG_TRACE_ID] = $traceId = bin2hex(random_bytes(4));
$startTime = microtime(true);
$result = $this->serializer->decode($data, $format, $context);
@@ -120,7 +121,7 @@ public function decode(string $data, string $format, array $context = []): mixed
$caller = $this->getCaller(__FUNCTION__, DecoderInterface::class);
- $this->dataCollector->collectDecode($traceId, $data, $format, $context, $time, $caller);
+ $this->dataCollector->collectDecode($traceId, $data, $format, $context, $time, $caller, $this->serializerName);
return $result;
}
diff --git a/DependencyInjection/SerializerPass.php b/DependencyInjection/SerializerPass.php
index 8c1e0a7bb..179b7a3d9 100644
--- a/DependencyInjection/SerializerPass.php
+++ b/DependencyInjection/SerializerPass.php
@@ -19,6 +19,8 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Serializer\Debug\TraceableEncoder;
use Symfony\Component\Serializer\Debug\TraceableNormalizer;
+use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
+use Symfony\Component\Serializer\SerializerInterface;
/**
* Adds all services with the tags "serializer.encoder" and "serializer.normalizer" as
@@ -31,45 +33,201 @@ class SerializerPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;
+ private const NAME_CONVERTER_METADATA_AWARE_ID = 'serializer.name_converter.metadata_aware';
+
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('serializer')) {
return;
}
- if (!$normalizers = $this->findAndSortTaggedServices('serializer.normalizer', $container)) {
+ $namedSerializers = $container->hasParameter('.serializer.named_serializers')
+ ? $container->getParameter('.serializer.named_serializers') : [];
+
+ $this->createNamedSerializerTags($container, 'serializer.normalizer', 'include_built_in_normalizers', $namedSerializers);
+ $this->createNamedSerializerTags($container, 'serializer.encoder', 'include_built_in_encoders', $namedSerializers);
+
+ if (!$normalizers = $this->findAndSortTaggedServices('serializer.normalizer.default', $container)) {
throw new RuntimeException('You must tag at least one service as "serializer.normalizer" to use the "serializer" service.');
}
- if (!$encoders = $this->findAndSortTaggedServices('serializer.encoder', $container)) {
+ if (!$encoders = $this->findAndSortTaggedServices('serializer.encoder.default', $container)) {
throw new RuntimeException('You must tag at least one service as "serializer.encoder" to use the "serializer" service.');
}
+ $defaultContext = [];
if ($container->hasParameter('serializer.default_context')) {
$defaultContext = $container->getParameter('serializer.default_context');
- foreach (array_merge($normalizers, $encoders) as $service) {
- $definition = $container->getDefinition($service);
- $definition->setBindings(['array $defaultContext' => new BoundArgument($defaultContext, false)] + $definition->getBindings());
- }
-
$container->getParameterBag()->remove('serializer.default_context');
$container->getDefinition('serializer')->setArgument('$defaultContext', $defaultContext);
}
+ /** @var ?string $circularReferenceHandler */
+ $circularReferenceHandler = $container->hasParameter('.serializer.circular_reference_handler')
+ ? $container->getParameter('.serializer.circular_reference_handler') : null;
+
+ /** @var ?string $maxDepthHandler */
+ $maxDepthHandler = $container->hasParameter('.serializer.max_depth_handler')
+ ? $container->getParameter('.serializer.max_depth_handler') : null;
+
+ $this->bindDefaultContext($container, array_merge($normalizers, $encoders), $defaultContext, $circularReferenceHandler, $maxDepthHandler);
+
+ $this->configureSerializer($container, 'serializer', $normalizers, $encoders, 'default');
+
+ if ($namedSerializers) {
+ $this->configureNamedSerializers($container, $circularReferenceHandler, $maxDepthHandler);
+ }
+ }
+
+ private function createNamedSerializerTags(ContainerBuilder $container, string $tagName, string $configName, array $namedSerializers): void
+ {
+ $serializerNames = array_keys($namedSerializers);
+ $withBuiltIn = array_filter($serializerNames, fn (string $name) => $namedSerializers[$name][$configName] ?? false);
+
+ foreach ($container->findTaggedServiceIds($tagName) as $serviceId => $tags) {
+ $definition = $container->getDefinition($serviceId);
+
+ foreach ($tags as $tag) {
+ $names = (array) ($tag['serializer'] ?? []);
+
+ if (!$names) {
+ $names = ['default'];
+ } elseif (\in_array('*', $names, true)) {
+ $names = array_unique(['default', ...$serializerNames]);
+ }
+
+ if ($tag['built_in'] ?? false) {
+ $names = array_unique(['default', ...$names, ...$withBuiltIn]);
+ }
+
+ unset($tag['serializer'], $tag['built_in']);
+
+ foreach ($names as $name) {
+ $definition->addTag($tagName.'.'.$name, $tag);
+ }
+ }
+ }
+ }
+
+ private function bindDefaultContext(ContainerBuilder $container, array $services, array $defaultContext, ?string $circularReferenceHandler, ?string $maxDepthHandler): void
+ {
+ foreach ($services as $id) {
+ $definition = $container->getDefinition((string) $id);
+
+ $context = $defaultContext;
+ if (is_a($definition->getClass(), ObjectNormalizer::class, true)) {
+ if (null !== $circularReferenceHandler) {
+ $context += ['circular_reference_handler' => new Reference($circularReferenceHandler)];
+ }
+ if (null !== $maxDepthHandler) {
+ $context += ['max_depth_handler' => new Reference($maxDepthHandler)];
+ }
+ }
+
+ $definition->setBindings(['array $defaultContext' => new BoundArgument($context, false)] + $definition->getBindings());
+ }
+ }
+
+ private function configureSerializer(ContainerBuilder $container, string $id, array $normalizers, array $encoders, string $serializerName): void
+ {
if ($container->getParameter('kernel.debug') && $container->hasDefinition('serializer.data_collector')) {
foreach ($normalizers as $i => $normalizer) {
$normalizers[$i] = $container->register('.debug.serializer.normalizer.'.$normalizer, TraceableNormalizer::class)
- ->setArguments([$normalizer, new Reference('serializer.data_collector')]);
+ ->setArguments([$normalizer, new Reference('serializer.data_collector'), $serializerName]);
}
foreach ($encoders as $i => $encoder) {
$encoders[$i] = $container->register('.debug.serializer.encoder.'.$encoder, TraceableEncoder::class)
- ->setArguments([$encoder, new Reference('serializer.data_collector')]);
+ ->setArguments([$encoder, new Reference('serializer.data_collector'), $serializerName]);
}
}
- $serializerDefinition = $container->getDefinition('serializer');
+ $serializerDefinition = $container->getDefinition($id);
$serializerDefinition->replaceArgument(0, $normalizers);
$serializerDefinition->replaceArgument(1, $encoders);
}
+
+ private function configureNamedSerializers(ContainerBuilder $container, ?string $circularReferenceHandler, ?string $maxDepthHandler): void
+ {
+ $defaultSerializerNameConverter = $container->hasParameter('.serializer.name_converter')
+ ? $container->getParameter('.serializer.name_converter') : null;
+
+ foreach ($container->getParameter('.serializer.named_serializers') as $serializerName => $config) {
+ $config += ['default_context' => [], 'name_converter' => null];
+ $serializerId = 'serializer.'.$serializerName;
+
+ if (!$normalizers = $this->findAndSortTaggedServices('serializer.normalizer.'.$serializerName, $container)) {
+ throw new RuntimeException(\sprintf('The named serializer "%1$s" requires at least one registered normalizer. Tag the normalizers as "serializer.normalizer" with the "serializer" attribute set to "%1$s".', $serializerName));
+ }
+
+ if (!$encoders = $this->findAndSortTaggedServices('serializer.encoder.'.$serializerName, $container)) {
+ throw new RuntimeException(\sprintf('The named serializer "%1$s" requires at least one registered encoder. Tag the encoders as "serializer.encoder" with the "serializer" attribute set to "%1$s".', $serializerName));
+ }
+
+ $config['name_converter'] = $defaultSerializerNameConverter !== $config['name_converter']
+ ? $this->buildChildNameConverterDefinition($container, $config['name_converter'])
+ : self::NAME_CONVERTER_METADATA_AWARE_ID;
+
+ $normalizers = $this->buildChildDefinitions($container, $serializerName, $normalizers, $config);
+ $encoders = $this->buildChildDefinitions($container, $serializerName, $encoders, $config);
+
+ $this->bindDefaultContext($container, array_merge($normalizers, $encoders), $config['default_context'], $circularReferenceHandler, $maxDepthHandler);
+
+ $container->registerChild($serializerId, 'serializer')->setArgument('$defaultContext', $config['default_context']);
+ $container->registerAliasForArgument($serializerId, SerializerInterface::class, $serializerName.'.serializer');
+
+ $this->configureSerializer($container, $serializerId, $normalizers, $encoders, $serializerName);
+
+ if ($container->getParameter('kernel.debug') && $container->hasDefinition('debug.serializer')) {
+ $container->registerChild($debugId = 'debug.'.$serializerId, 'debug.serializer')
+ ->setDecoratedService($serializerId)
+ ->replaceArgument(0, new Reference($debugId.'.inner'))
+ ->replaceArgument(2, $serializerName);
+ }
+ }
+ }
+
+ private function buildChildNameConverterDefinition(ContainerBuilder $container, ?string $nameConverter): ?string
+ {
+ $childId = self::NAME_CONVERTER_METADATA_AWARE_ID.'.'.ContainerBuilder::hash($nameConverter);
+
+ if (!$container->hasDefinition($childId)) {
+ $childDefinition = $container->registerChild($childId, self::NAME_CONVERTER_METADATA_AWARE_ID.'.abstract');
+ if (null !== $nameConverter) {
+ $childDefinition->addArgument(new Reference($nameConverter));
+ }
+ }
+
+ return $childId;
+ }
+
+ private function buildChildDefinitions(ContainerBuilder $container, string $serializerName, array $services, array $config): array
+ {
+ foreach ($services as &$id) {
+ $childId = $id.'.'.$serializerName;
+
+ $definition = $container->registerChild($childId, (string) $id)
+ ->setClass($container->getDefinition((string) $id)->getClass())
+ ;
+
+ if (null !== $nameConverterIndex = $this->findNameConverterIndex($container, (string) $id)) {
+ $definition->replaceArgument($nameConverterIndex, new Reference($config['name_converter']));
+ }
+
+ $id = new Reference($childId);
+ }
+
+ return $services;
+ }
+
+ private function findNameConverterIndex(ContainerBuilder $container, string $id): int|string|null
+ {
+ foreach ($container->getDefinition($id)->getArguments() as $index => $argument) {
+ if ($argument instanceof Reference && self::NAME_CONVERTER_METADATA_AWARE_ID === (string) $argument) {
+ return $index;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/Encoder/ChainDecoder.php b/Encoder/ChainDecoder.php
index ad182a9a4..8df5cd8b8 100644
--- a/Encoder/ChainDecoder.php
+++ b/Encoder/ChainDecoder.php
@@ -78,6 +78,6 @@ private function getDecoder(string $format, array $context): DecoderInterface
}
}
- throw new RuntimeException(sprintf('No decoder found for format "%s".', $format));
+ throw new RuntimeException(\sprintf('No decoder found for format "%s".', $format));
}
}
diff --git a/Encoder/ChainEncoder.php b/Encoder/ChainEncoder.php
index 5445761f3..3621471b4 100644
--- a/Encoder/ChainEncoder.php
+++ b/Encoder/ChainEncoder.php
@@ -101,6 +101,6 @@ private function getEncoder(string $format, array $context): EncoderInterface
}
}
- throw new RuntimeException(sprintf('No encoder found for format "%s".', $format));
+ throw new RuntimeException(\sprintf('No encoder found for format "%s".', $format));
}
}
diff --git a/Encoder/CsvEncoder.php b/Encoder/CsvEncoder.php
index a3112ae36..3902b5613 100644
--- a/Encoder/CsvEncoder.php
+++ b/Encoder/CsvEncoder.php
@@ -25,6 +25,9 @@ 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';
@@ -53,6 +56,10 @@ 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);
}
@@ -241,7 +248,7 @@ private function getCsvOptions(array $context): array
$asCollection = $context[self::AS_COLLECTION_KEY] ?? $this->defaultContext[self::AS_COLLECTION_KEY];
if (!\is_array($headers)) {
- throw new InvalidArgumentException(sprintf('The "%s" context variable must be an array or null, given "%s".', self::HEADERS_KEY, get_debug_type($headers)));
+ 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];
diff --git a/Encoder/JsonDecode.php b/Encoder/JsonDecode.php
index 0dbc9f6df..b50538175 100644
--- a/Encoder/JsonDecode.php
+++ b/Encoder/JsonDecode.php
@@ -106,7 +106,7 @@ public function decode(string $data, string $format, array $context = []): mixed
}
if (!class_exists(JsonParser::class)) {
- throw new UnsupportedException(sprintf('Enabling "%s" serializer option requires seld/jsonlint. Try running "composer require seld/jsonlint".', self::DETAILED_ERROR_MESSAGES));
+ throw new UnsupportedException(\sprintf('Enabling "%s" serializer option requires seld/jsonlint. Try running "composer require seld/jsonlint".', self::DETAILED_ERROR_MESSAGES));
}
throw new NotEncodableValueException((new JsonParser())->lint($data)?->getMessage() ?: $errorMessage);
diff --git a/Encoder/XmlEncoder.php b/Encoder/XmlEncoder.php
index 5dcb2ba7e..e1a816380 100644
--- a/Encoder/XmlEncoder.php
+++ b/Encoder/XmlEncoder.php
@@ -152,9 +152,8 @@ public function decode(string $data, string $format, array $context = []): mixed
}
$data = array_merge($this->parseXmlAttributes($rootNode, $context), ['#' => $rootNode->nodeValue]);
- $data = $this->addXmlNamespaces($data, $rootNode, $dom);
- return $data;
+ return $this->addXmlNamespaces($data, $rootNode, $dom);
}
public function supportsEncoding(string $format): bool
@@ -389,7 +388,7 @@ private function buildXml(\DOMNode $parentNode, mixed $data, string $format, arr
if (\is_object($data)) {
if (null === $this->serializer) {
- throw new BadMethodCallException(sprintf('The serializer needs to be set to allow "%s()" to be used with object data.', __METHOD__));
+ throw new BadMethodCallException(\sprintf('The serializer needs to be set to allow "%s()" to be used with object data.', __METHOD__));
}
$data = $this->serializer->normalize($data, $format, $context);
@@ -408,7 +407,7 @@ private function buildXml(\DOMNode $parentNode, mixed $data, string $format, arr
return $this->appendNode($parentNode, $data, $format, $context, 'data');
}
- throw new NotEncodableValueException('An unexpected value could not be serialized: '.(!\is_resource($data) ? var_export($data, true) : sprintf('%s resource', get_resource_type($data))));
+ throw new NotEncodableValueException('An unexpected value could not be serialized: '.(!\is_resource($data) ? var_export($data, true) : \sprintf('%s resource', get_resource_type($data))));
}
/**
@@ -457,7 +456,7 @@ private function selectNodeType(\DOMNode $node, mixed $val, string $format, arra
$node->appendChild($child);
} elseif (\is_object($val)) {
if (null === $this->serializer) {
- throw new BadMethodCallException(sprintf('The serializer needs to be set to allow "%s()" to be used with object data.', __METHOD__));
+ throw new BadMethodCallException(\sprintf('The serializer needs to be set to allow "%s()" to be used with object data.', __METHOD__));
}
return $this->selectNodeType($node, $this->serializer->normalize($val, $format, $context), $format, $context);
diff --git a/Exception/ExtraAttributesException.php b/Exception/ExtraAttributesException.php
index 24b031ae3..639808b10 100644
--- a/Exception/ExtraAttributesException.php
+++ b/Exception/ExtraAttributesException.php
@@ -22,7 +22,7 @@ public function __construct(
private readonly array $extraAttributes,
?\Throwable $previous = null,
) {
- $msg = sprintf('Extra attributes are not allowed ("%s" %s unknown).', implode('", "', $extraAttributes), \count($extraAttributes) > 1 ? 'are' : 'is');
+ $msg = \sprintf('Extra attributes are not allowed ("%s" %s unknown).', implode('", "', $extraAttributes), \count($extraAttributes) > 1 ? 'are' : 'is');
parent::__construct($msg, 0, $previous);
}
diff --git a/Exception/UnexpectedPropertyException.php b/Exception/UnexpectedPropertyException.php
index 4f9ead9a6..03e42fca5 100644
--- a/Exception/UnexpectedPropertyException.php
+++ b/Exception/UnexpectedPropertyException.php
@@ -22,7 +22,7 @@ public function __construct(
public readonly string $property,
?\Throwable $previous = null,
) {
- $msg = sprintf('Property is not allowed ("%s" is unknown).', $this->property);
+ $msg = \sprintf('Property is not allowed ("%s" is unknown).', $this->property);
parent::__construct($msg, 0, $previous);
}
diff --git a/Extractor/ObjectPropertyListExtractor.php b/Extractor/ObjectPropertyListExtractor.php
index 8422b0786..42a546805 100644
--- a/Extractor/ObjectPropertyListExtractor.php
+++ b/Extractor/ObjectPropertyListExtractor.php
@@ -18,12 +18,12 @@
*/
final class ObjectPropertyListExtractor implements ObjectPropertyListExtractorInterface
{
- private PropertyListExtractorInterface $propertyListExtractor;
private \Closure $objectClassResolver;
- public function __construct(PropertyListExtractorInterface $propertyListExtractor, ?callable $objectClassResolver = null)
- {
- $this->propertyListExtractor = $propertyListExtractor;
+ public function __construct(
+ private PropertyListExtractorInterface $propertyListExtractor,
+ ?callable $objectClassResolver = null,
+ ) {
$this->objectClassResolver = ($objectClassResolver ?? 'get_class')(...);
}
diff --git a/Mapping/ClassMetadata.php b/Mapping/ClassMetadata.php
index e68f4c71f..b635ee10b 100644
--- a/Mapping/ClassMetadata.php
+++ b/Mapping/ClassMetadata.php
@@ -78,11 +78,7 @@ public function merge(ClassMetadataInterface $classMetadata): void
public function getReflectionClass(): \ReflectionClass
{
- if (!$this->reflClass) {
- $this->reflClass = new \ReflectionClass($this->getName());
- }
-
- return $this->reflClass;
+ return $this->reflClass ??= new \ReflectionClass($this->getName());
}
public function getClassDiscriminatorMapping(): ?ClassDiscriminatorMapping
diff --git a/Mapping/Factory/ClassMetadataFactoryCompiler.php b/Mapping/Factory/ClassMetadataFactoryCompiler.php
index f01fe9ce2..1e9202b7d 100644
--- a/Mapping/Factory/ClassMetadataFactoryCompiler.php
+++ b/Mapping/Factory/ClassMetadataFactoryCompiler.php
@@ -57,7 +57,7 @@ private function generateDeclaredClassMetadata(array $classMetadatas): string
$classMetadata->getClassDiscriminatorMapping()->getTypesMapping(),
] : null;
- $compiled .= sprintf("\n'%s' => %s,", $classMetadata->getName(), VarExporter::export([
+ $compiled .= \sprintf("\n'%s' => %s,", $classMetadata->getName(), VarExporter::export([
$attributesMetadata,
$classDiscriminatorMapping,
]));
diff --git a/Mapping/Factory/ClassResolverTrait.php b/Mapping/Factory/ClassResolverTrait.php
index 7af722d55..d7037f894 100644
--- a/Mapping/Factory/ClassResolverTrait.php
+++ b/Mapping/Factory/ClassResolverTrait.php
@@ -31,7 +31,7 @@ private function getClass(object|string $value): string
{
if (\is_string($value)) {
if (!class_exists($value) && !interface_exists($value, false)) {
- throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $value));
+ throw new InvalidArgumentException(\sprintf('The class or interface "%s" does not exist.', $value));
}
return ltrim($value, '\\');
diff --git a/Mapping/Factory/CompiledClassMetadataFactory.php b/Mapping/Factory/CompiledClassMetadataFactory.php
index f4d41c1e6..ec25d7440 100644
--- a/Mapping/Factory/CompiledClassMetadataFactory.php
+++ b/Mapping/Factory/CompiledClassMetadataFactory.php
@@ -35,7 +35,7 @@ public function __construct(
$compiledClassMetadata = require $compiledClassMetadataFile;
if (!\is_array($compiledClassMetadata)) {
- throw new \RuntimeException(sprintf('Compiled metadata must be of the type array, %s given.', \gettype($compiledClassMetadata)));
+ throw new \RuntimeException(\sprintf('Compiled metadata must be of the type array, %s given.', \gettype($compiledClassMetadata)));
}
$this->compiledClassMetadata = $compiledClassMetadata;
diff --git a/Mapping/Loader/AttributeLoader.php b/Mapping/Loader/AttributeLoader.php
index 1284e91e0..13c59d1c3 100644
--- a/Mapping/Loader/AttributeLoader.php
+++ b/Mapping/Loader/AttributeLoader.php
@@ -53,28 +53,17 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
$className = $reflectionClass->name;
$loaded = false;
$classGroups = [];
- $classContextAnnotation = null;
+ $classContextAttribute = null;
$attributesMetadata = $classMetadata->getAttributesMetadata();
- foreach ($this->loadAttributes($reflectionClass) as $annotation) {
- if ($annotation instanceof DiscriminatorMap) {
- $classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping(
- $annotation->getTypeProperty(),
- $annotation->getMapping()
- ));
- continue;
- }
-
- if ($annotation instanceof Groups) {
- $classGroups = $annotation->getGroups();
-
- continue;
- }
-
- if ($annotation instanceof Context) {
- $classContextAnnotation = $annotation;
- }
+ foreach ($this->loadAttributes($reflectionClass) as $attribute) {
+ match (true) {
+ $attribute instanceof DiscriminatorMap => $classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping($attribute->getTypeProperty(), $attribute->getMapping())),
+ $attribute instanceof Groups => $classGroups = $attribute->getGroups(),
+ $attribute instanceof Context => $classContextAttribute = $attribute,
+ default => null,
+ };
}
foreach ($reflectionClass->getProperties() as $property) {
@@ -83,33 +72,35 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
$classMetadata->addAttributeMetadata($attributesMetadata[$property->name]);
}
+ $attributeMetadata = $attributesMetadata[$property->name];
if ($property->getDeclaringClass()->name === $className) {
- if ($classContextAnnotation) {
- $this->setAttributeContextsForGroups($classContextAnnotation, $attributesMetadata[$property->name]);
+ if ($classContextAttribute) {
+ $this->setAttributeContextsForGroups($classContextAttribute, $attributeMetadata);
}
foreach ($classGroups as $group) {
- $attributesMetadata[$property->name]->addGroup($group);
+ $attributeMetadata->addGroup($group);
}
- foreach ($this->loadAttributes($property) as $annotation) {
- if ($annotation instanceof Groups) {
- foreach ($annotation->getGroups() as $group) {
- $attributesMetadata[$property->name]->addGroup($group);
+ foreach ($this->loadAttributes($property) as $attribute) {
+ $loaded = true;
+
+ if ($attribute instanceof Groups) {
+ foreach ($attribute->getGroups() as $group) {
+ $attributeMetadata->addGroup($group);
}
- } elseif ($annotation instanceof MaxDepth) {
- $attributesMetadata[$property->name]->setMaxDepth($annotation->getMaxDepth());
- } elseif ($annotation instanceof SerializedName) {
- $attributesMetadata[$property->name]->setSerializedName($annotation->getSerializedName());
- } elseif ($annotation instanceof SerializedPath) {
- $attributesMetadata[$property->name]->setSerializedPath($annotation->getSerializedPath());
- } elseif ($annotation instanceof Ignore) {
- $attributesMetadata[$property->name]->setIgnore(true);
- } elseif ($annotation instanceof Context) {
- $this->setAttributeContextsForGroups($annotation, $attributesMetadata[$property->name]);
+
+ continue;
}
- $loaded = true;
+ match (true) {
+ $attribute instanceof MaxDepth => $attributeMetadata->setMaxDepth($attribute->getMaxDepth()),
+ $attribute instanceof SerializedName => $attributeMetadata->setSerializedName($attribute->getSerializedName()),
+ $attribute instanceof SerializedPath => $attributeMetadata->setSerializedPath($attribute->getSerializedPath()),
+ $attribute instanceof Ignore => $attributeMetadata->setIgnore(true),
+ $attribute instanceof Context => $this->setAttributeContextsForGroups($attribute, $attributeMetadata),
+ default => null,
+ };
}
}
}
@@ -135,43 +126,43 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
}
}
- foreach ($this->loadAttributes($method) as $annotation) {
- if ($annotation instanceof Groups) {
+ foreach ($this->loadAttributes($method) as $attribute) {
+ if ($attribute instanceof Groups) {
if (!$accessorOrMutator) {
- throw new MappingException(sprintf('Groups on "%s::%s()" cannot be added. Groups can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
+ throw new MappingException(\sprintf('Groups on "%s::%s()" cannot be added. Groups can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
}
- foreach ($annotation->getGroups() as $group) {
+ foreach ($attribute->getGroups() as $group) {
$attributeMetadata->addGroup($group);
}
- } elseif ($annotation instanceof MaxDepth) {
+ } elseif ($attribute instanceof MaxDepth) {
if (!$accessorOrMutator) {
- throw new MappingException(sprintf('MaxDepth on "%s::%s()" cannot be added. MaxDepth can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
+ throw new MappingException(\sprintf('MaxDepth on "%s::%s()" cannot be added. MaxDepth can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
}
- $attributeMetadata->setMaxDepth($annotation->getMaxDepth());
- } elseif ($annotation instanceof SerializedName) {
+ $attributeMetadata->setMaxDepth($attribute->getMaxDepth());
+ } elseif ($attribute instanceof SerializedName) {
if (!$accessorOrMutator) {
- throw new MappingException(sprintf('SerializedName on "%s::%s()" cannot be added. SerializedName can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
+ throw new MappingException(\sprintf('SerializedName on "%s::%s()" cannot be added. SerializedName can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
}
- $attributeMetadata->setSerializedName($annotation->getSerializedName());
- } elseif ($annotation instanceof SerializedPath) {
+ $attributeMetadata->setSerializedName($attribute->getSerializedName());
+ } elseif ($attribute instanceof SerializedPath) {
if (!$accessorOrMutator) {
- throw new MappingException(sprintf('SerializedPath on "%s::%s()" cannot be added. SerializedPath can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
+ throw new MappingException(\sprintf('SerializedPath on "%s::%s()" cannot be added. SerializedPath can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
}
- $attributeMetadata->setSerializedPath($annotation->getSerializedPath());
- } elseif ($annotation instanceof Ignore) {
+ $attributeMetadata->setSerializedPath($attribute->getSerializedPath());
+ } elseif ($attribute instanceof Ignore) {
if ($accessorOrMutator) {
$attributeMetadata->setIgnore(true);
}
- } elseif ($annotation instanceof Context) {
+ } elseif ($attribute instanceof Context) {
if (!$accessorOrMutator) {
- throw new MappingException(sprintf('Context on "%s::%s()" cannot be added. Context can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
+ throw new MappingException(\sprintf('Context on "%s::%s()" cannot be added. Context can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
}
- $this->setAttributeContextsForGroups($annotation, $attributeMetadata);
+ $this->setAttributeContextsForGroups($attribute, $attributeMetadata);
}
$loaded = true;
@@ -193,30 +184,30 @@ private function loadAttributes(\ReflectionMethod|\ReflectionClass|\ReflectionPr
}
$on = match (true) {
$reflector instanceof \ReflectionClass => ' on class '.$reflector->name,
- $reflector instanceof \ReflectionMethod => sprintf(' on "%s::%s()"', $reflector->getDeclaringClass()->name, $reflector->name),
- $reflector instanceof \ReflectionProperty => sprintf(' on "%s::$%s"', $reflector->getDeclaringClass()->name, $reflector->name),
+ $reflector instanceof \ReflectionMethod => \sprintf(' on "%s::%s()"', $reflector->getDeclaringClass()->name, $reflector->name),
+ $reflector instanceof \ReflectionProperty => \sprintf(' on "%s::$%s"', $reflector->getDeclaringClass()->name, $reflector->name),
default => '',
};
- throw new MappingException(sprintf('Could not instantiate attribute "%s"%s.', $attribute->getName(), $on), 0, $e);
+ throw new MappingException(\sprintf('Could not instantiate attribute "%s"%s.', $attribute->getName(), $on), 0, $e);
}
}
}
}
- private function setAttributeContextsForGroups(Context $annotation, AttributeMetadataInterface $attributeMetadata): void
+ private function setAttributeContextsForGroups(Context $attribute, AttributeMetadataInterface $attributeMetadata): void
{
- if ($annotation->getContext()) {
- $attributeMetadata->setNormalizationContextForGroups($annotation->getContext(), $annotation->getGroups());
- $attributeMetadata->setDenormalizationContextForGroups($annotation->getContext(), $annotation->getGroups());
- }
+ $context = $attribute->getContext();
+ $groups = $attribute->getGroups();
+ $normalizationContext = $attribute->getNormalizationContext();
+ $denormalizationContext = $attribute->getDenormalizationContext();
- if ($annotation->getNormalizationContext()) {
- $attributeMetadata->setNormalizationContextForGroups($annotation->getNormalizationContext(), $annotation->getGroups());
+ if ($normalizationContext || $context) {
+ $attributeMetadata->setNormalizationContextForGroups($normalizationContext ?: $context, $groups);
}
- if ($annotation->getDenormalizationContext()) {
- $attributeMetadata->setDenormalizationContextForGroups($annotation->getDenormalizationContext(), $annotation->getGroups());
+ if ($denormalizationContext || $context) {
+ $attributeMetadata->setDenormalizationContextForGroups($denormalizationContext ?: $context, $groups);
}
}
diff --git a/Mapping/Loader/FileLoader.php b/Mapping/Loader/FileLoader.php
index 7fda4ebd5..ac68d21e8 100644
--- a/Mapping/Loader/FileLoader.php
+++ b/Mapping/Loader/FileLoader.php
@@ -20,23 +20,20 @@
*/
abstract class FileLoader implements LoaderInterface
{
- protected string $file;
-
/**
* @param string $file The mapping file to load
*
* @throws MappingException if the mapping file does not exist or is not readable
*/
- public function __construct(string $file)
- {
+ public function __construct(
+ protected string $file,
+ ) {
if (!is_file($file)) {
- throw new MappingException(sprintf('The mapping file "%s" does not exist.', $file));
+ throw new MappingException(\sprintf('The mapping file "%s" does not exist.', $file));
}
if (!is_readable($file)) {
- throw new MappingException(sprintf('The mapping file "%s" is not readable.', $file));
+ throw new MappingException(\sprintf('The mapping file "%s" is not readable.', $file));
}
-
- $this->file = $file;
}
}
diff --git a/Mapping/Loader/LoaderChain.php b/Mapping/Loader/LoaderChain.php
index e93a0a7b0..41abf8cec 100644
--- a/Mapping/Loader/LoaderChain.php
+++ b/Mapping/Loader/LoaderChain.php
@@ -38,7 +38,7 @@ public function __construct(private readonly array $loaders)
{
foreach ($loaders as $loader) {
if (!$loader instanceof LoaderInterface) {
- throw new MappingException(sprintf('Class "%s" is expected to implement LoaderInterface.', get_debug_type($loader)));
+ throw new MappingException(\sprintf('Class "%s" is expected to implement LoaderInterface.', get_debug_type($loader)));
}
}
}
diff --git a/Mapping/Loader/XmlFileLoader.php b/Mapping/Loader/XmlFileLoader.php
index b36fb871d..44ba89df1 100644
--- a/Mapping/Loader/XmlFileLoader.php
+++ b/Mapping/Loader/XmlFileLoader.php
@@ -70,7 +70,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
try {
$attributeMetadata->setSerializedPath(new PropertyPath((string) $attribute['serialized-path']));
} catch (InvalidPropertyPathException) {
- throw new MappingException(sprintf('The "serialized-path" value must be a valid property path for the attribute "%s" of the class "%s".', $attributeName, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "serialized-path" value must be a valid property path for the attribute "%s" of the class "%s".', $attributeName, $classMetadata->getName()));
}
}
diff --git a/Mapping/Loader/YamlFileLoader.php b/Mapping/Loader/YamlFileLoader.php
index b0398355a..ca71cbcba 100644
--- a/Mapping/Loader/YamlFileLoader.php
+++ b/Mapping/Loader/YamlFileLoader.php
@@ -59,12 +59,12 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
if (isset($data['groups'])) {
if (!\is_array($data['groups'])) {
- throw new MappingException(sprintf('The "groups" key must be an array of strings in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "groups" key must be an array of strings in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
foreach ($data['groups'] as $group) {
if (!\is_string($group)) {
- throw new MappingException(sprintf('Group names must be strings in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('Group names must be strings in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
$attributeMetadata->addGroup($group);
@@ -73,7 +73,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
if (isset($data['max_depth'])) {
if (!\is_int($data['max_depth'])) {
- throw new MappingException(sprintf('The "max_depth" value must be an integer in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "max_depth" value must be an integer in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
$attributeMetadata->setMaxDepth($data['max_depth']);
@@ -81,7 +81,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
if (isset($data['serialized_name'])) {
if (!\is_string($data['serialized_name']) || '' === $data['serialized_name']) {
- throw new MappingException(sprintf('The "serialized_name" value must be a non-empty string in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "serialized_name" value must be a non-empty string in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
$attributeMetadata->setSerializedName($data['serialized_name']);
@@ -91,13 +91,13 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
try {
$attributeMetadata->setSerializedPath(new PropertyPath((string) $data['serialized_path']));
} catch (InvalidPropertyPathException) {
- throw new MappingException(sprintf('The "serialized_path" value must be a valid property path in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "serialized_path" value must be a valid property path in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
}
if (isset($data['ignore'])) {
if (!\is_bool($data['ignore'])) {
- throw new MappingException(sprintf('The "ignore" value must be a boolean in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
+ throw new MappingException(\sprintf('The "ignore" value must be a boolean in "%s" for the attribute "%s" of the class "%s".', $this->file, $attribute, $classMetadata->getName()));
}
$attributeMetadata->setIgnore($data['ignore']);
@@ -124,11 +124,11 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
if (isset($yaml['discriminator_map'])) {
if (!isset($yaml['discriminator_map']['type_property'])) {
- throw new MappingException(sprintf('The "type_property" key must be set for the discriminator map of the class "%s" in "%s".', $classMetadata->getName(), $this->file));
+ throw new MappingException(\sprintf('The "type_property" key must be set for the discriminator map of the class "%s" in "%s".', $classMetadata->getName(), $this->file));
}
if (!isset($yaml['discriminator_map']['mapping'])) {
- throw new MappingException(sprintf('The "mapping" key must be set for the discriminator map of the class "%s" in "%s".', $classMetadata->getName(), $this->file));
+ throw new MappingException(\sprintf('The "mapping" key must be set for the discriminator map of the class "%s" in "%s".', $classMetadata->getName(), $this->file));
}
$classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping(
@@ -153,7 +153,7 @@ public function getMappedClasses(): array
private function getClassesFromYaml(): array
{
if (!stream_is_local($this->file)) {
- throw new MappingException(sprintf('This is not a local file "%s".', $this->file));
+ throw new MappingException(\sprintf('This is not a local file "%s".', $this->file));
}
$this->yamlParser ??= new Parser();
@@ -165,7 +165,7 @@ private function getClassesFromYaml(): array
}
if (!\is_array($classes)) {
- throw new MappingException(sprintf('The file "%s" must contain a YAML array.', $this->file));
+ throw new MappingException(\sprintf('The file "%s" must contain a YAML array.', $this->file));
}
return $classes;
diff --git a/NameConverter/AdvancedNameConverterInterface.php b/NameConverter/AdvancedNameConverterInterface.php
index 1e74f4d20..975d28fd3 100644
--- a/NameConverter/AdvancedNameConverterInterface.php
+++ b/NameConverter/AdvancedNameConverterInterface.php
@@ -15,6 +15,8 @@
* 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
{
diff --git a/NameConverter/CamelCaseToSnakeCaseNameConverter.php b/NameConverter/CamelCaseToSnakeCaseNameConverter.php
index 47d69d3ab..033ec94b7 100644
--- a/NameConverter/CamelCaseToSnakeCaseNameConverter.php
+++ b/NameConverter/CamelCaseToSnakeCaseNameConverter.php
@@ -27,8 +27,8 @@ class CamelCaseToSnakeCaseNameConverter implements NameConverterInterface
public const REQUIRE_SNAKE_CASE_PROPERTIES = 'require_snake_case_properties';
/**
- * @param array|null $attributes The list of attributes to rename or null for all attributes
- * @param bool $lowerCamelCase Use lowerCamelCase style
+ * @param string[]|null $attributes The list of attributes to rename or null for all attributes
+ * @param bool $lowerCamelCase Use lowerCamelCase style
*/
public function __construct(
private ?array $attributes = null,
diff --git a/NameConverter/MetadataAwareNameConverter.php b/NameConverter/MetadataAwareNameConverter.php
index 445ad7422..c72f148eb 100644
--- a/NameConverter/MetadataAwareNameConverter.php
+++ b/NameConverter/MetadataAwareNameConverter.php
@@ -80,7 +80,7 @@ private function getCacheValueForNormalization(string $propertyName, string $cla
}
if (null !== $attributesMetadata[$propertyName]->getSerializedName() && null !== $attributesMetadata[$propertyName]->getSerializedPath()) {
- throw new LogicException(sprintf('Found SerializedName and SerializedPath attributes on property "%s" of class "%s".', $propertyName, $class));
+ throw new LogicException(\sprintf('Found SerializedName and SerializedPath attributes on property "%s" of class "%s".', $propertyName, $class));
}
return $attributesMetadata[$propertyName]->getSerializedName() ?? null;
@@ -124,7 +124,7 @@ private function getCacheValueForAttributesMetadata(string $class, array $contex
}
if (null !== $metadata->getSerializedName() && null !== $metadata->getSerializedPath()) {
- throw new LogicException(sprintf('Found SerializedName and SerializedPath attributes on property "%s" of class "%s".', $name, $class));
+ throw new LogicException(\sprintf('Found SerializedName and SerializedPath attributes on property "%s" of class "%s".', $name, $class));
}
$metadataGroups = $metadata->getGroups();
diff --git a/NameConverter/SnakeCaseToCamelCaseNameConverter.php b/NameConverter/SnakeCaseToCamelCaseNameConverter.php
new file mode 100644
index 000000000..cb93d3e98
--- /dev/null
+++ b/NameConverter/SnakeCaseToCamelCaseNameConverter.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Serializer\NameConverter;
+
+use Symfony\Component\Serializer\Exception\UnexpectedPropertyException;
+
+/**
+ * Underscore to camelCase name converter.
+ *
+ * @author Kévin Dunglas
+ */
+final readonly class SnakeCaseToCamelCaseNameConverter implements NameConverterInterface
+{
+ /**
+ * Require all properties to be written in camelCase.
+ */
+ public const REQUIRE_CAMEL_CASE_PROPERTIES = 'require_camel_case_properties';
+
+ /**
+ * @param string[]|null $attributes The list of attributes to rename or null for all attributes
+ * @param bool $lowerCamelCase Use lowerCamelCase style
+ */
+ public function __construct(
+ private ?array $attributes = null,
+ private bool $lowerCamelCase = true,
+ ) {
+ }
+
+ /**
+ * @param class-string|null $class
+ * @param array $context
+ */
+ 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 $propertyName;
+ }
+
+ $camelCasedName = preg_replace_callback(
+ '/(^|_|\.)+(.)/',
+ fn ($match) => ('.' === $match[1] ? '_' : '').strtoupper($match[2]),
+ $propertyName
+ );
+
+ if ($this->lowerCamelCase) {
+ $camelCasedName = lcfirst($camelCasedName);
+ }
+
+ return $camelCasedName;
+ }
+
+ /**
+ * @param class-string|null $class
+ * @param array $context
+ */
+ public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string
+ {
+ if (($context[self::REQUIRE_CAMEL_CASE_PROPERTIES] ?? false) && $propertyName !== $this->normalize($propertyName, $class, $format, $context)) {
+ throw new UnexpectedPropertyException($propertyName);
+ }
+
+ $snakeCased = strtolower(preg_replace('/[A-Z]/', '_\\0', lcfirst($propertyName)));
+ if (null === $this->attributes || \in_array($snakeCased, $this->attributes, true)) {
+ return $snakeCased;
+ }
+
+ return $propertyName;
+ }
+}
diff --git a/Normalizer/AbstractNormalizer.php b/Normalizer/AbstractNormalizer.php
index d8f796b4c..04f378c46 100644
--- a/Normalizer/AbstractNormalizer.php
+++ b/Normalizer/AbstractNormalizer.php
@@ -139,22 +139,21 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
self::CIRCULAR_REFERENCE_LIMIT => 1,
self::IGNORED_ATTRIBUTES => [],
];
- protected ?ClassMetadataFactoryInterface $classMetadataFactory;
- protected ?NameConverterInterface $nameConverter;
/**
* Sets the {@link ClassMetadataFactoryInterface} to use.
*/
- public function __construct(?ClassMetadataFactoryInterface $classMetadataFactory = null, ?NameConverterInterface $nameConverter = null, array $defaultContext = [])
- {
- $this->classMetadataFactory = $classMetadataFactory;
- $this->nameConverter = $nameConverter;
+ public function __construct(
+ protected ?ClassMetadataFactoryInterface $classMetadataFactory = null,
+ protected ?NameConverterInterface $nameConverter = null,
+ array $defaultContext = [],
+ ) {
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
$this->validateCallbackContext($this->defaultContext, 'default');
if (isset($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER]) && !\is_callable($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER])) {
- throw new InvalidArgumentException(sprintf('Invalid callback found in the "%s" default context option.', self::CIRCULAR_REFERENCE_HANDLER));
+ throw new InvalidArgumentException(\sprintf('Invalid callback found in the "%s" default context option.', self::CIRCULAR_REFERENCE_HANDLER));
}
}
@@ -200,7 +199,7 @@ protected function handleCircularReference(object $object, ?string $format = nul
return $circularReferenceHandler($object, $format, $context);
}
- throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d).', get_debug_type($object), $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT]));
+ throw new CircularReferenceException(\sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d).', get_debug_type($object), $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT]));
}
/**
@@ -217,7 +216,7 @@ protected function getAllowedAttributes(string|object $classOrObject, array $con
$allowExtraAttributes = $context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES];
if (!$this->classMetadataFactory) {
if (!$allowExtraAttributes) {
- throw new LogicException(sprintf('A class metadata factory must be provided in the constructor when setting "%s" to false.', self::ALLOW_EXTRA_ATTRIBUTES));
+ throw new LogicException(\sprintf('A class metadata factory must be provided in the constructor when setting "%s" to false.', self::ALLOW_EXTRA_ATTRIBUTES));
}
return false;
@@ -342,7 +341,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
if ($constructorParameter->isVariadic()) {
if ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) {
if (!\is_array($data[$key])) {
- throw new RuntimeException(sprintf('Cannot create an instance of "%s" from serialized data because the variadic parameter "%s" can only accept an array.', $class, $constructorParameter->name));
+ throw new RuntimeException(\sprintf('Cannot create an instance of "%s" from serialized data because the variadic parameter "%s" can only accept an array.', $class, $constructorParameter->name));
}
$variadicParameters = [];
@@ -404,7 +403,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
}
$exception = NotNormalizableValueException::createForUnexpectedDataType(
- sprintf('Failed to create object because the class misses the "%s" property.', $constructorParameter->name),
+ \sprintf('Failed to create object because the class misses the "%s" property.', $constructorParameter->name),
null,
[$constructorParameterType],
$attributeContext['deserialization_path'] ?? null,
@@ -415,7 +414,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
}
if ($missingConstructorArguments) {
- throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments, $class);
+ throw new MissingConstructorArgumentsException(\sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments, $class);
}
if (!$constructor->isConstructor()) {
@@ -450,7 +449,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
unset($context['has_constructor']);
if (!$reflectionClass->isInstantiable()) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Failed to create object because the class "%s" is not instantiable.', $class), $data, ['unknown'], $context['deserialization_path'] ?? null);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Failed to create object because the class "%s" is not instantiable.', $class), $data, ['unknown'], $context['deserialization_path'] ?? null);
}
return new $class();
@@ -467,13 +466,13 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
if (!$this->serializer instanceof DenormalizerInterface) {
- throw new LogicException(sprintf('Cannot create an instance of "%s" from serialized data because the serializer inject in "%s" is not a denormalizer.', $parameterClass, static::class));
+ throw new LogicException(\sprintf('Cannot create an instance of "%s" from serialized data because the serializer inject in "%s" is not a denormalizer.', $parameterClass, static::class));
}
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName, $format));
}
} catch (\ReflectionException $e) {
- throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e);
+ throw new RuntimeException(\sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e);
} catch (MissingConstructorArgumentsException $e) {
if (!$parameter->getType()->allowsNull()) {
throw $e;
@@ -515,12 +514,12 @@ final protected function validateCallbackContext(array $context, string $context
}
if (!\is_array($context[self::CALLBACKS])) {
- throw new InvalidArgumentException(sprintf('The "%s"%s context option must be an array of callables.', self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
+ throw new InvalidArgumentException(\sprintf('The "%s"%s context option must be an array of callables.', self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
}
foreach ($context[self::CALLBACKS] as $attribute => $callback) {
if (!\is_callable($callback)) {
- throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s"%s context option.', $attribute, self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
+ throw new InvalidArgumentException(\sprintf('Invalid callback found for attribute "%s" in the "%s"%s context option.', $attribute, self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
}
}
}
diff --git a/Normalizer/AbstractObjectNormalizer.php b/Normalizer/AbstractObjectNormalizer.php
index 1860425f9..00d2e3b00 100644
--- a/Normalizer/AbstractObjectNormalizer.php
+++ b/Normalizer/AbstractObjectNormalizer.php
@@ -137,7 +137,7 @@ public function __construct(
parent::__construct($classMetadataFactory, $nameConverter, $defaultContext);
if (isset($this->defaultContext[self::MAX_DEPTH_HANDLER]) && !\is_callable($this->defaultContext[self::MAX_DEPTH_HANDLER])) {
- throw new InvalidArgumentException(sprintf('The "%s" given in the default context is not callable.', self::MAX_DEPTH_HANDLER));
+ throw new InvalidArgumentException(\sprintf('The "%s" given in the default context is not callable.', self::MAX_DEPTH_HANDLER));
}
$this->defaultContext[self::EXCLUDE_FROM_CACHE_KEY] = array_merge($this->defaultContext[self::EXCLUDE_FROM_CACHE_KEY] ?? [], [self::CIRCULAR_REFERENCE_LIMIT_COUNTERS]);
@@ -177,7 +177,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
if (isset($context[self::MAX_DEPTH_HANDLER])) {
$maxDepthHandler = $context[self::MAX_DEPTH_HANDLER];
if (!\is_callable($maxDepthHandler)) {
- throw new InvalidArgumentException(sprintf('The "%s" given in the context is not callable.', self::MAX_DEPTH_HANDLER));
+ throw new InvalidArgumentException(\sprintf('The "%s" given in the context is not callable.', self::MAX_DEPTH_HANDLER));
}
} else {
$maxDepthHandler = null;
@@ -218,7 +218,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
}
if (!$this->serializer instanceof NormalizerInterface) {
- throw new LogicException(sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer.', $attribute));
+ throw new LogicException(\sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer.', $attribute));
}
$childContext = $this->createChildContext($attributeContext, $attribute, $format);
@@ -344,7 +344,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
$notConverted = $attribute;
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context);
if (isset($nestedData[$notConverted]) && !isset($originalNestedData[$attribute])) {
- throw new LogicException(sprintf('Duplicate values for key "%s" found. One value is set via the SerializedPath attribute: "%s", the other one is set via the SerializedName attribute: "%s".', $notConverted, implode('->', $nestedAttributes[$notConverted]->getElements()), $attribute));
+ throw new LogicException(\sprintf('Duplicate values for key "%s" found. One value is set via the SerializedPath attribute: "%s", the other one is set via the SerializedName attribute: "%s".', $notConverted, implode('->', $nestedAttributes[$notConverted]->getElements()), $attribute));
}
}
@@ -397,7 +397,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
$this->setAttributeValue($object, $attribute, $value, $format, $attributeContext);
} catch (PropertyAccessInvalidArgumentException $e) {
$exception = NotNormalizableValueException::createForUnexpectedDataType(
- sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $resolvedClass),
+ \sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $resolvedClass),
$data,
$e instanceof InvalidTypeException ? [$e->expectedType] : ['unknown'],
$attributeContext['deserialization_path'] ?? null,
@@ -488,14 +488,14 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
} 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);
+ 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);
+ 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:
@@ -507,7 +507,7 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
'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),
+ 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),
};
}
}
@@ -550,7 +550,7 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
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));
+ 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);
@@ -633,7 +633,7 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
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);
+ 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);
}
/**
@@ -658,7 +658,6 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
$e = null;
$extraAttributesException = null;
$missingConstructorArgumentsException = null;
- $isNullable = false;
$types = match (true) {
$type instanceof IntersectionType => throw new LogicException('Unable to handle intersection type.'),
@@ -715,11 +714,6 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
if (TypeIdentifier::STRING === $typeIdentifier) {
return '';
}
-
- // BC layer for type-info < 7.2
- if (method_exists(Type::class, 'isNullable')) {
- $isNullable = $isNullable ?: $type->isNullable();
- }
}
switch ($typeIdentifier) {
@@ -730,14 +724,14 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
} 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, [Type::bool()], $context['deserialization_path'] ?? null);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).', $attribute, $currentClass, $data), $data, [Type::bool()], $context['deserialization_path'] ?? null);
}
break;
case TypeIdentifier::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, [Type::int()], $context['deserialization_path'] ?? null);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).', $attribute, $currentClass, $data), $data, [Type::int()], $context['deserialization_path'] ?? null);
}
break;
case TypeIdentifier::FLOAT:
@@ -749,7 +743,7 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
'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, [Type::float()], $context['deserialization_path'] ?? null),
+ default => throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).', $attribute, $currentClass, $data), $data, [Type::float()], $context['deserialization_path'] ?? null),
};
}
}
@@ -835,7 +829,7 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
if (TypeIdentifier::OBJECT === $typeIdentifier && 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));
+ 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);
@@ -879,17 +873,17 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
return $data;
}
} catch (NotNormalizableValueException|InvalidArgumentException $e) {
- if (!$isUnionType && !$isNullable) {
+ if (!$type instanceof UnionType) {
throw $e;
}
} catch (ExtraAttributesException $e) {
- if (!$isUnionType && !$isNullable) {
+ if (!$type instanceof UnionType) {
throw $e;
}
$extraAttributesException ??= $e;
} catch (MissingConstructorArgumentsException $e) {
- if (!$isUnionType && !$isNullable) {
+ if (!$type instanceof UnionType) {
throw $e;
}
@@ -924,7 +918,7 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
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);
+ 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);
}
/**
@@ -1011,7 +1005,7 @@ private function updateData(array $data, string $attribute, mixed $attributeValu
if (null !== $classMetadata && null !== $serializedPath = ($attributesMetadata[$attribute] ?? null)?->getSerializedPath()) {
$propertyAccessor = PropertyAccess::createPropertyAccessor();
if ($propertyAccessor->isReadable($data, $serializedPath) && null !== $propertyAccessor->getValue($data, $serializedPath)) {
- throw new LogicException(sprintf('The element you are trying to set is already populated: "%s".', (string) $serializedPath));
+ throw new LogicException(\sprintf('The element you are trying to set is already populated: "%s".', (string) $serializedPath));
}
$propertyAccessor->setValue($data, $serializedPath, $attributeValue);
@@ -1040,7 +1034,7 @@ private function isMaxDepthReached(array $attributesMetadata, string $class, str
return false;
}
- $key = sprintf(self::DEPTH_KEY_PATTERN, $class, $attribute);
+ $key = \sprintf(self::DEPTH_KEY_PATTERN, $class, $attribute);
if (!isset($context[$key])) {
$context[$key] = 1;
@@ -1129,7 +1123,7 @@ private function getNestedAttributes(string $class): array
}
$pathIdentifier = implode(',', $serializedPath->getElements());
if (isset($serializedPaths[$pathIdentifier])) {
- throw new LogicException(sprintf('Duplicate serialized path: "%s" used for properties "%s" and "%s".', $pathIdentifier, $serializedPaths[$pathIdentifier], $name));
+ throw new LogicException(\sprintf('Duplicate serialized path: "%s" used for properties "%s" and "%s".', $pathIdentifier, $serializedPaths[$pathIdentifier], $name));
}
$serializedPaths[$pathIdentifier] = $name;
$properties[$name] = $serializedPath;
@@ -1162,11 +1156,11 @@ private function getMappedClass(array $data, string $class, array $context): str
}
if (null === $type = $data[$mapping->getTypeProperty()] ?? null) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Type property "%s" not found for the abstract object "%s".', $mapping->getTypeProperty(), $class), null, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), false);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Type property "%s" not found for the abstract object "%s".', $mapping->getTypeProperty(), $class), null, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), false);
}
if (null === $mappedClass = $mapping->getClassForType($type)) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type "%s" is not a valid value.', $type), $type, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), true);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type "%s" is not a valid value.', $type), $type, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), true);
}
return $mappedClass;
diff --git a/Normalizer/ArrayDenormalizer.php b/Normalizer/ArrayDenormalizer.php
index 964d74b61..96c4d259c 100644
--- a/Normalizer/ArrayDenormalizer.php
+++ b/Normalizer/ArrayDenormalizer.php
@@ -31,11 +31,6 @@ class ArrayDenormalizer implements DenormalizerInterface, DenormalizerAwareInter
{
use DenormalizerAwareTrait;
- public function setDenormalizer(DenormalizerInterface $denormalizer): void
- {
- $this->denormalizer = $denormalizer;
- }
-
public function getSupportedTypes(?string $format): array
{
return ['object' => null, '*' => false];
@@ -50,7 +45,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
throw new BadMethodCallException('Please set a denormalizer before calling denormalize()!');
}
if (!\is_array($data)) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Data expected to be "%s", "%s" given.', $type, get_debug_type($data)), $data, ['array'], $context['deserialization_path'] ?? null);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Data expected to be "%s", "%s" given.', $type, get_debug_type($data)), $data, ['array'], $context['deserialization_path'] ?? null);
}
if (!str_ends_with($type, '[]')) {
throw new InvalidArgumentException('Unsupported class: '.$type);
@@ -77,7 +72,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
foreach ($data as $key => $value) {
$subContext = $context;
- $subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
+ $subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? \sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
$this->validateKeyType($typeIdentifiers, $key, $subContext['deserialization_path']);
@@ -90,7 +85,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
{
if (!isset($this->denormalizer)) {
- throw new BadMethodCallException(sprintf('The nested denormalizer needs to be set to allow "%s()" to be used.', __METHOD__));
+ throw new BadMethodCallException(\sprintf('The nested denormalizer needs to be set to allow "%s()" to be used.', __METHOD__));
}
return str_ends_with($type, '[]')
@@ -112,6 +107,6 @@ private function validateKeyType(array $typeIdentifiers, mixed $key, string $pat
}
}
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, implode('", "', $typeIdentifiers), get_debug_type($key)), $key, $typeIdentifiers, $path, true);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, implode('", "', $typeIdentifiers), get_debug_type($key)), $key, $typeIdentifiers, $path, true);
}
}
diff --git a/Normalizer/BackedEnumNormalizer.php b/Normalizer/BackedEnumNormalizer.php
index 504047bc1..3d8e7e7c5 100644
--- a/Normalizer/BackedEnumNormalizer.php
+++ b/Normalizer/BackedEnumNormalizer.php
@@ -29,7 +29,7 @@ final class BackedEnumNormalizer implements NormalizerInterface, DenormalizerInt
public function getSupportedTypes(?string $format): array
{
return [
- \BackedEnum::class => true,
+ \BackedEnum::class => true,
];
}
diff --git a/Normalizer/ConstraintViolationListNormalizer.php b/Normalizer/ConstraintViolationListNormalizer.php
index eeb6ab462..eda3b758e 100644
--- a/Normalizer/ConstraintViolationListNormalizer.php
+++ b/Normalizer/ConstraintViolationListNormalizer.php
@@ -69,7 +69,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
'parameters' => $violation->getParameters(),
];
if (null !== $code = $violation->getCode()) {
- $violationEntry['type'] = sprintf('urn:uuid:%s', $code);
+ $violationEntry['type'] = \sprintf('urn:uuid:%s', $code);
}
$constraint = $violation->getConstraint();
@@ -85,7 +85,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
$violations[] = $violationEntry;
- $prefix = $propertyPath ? sprintf('%s: ', $propertyPath) : '';
+ $prefix = $propertyPath ? \sprintf('%s: ', $propertyPath) : '';
$messages[] = $prefix.$violation->getMessage();
}
diff --git a/Normalizer/DataUriNormalizer.php b/Normalizer/DataUriNormalizer.php
index bd1dc822b..5ee076be6 100644
--- a/Normalizer/DataUriNormalizer.php
+++ b/Normalizer/DataUriNormalizer.php
@@ -44,11 +44,7 @@ public function __construct(?MimeTypeGuesserInterface $mimeTypeGuesser = null)
public function getSupportedTypes(?string $format): array
{
- return [
- \SplFileInfo::class => true,
- \SplFileObject::class => true,
- File::class => true,
- ];
+ return self::SUPPORTED_TYPES;
}
public function normalize(mixed $object, ?string $format = null, array $context = []): string
@@ -68,10 +64,10 @@ public function normalize(mixed $object, ?string $format = null, array $context
}
if ('text' === explode('/', $mimeType, 2)[0]) {
- return sprintf('data:%s,%s', $mimeType, rawurlencode($data));
+ return \sprintf('data:%s,%s', $mimeType, rawurlencode($data));
}
- return sprintf('data:%s;base64,%s', $mimeType, base64_encode($data));
+ return \sprintf('data:%s;base64,%s', $mimeType, base64_encode($data));
}
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
@@ -97,7 +93,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
switch ($type) {
case File::class:
if (!class_exists(File::class)) {
- throw new InvalidArgumentException(sprintf('Cannot denormalize to a "%s" without the HttpFoundation component installed. Try running "composer require symfony/http-foundation".', File::class));
+ throw new InvalidArgumentException(\sprintf('Cannot denormalize to a "%s" without the HttpFoundation component installed. Try running "composer require symfony/http-foundation".', File::class));
}
return new File($data, false);
@@ -110,7 +106,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
throw NotNormalizableValueException::createForUnexpectedDataType($exception->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, false, $exception->getCode(), $exception);
}
- throw new InvalidArgumentException(sprintf('The class parameter "%s" is not supported. It must be one of "SplFileInfo", "SplFileObject" or "Symfony\Component\HttpFoundation\File\File".', $type));
+ throw new InvalidArgumentException(\sprintf('The class parameter "%s" is not supported. It must be one of "SplFileInfo", "SplFileObject" or "Symfony\Component\HttpFoundation\File\File".', $type));
}
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
diff --git a/Normalizer/DateIntervalNormalizer.php b/Normalizer/DateIntervalNormalizer.php
index 995d4f6a3..05d1a8529 100644
--- a/Normalizer/DateIntervalNormalizer.php
+++ b/Normalizer/DateIntervalNormalizer.php
@@ -85,7 +85,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
}
$valuePattern = '/^'.$signPattern.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?:(?P<$1>\d+)$2)?', preg_replace('/(T.*)$/', '($1)?', $dateIntervalFormat)).'$/';
if (!preg_match($valuePattern, $data)) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat), $data, ['string'], $context['deserialization_path'] ?? null, false);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat), $data, ['string'], $context['deserialization_path'] ?? null, false);
}
try {
diff --git a/Normalizer/DateTimeNormalizer.php b/Normalizer/DateTimeNormalizer.php
index 71ce26496..dfc498c19 100644
--- a/Normalizer/DateTimeNormalizer.php
+++ b/Normalizer/DateTimeNormalizer.php
@@ -50,11 +50,7 @@ public function setDefaultContext(array $defaultContext): void
public function getSupportedTypes(?string $format): array
{
- return [
- \DateTimeInterface::class => true,
- \DateTimeImmutable::class => true,
- \DateTime::class => true,
- ];
+ return self::SUPPORTED_TYPES;
}
/**
@@ -94,10 +90,10 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
if (\is_int($data) || \is_float($data)) {
switch ($context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY] ?? null) {
case 'U':
- $data = sprintf('%d', $data);
+ $data = \sprintf('%d', $data);
break;
case 'U.u':
- $data = sprintf('%.6F', $data);
+ $data = \sprintf('%.6F', $data);
break;
}
}
@@ -121,7 +117,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
$dateTimeErrors = $type::getLastErrors();
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors: ', $data, $dateTimeFormat, $dateTimeErrors['error_count'])."\n".implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])), $data, ['string'], $context['deserialization_path'] ?? null, true);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors: ', $data, $dateTimeFormat, $dateTimeErrors['error_count'])."\n".implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])), $data, ['string'], $context['deserialization_path'] ?? null, true);
}
$defaultDateTimeFormat = $this->defaultContext[self::FORMAT_KEY] ?? null;
@@ -142,7 +138,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
{
- return isset(self::SUPPORTED_TYPES[$type]);
+ return is_a($type, \DateTimeInterface::class, true);
}
/**
@@ -155,7 +151,7 @@ private function formatDateTimeErrors(array $errors): array
$formattedErrors = [];
foreach ($errors as $pos => $message) {
- $formattedErrors[] = sprintf('at position %d: %s', $pos, $message);
+ $formattedErrors[] = \sprintf('at position %d: %s', $pos, $message);
}
return $formattedErrors;
diff --git a/Normalizer/GetSetMethodNormalizer.php b/Normalizer/GetSetMethodNormalizer.php
index ec3d7cb10..4d2d7829a 100644
--- a/Normalizer/GetSetMethodNormalizer.php
+++ b/Normalizer/GetSetMethodNormalizer.php
@@ -100,6 +100,7 @@ private function isSetMethod(\ReflectionMethod $method): bool
return !$method->isStatic()
&& !$method->getAttributes(Ignore::class)
&& 0 < $method->getNumberOfParameters()
+ && 3 < \strlen($method->name)
&& str_starts_with($method->name, 'set')
&& !ctype_lower($method->name[3])
;
@@ -166,7 +167,7 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string
return false;
}
- $class = \is_object($classOrObject) ? \get_class($classOrObject) : $classOrObject;
+ $class = \is_object($classOrObject) ? $classOrObject::class : $classOrObject;
if (!isset(self::$reflectionCache[$class])) {
self::$reflectionCache[$class] = new \ReflectionClass($class);
diff --git a/Normalizer/JsonSerializableNormalizer.php b/Normalizer/JsonSerializableNormalizer.php
index 1287627fb..31c224175 100644
--- a/Normalizer/JsonSerializableNormalizer.php
+++ b/Normalizer/JsonSerializableNormalizer.php
@@ -28,7 +28,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
}
if (!$object instanceof \JsonSerializable) {
- throw new InvalidArgumentException(sprintf('The object must implement "%s".', \JsonSerializable::class));
+ throw new InvalidArgumentException(\sprintf('The object must implement "%s".', \JsonSerializable::class));
}
if (!$this->serializer instanceof NormalizerInterface) {
@@ -57,6 +57,6 @@ public function supportsDenormalization(mixed $data, string $type, ?string $form
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
{
- throw new LogicException(sprintf('Cannot denormalize with "%s".', \JsonSerializable::class));
+ throw new LogicException(\sprintf('Cannot denormalize with "%s".', \JsonSerializable::class));
}
}
diff --git a/Normalizer/MimeMessageNormalizer.php b/Normalizer/MimeMessageNormalizer.php
index 7006ab321..633edf369 100644
--- a/Normalizer/MimeMessageNormalizer.php
+++ b/Normalizer/MimeMessageNormalizer.php
@@ -56,7 +56,7 @@ public function getSupportedTypes(?string $format): array
public function setSerializer(SerializerInterface $serializer): void
{
if (!$serializer instanceof NormalizerInterface || !$serializer instanceof DenormalizerInterface) {
- throw new LogicException(sprintf('The passed serializer should implement both NormalizerInterface and DenormalizerInterface, "%s" given.', get_debug_type($serializer)));
+ throw new LogicException(\sprintf('The passed serializer should implement both NormalizerInterface and DenormalizerInterface, "%s" given.', get_debug_type($serializer)));
}
$this->serializer = $serializer;
$this->normalizer->setSerializer($serializer);
diff --git a/Normalizer/NormalizerInterface.php b/Normalizer/NormalizerInterface.php
index 562f87c28..bbc8a94e7 100644
--- a/Normalizer/NormalizerInterface.php
+++ b/Normalizer/NormalizerInterface.php
@@ -22,9 +22,9 @@
interface NormalizerInterface
{
/**
- * Normalizes an object into a set of arrays/scalars.
+ * Normalizes data into a set of arrays/scalars.
*
- * @param mixed $object Object to normalize
+ * @param mixed $data Data to normalize
* @param string|null $format Format the normalization result will be encoded as
* @param array $context Context options for the normalizer
*
@@ -36,7 +36,7 @@ interface NormalizerInterface
* @throws LogicException Occurs when the normalizer is not called in an expected context
* @throws ExceptionInterface Occurs for all the other cases of errors
*/
- public function normalize(mixed $object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null;
+ public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null;
/**
* Checks whether the given class is supported for normalization by this normalizer.
diff --git a/Normalizer/ObjectNormalizer.php b/Normalizer/ObjectNormalizer.php
index 4466e7428..1d60cba50 100644
--- a/Normalizer/ObjectNormalizer.php
+++ b/Normalizer/ObjectNormalizer.php
@@ -179,7 +179,7 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string
return false;
}
- $class = \is_object($classOrObject) ? \get_class($classOrObject) : $classOrObject;
+ $class = \is_object($classOrObject) ? $classOrObject::class : $classOrObject;
if ($context['_read_attributes'] ?? true) {
if (!isset(self::$isReadableCache[$class.$attribute])) {
diff --git a/Normalizer/ProblemNormalizer.php b/Normalizer/ProblemNormalizer.php
index 04c680647..08aca6796 100644
--- a/Normalizer/ProblemNormalizer.php
+++ b/Normalizer/ProblemNormalizer.php
@@ -54,7 +54,7 @@ public function getSupportedTypes(?string $format): array
public function normalize(mixed $object, ?string $format = null, array $context = []): array
{
if (!$object instanceof FlattenException) {
- throw new InvalidArgumentException(sprintf('The object must implement "%s".', FlattenException::class));
+ throw new InvalidArgumentException(\sprintf('The object must implement "%s".', FlattenException::class));
}
$data = [];
diff --git a/Normalizer/PropertyNormalizer.php b/Normalizer/PropertyNormalizer.php
index e1d893be8..1619f35bf 100644
--- a/Normalizer/PropertyNormalizer.php
+++ b/Normalizer/PropertyNormalizer.php
@@ -162,7 +162,7 @@ protected function getAttributeValue(object $object, string $attribute, ?string
|| ($reflectionProperty->isProtected() && !\array_key_exists("\0*\0{$reflectionProperty->name}", $propertyValues))
|| ($reflectionProperty->isPrivate() && !\array_key_exists("\0{$reflectionProperty->class}\0{$reflectionProperty->name}", $propertyValues))
) {
- throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not initialized.', $object::class, $reflectionProperty->name));
+ throw new UninitializedPropertyException(\sprintf('The property "%s::$%s" is not initialized.', $object::class, $reflectionProperty->name));
}
}
diff --git a/Normalizer/TranslatableNormalizer.php b/Normalizer/TranslatableNormalizer.php
index 398e00b79..463616e72 100644
--- a/Normalizer/TranslatableNormalizer.php
+++ b/Normalizer/TranslatableNormalizer.php
@@ -37,7 +37,7 @@ public function __construct(
public function normalize(mixed $object, ?string $format = null, array $context = []): string
{
if (!$object instanceof TranslatableInterface) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The object must implement the "%s".', TranslatableInterface::class), $object, [TranslatableInterface::class]);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The object must implement the "%s".', TranslatableInterface::class), $object, [TranslatableInterface::class]);
}
return $object->trans($this->translator, $context[self::NORMALIZATION_LOCALE_KEY] ?? $this->defaultContext[self::NORMALIZATION_LOCALE_KEY]);
diff --git a/Normalizer/UidNormalizer.php b/Normalizer/UidNormalizer.php
index 843d7a550..0bee1f704 100644
--- a/Normalizer/UidNormalizer.php
+++ b/Normalizer/UidNormalizer.php
@@ -22,7 +22,9 @@ final class UidNormalizer implements NormalizerInterface, DenormalizerInterface
public const NORMALIZATION_FORMAT_CANONICAL = 'canonical';
public const NORMALIZATION_FORMAT_BASE58 = 'base58';
public const NORMALIZATION_FORMAT_BASE32 = 'base32';
- public const NORMALIZATION_FORMAT_RFC4122 = 'rfc4122'; // RFC 9562 obsoleted RFC 4122 but the format is the same
+ public const NORMALIZATION_FORMAT_RFC4122 = 'rfc4122';
+ public const NORMALIZATION_FORMAT_RFC9562 = self::NORMALIZATION_FORMAT_RFC4122; // RFC 9562 obsoleted RFC 4122 but the format is the same
+
public const NORMALIZATION_FORMATS = [
self::NORMALIZATION_FORMAT_CANONICAL,
self::NORMALIZATION_FORMAT_BASE58,
@@ -56,7 +58,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
self::NORMALIZATION_FORMAT_BASE58 => $object->toBase58(),
self::NORMALIZATION_FORMAT_BASE32 => $object->toBase32(),
self::NORMALIZATION_FORMAT_RFC4122 => $object->toRfc4122(),
- default => throw new LogicException(sprintf('The "%s" format is not valid.', $context[self::NORMALIZATION_FORMAT_KEY] ?? $this->defaultContext[self::NORMALIZATION_FORMAT_KEY])),
+ default => throw new LogicException(\sprintf('The "%s" format is not valid.', $context[self::NORMALIZATION_FORMAT_KEY] ?? $this->defaultContext[self::NORMALIZATION_FORMAT_KEY])),
};
}
@@ -70,7 +72,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
try {
return $type::fromString($data);
} catch (\InvalidArgumentException|\TypeError) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The data is not a valid "%s" string representation.', $type), $data, ['string'], $context['deserialization_path'] ?? null, true);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The data is not a valid "%s" string representation.', $type), $data, ['string'], $context['deserialization_path'] ?? null, true);
}
}
diff --git a/Serializer.php b/Serializer.php
index d61f009d9..f95f2d72e 100644
--- a/Serializer.php
+++ b/Serializer.php
@@ -96,7 +96,7 @@ public function __construct(
}
if (!($normalizer instanceof NormalizerInterface || $normalizer instanceof DenormalizerInterface)) {
- throw new InvalidArgumentException(sprintf('The class "%s" neither implements "%s" nor "%s".', get_debug_type($normalizer), NormalizerInterface::class, DenormalizerInterface::class));
+ throw new InvalidArgumentException(\sprintf('The class "%s" neither implements "%s" nor "%s".', get_debug_type($normalizer), NormalizerInterface::class, DenormalizerInterface::class));
}
}
@@ -114,7 +114,7 @@ public function __construct(
}
if (!($encoder instanceof EncoderInterface || $encoder instanceof DecoderInterface)) {
- throw new InvalidArgumentException(sprintf('The class "%s" neither implements "%s" nor "%s".', get_debug_type($encoder), EncoderInterface::class, DecoderInterface::class));
+ throw new InvalidArgumentException(\sprintf('The class "%s" neither implements "%s" nor "%s".', get_debug_type($encoder), EncoderInterface::class, DecoderInterface::class));
}
}
$this->encoder = new ChainEncoder($realEncoders);
@@ -124,7 +124,7 @@ public function __construct(
final public function serialize(mixed $data, string $format, array $context = []): string
{
if (!$this->supportsEncoding($format, $context)) {
- throw new UnsupportedFormatException(sprintf('Serialization for the format "%s" is not supported.', $format));
+ throw new UnsupportedFormatException(\sprintf('Serialization for the format "%s" is not supported.', $format));
}
if ($this->encoder->needsNormalization($format, $context)) {
@@ -137,7 +137,7 @@ final public function serialize(mixed $data, string $format, array $context = []
final public function deserialize(mixed $data, string $type, string $format, array $context = []): mixed
{
if (!$this->supportsDecoding($format, $context)) {
- throw new UnsupportedFormatException(sprintf('Deserialization for the format "%s" is not supported.', $format));
+ throw new UnsupportedFormatException(\sprintf('Deserialization for the format "%s" is not supported.', $format));
}
$data = $this->decode($data, $format, $context);
@@ -178,10 +178,10 @@ public function normalize(mixed $data, ?string $format = null, array $context =
throw new LogicException('You must register at least one normalizer to be able to normalize objects.');
}
- throw new NotNormalizableValueException(sprintf('Could not normalize object of type "%s", no supporting normalizer found.', get_debug_type($data)));
+ throw new NotNormalizableValueException(\sprintf('Could not normalize object of type "%s", no supporting normalizer found.', get_debug_type($data)));
}
- throw new NotNormalizableValueException('An unexpected value could not be normalized: '.(!\is_resource($data) ? var_export($data, true) : sprintf('"%s" resource', get_resource_type($data))));
+ throw new NotNormalizableValueException('An unexpected value could not be normalized: '.(!\is_resource($data) ? var_export($data, true) : \sprintf('"%s" resource', get_resource_type($data))));
}
/**
@@ -199,7 +199,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
// Check for a denormalizer first, e.g. the data is wrapped
if (!$normalizer && isset(self::SCALAR_TYPES[$type])) {
if (!('is_'.$type)($data)) {
- throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Data expected to be of type "%s" ("%s" given).', $type, get_debug_type($data)), $data, [$type], $context['deserialization_path'] ?? null, true);
+ throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Data expected to be of type "%s" ("%s" given).', $type, get_debug_type($data)), $data, [$type], $context['deserialization_path'] ?? null, true);
}
return $data;
@@ -210,7 +210,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
}
if (!$normalizer) {
- throw new NotNormalizableValueException(sprintf('Could not denormalize object of type "%s", no supporting normalizer found.', $type));
+ throw new NotNormalizableValueException(\sprintf('Could not denormalize object of type "%s", no supporting normalizer found.', $type));
}
if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]) || isset($this->defaultContext[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) {
diff --git a/Tests/Annotation/ContextTest.php b/Tests/Attribute/ContextTest.php
similarity index 94%
rename from Tests/Annotation/ContextTest.php
rename to Tests/Attribute/ContextTest.php
index 9584d6f1b..cfe175050 100644
--- a/Tests/Annotation/ContextTest.php
+++ b/Tests/Attribute/ContextTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Attribute\Context;
@@ -40,7 +40,7 @@ public function testThrowsOnEmptyContext()
public function testInvalidGroupOption()
{
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage(sprintf('Parameter "groups" given to "%s" must be a string or an array of strings, "stdClass" given', Context::class));
+ $this->expectExceptionMessage(\sprintf('Parameter "groups" given to "%s" must be a string or an array of strings, "stdClass" given', Context::class));
new Context(context: ['foo' => 'bar'], groups: ['fine', new \stdClass()]);
}
diff --git a/Tests/Annotation/DiscriminatorMapTest.php b/Tests/Attribute/DiscriminatorMapTest.php
similarity index 82%
rename from Tests/Annotation/DiscriminatorMapTest.php
rename to Tests/Attribute/DiscriminatorMapTest.php
index bbd112e26..497bc6201 100644
--- a/Tests/Annotation/DiscriminatorMapTest.php
+++ b/Tests/Attribute/DiscriminatorMapTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Attribute\DiscriminatorMap;
@@ -22,16 +22,16 @@ class DiscriminatorMapTest extends TestCase
{
public function testGetTypePropertyAndMapping()
{
- $annotation = new DiscriminatorMap(typeProperty: 'type', mapping: [
+ $attribute = new DiscriminatorMap(typeProperty: 'type', mapping: [
'foo' => 'FooClass',
'bar' => 'BarClass',
]);
- $this->assertEquals('type', $annotation->getTypeProperty());
+ $this->assertEquals('type', $attribute->getTypeProperty());
$this->assertEquals([
'foo' => 'FooClass',
'bar' => 'BarClass',
- ], $annotation->getMapping());
+ ], $attribute->getMapping());
}
public function testExceptionWithEmptyTypeProperty()
diff --git a/Tests/Annotation/GroupsTest.php b/Tests/Attribute/GroupsTest.php
similarity index 95%
rename from Tests/Annotation/GroupsTest.php
rename to Tests/Attribute/GroupsTest.php
index 38ec518bd..266cbc4f4 100644
--- a/Tests/Annotation/GroupsTest.php
+++ b/Tests/Attribute/GroupsTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Attribute\Groups;
diff --git a/Tests/Annotation/MaxDepthTest.php b/Tests/Attribute/MaxDepthTest.php
similarity index 94%
rename from Tests/Annotation/MaxDepthTest.php
rename to Tests/Attribute/MaxDepthTest.php
index f2ff35c87..e611bfbc4 100644
--- a/Tests/Annotation/MaxDepthTest.php
+++ b/Tests/Attribute/MaxDepthTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Attribute\MaxDepth;
diff --git a/Tests/Annotation/SerializedNameTest.php b/Tests/Attribute/SerializedNameTest.php
similarity index 94%
rename from Tests/Annotation/SerializedNameTest.php
rename to Tests/Attribute/SerializedNameTest.php
index 3a829aecf..c645e7e85 100644
--- a/Tests/Annotation/SerializedNameTest.php
+++ b/Tests/Attribute/SerializedNameTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Attribute\SerializedName;
diff --git a/Tests/Annotation/SerializedPathTest.php b/Tests/Attribute/SerializedPathTest.php
similarity index 95%
rename from Tests/Annotation/SerializedPathTest.php
rename to Tests/Attribute/SerializedPathTest.php
index f5bbfa62b..7ba31fc22 100644
--- a/Tests/Annotation/SerializedPathTest.php
+++ b/Tests/Attribute/SerializedPathTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Serializer\Tests\Annotation;
+namespace Symfony\Component\Serializer\Tests\Attribute;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyAccess\PropertyPath;
diff --git a/Tests/Context/ContextBuilderTraitTest.php b/Tests/Context/ContextBuilderTraitTest.php
index 17ad231a0..edd3937e2 100644
--- a/Tests/Context/ContextBuilderTraitTest.php
+++ b/Tests/Context/ContextBuilderTraitTest.php
@@ -22,7 +22,7 @@ class ContextBuilderTraitTest extends TestCase
{
public function testWithContext()
{
- $contextBuilder = new class() implements ContextBuilderInterface {
+ $contextBuilder = new class implements ContextBuilderInterface {
use ContextBuilderTrait;
};
@@ -37,7 +37,7 @@ public function testWithContext()
public function testWith()
{
- $contextBuilder = new class() {
+ $contextBuilder = new class {
use ContextBuilderTrait;
public function withFoo(string $value): static
diff --git a/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php b/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php
index c71d41b63..fe39feb81 100644
--- a/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php
+++ b/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Serializer\Tests\Context\Encoder;
use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait;
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
@@ -21,6 +22,8 @@
*/
class CsvEncoderContextBuilderTest extends TestCase
{
+ use ExpectUserDeprecationMessageTrait;
+
private CsvEncoderContextBuilder $contextBuilder;
protected function setUp(): void
@@ -38,7 +41,6 @@ public function testWithers(array $values)
$context = $this->contextBuilder
->withDelimiter($values[CsvEncoder::DELIMITER_KEY])
->withEnclosure($values[CsvEncoder::ENCLOSURE_KEY])
- ->withEscapeChar($values[CsvEncoder::ESCAPE_CHAR_KEY])
->withKeySeparator($values[CsvEncoder::KEY_SEPARATOR_KEY])
->withHeaders($values[CsvEncoder::HEADERS_KEY])
->withEscapedFormulas($values[CsvEncoder::ESCAPE_FORMULAS_KEY])
@@ -59,7 +61,6 @@ public static function withersDataProvider(): iterable
yield 'With values' => [[
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => '"',
- CsvEncoder::ESCAPE_CHAR_KEY => '\\',
CsvEncoder::KEY_SEPARATOR_KEY => '_',
CsvEncoder::HEADERS_KEY => ['h1', 'h2'],
CsvEncoder::ESCAPE_FORMULAS_KEY => true,
@@ -72,7 +73,6 @@ public static function withersDataProvider(): iterable
yield 'With null values' => [[
CsvEncoder::DELIMITER_KEY => null,
CsvEncoder::ENCLOSURE_KEY => null,
- CsvEncoder::ESCAPE_CHAR_KEY => null,
CsvEncoder::KEY_SEPARATOR_KEY => null,
CsvEncoder::HEADERS_KEY => null,
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
@@ -88,7 +88,6 @@ public function testWithersWithoutValue()
$context = $this->contextBuilder
->withDelimiter(null)
->withEnclosure(null)
- ->withEscapeChar(null)
->withKeySeparator(null)
->withHeaders(null)
->withEscapedFormulas(null)
@@ -101,7 +100,6 @@ public function testWithersWithoutValue()
$this->assertSame([
CsvEncoder::DELIMITER_KEY => null,
CsvEncoder::ENCLOSURE_KEY => null,
- CsvEncoder::ESCAPE_CHAR_KEY => null,
CsvEncoder::KEY_SEPARATOR_KEY => null,
CsvEncoder::HEADERS_KEY => null,
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
@@ -124,9 +122,25 @@ public function testCannotSetMultipleBytesAsEnclosure()
$this->contextBuilder->withEnclosure('ọ');
}
+ /**
+ * @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('ọ');
}
+
+ /**
+ * @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/Context/Normalizer/AbstractNormalizerContextBuilderTest.php b/Tests/Context/Normalizer/AbstractNormalizerContextBuilderTest.php
index 4b8f0cc3f..4e92c54d8 100644
--- a/Tests/Context/Normalizer/AbstractNormalizerContextBuilderTest.php
+++ b/Tests/Context/Normalizer/AbstractNormalizerContextBuilderTest.php
@@ -25,7 +25,7 @@ class AbstractNormalizerContextBuilderTest extends TestCase
protected function setUp(): void
{
- $this->contextBuilder = new class() extends AbstractNormalizerContextBuilder {};
+ $this->contextBuilder = new class extends AbstractNormalizerContextBuilder {};
}
/**
diff --git a/Tests/Context/Normalizer/AbstractObjectNormalizerContextBuilderTest.php b/Tests/Context/Normalizer/AbstractObjectNormalizerContextBuilderTest.php
index 410f2972b..c13760118 100644
--- a/Tests/Context/Normalizer/AbstractObjectNormalizerContextBuilderTest.php
+++ b/Tests/Context/Normalizer/AbstractObjectNormalizerContextBuilderTest.php
@@ -25,7 +25,7 @@ class AbstractObjectNormalizerContextBuilderTest extends TestCase
protected function setUp(): void
{
- $this->contextBuilder = new class() extends AbstractObjectNormalizerContextBuilder {};
+ $this->contextBuilder = new class extends AbstractObjectNormalizerContextBuilder {};
}
/**
diff --git a/Tests/DataCollector/SerializerDataCollectorTest.php b/Tests/DataCollector/SerializerDataCollectorTest.php
index aebde8efa..6a26565a8 100644
--- a/Tests/DataCollector/SerializerDataCollectorTest.php
+++ b/Tests/DataCollector/SerializerDataCollectorTest.php
@@ -25,8 +25,8 @@ public function testCollectSerialize()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller);
+ $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
$dataCollector->lateCollect();
$collectedData = $this->castCollectedData($dataCollector->getData());
@@ -41,6 +41,7 @@ public function testCollectSerialize()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['serialize']);
$this->assertSame([[
@@ -53,6 +54,7 @@ public function testCollectSerialize()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['deserialize']);
}
@@ -61,8 +63,8 @@ public function testCollectNormalize()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectNormalize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectDenormalize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller);
+ $dataCollector->collectNormalize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectDenormalize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
$dataCollector->lateCollect();
$collectedData = $this->castCollectedData($dataCollector->getData());
@@ -77,6 +79,7 @@ public function testCollectNormalize()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['normalize']);
$this->assertSame([[
@@ -89,6 +92,7 @@ public function testCollectNormalize()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['denormalize']);
}
@@ -97,8 +101,8 @@ public function testCollectEncode()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectEncode('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectDecode('traceIdTwo', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
+ $dataCollector->collectEncode('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectDecode('traceIdTwo', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
$dataCollector->lateCollect();
$collectedData = $this->castCollectedData($dataCollector->getData());
@@ -113,6 +117,7 @@ public function testCollectEncode()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['encode']);
$this->assertSame([[
@@ -125,6 +130,7 @@ public function testCollectEncode()
'normalization' => [],
'encoding' => [],
'caller' => $caller,
+ 'name' => 'default',
]], $collectedData['decode']);
}
@@ -133,18 +139,18 @@ public function testCollectNormalization()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectNormalize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectDenormalize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 20.0, $caller);
+ $dataCollector->collectNormalize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectDenormalize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
- $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 1.0);
- $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 2.0);
- $dataCollector->collectNormalization('traceIdOne', ObjectNormalizer::class, 5.0);
- $dataCollector->collectNormalization('traceIdOne', ObjectNormalizer::class, 10.0);
+ $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 1.0, 'default');
+ $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 2.0, 'default');
+ $dataCollector->collectNormalization('traceIdOne', ObjectNormalizer::class, 5.0, 'default');
+ $dataCollector->collectNormalization('traceIdOne', ObjectNormalizer::class, 10.0, 'default');
- $dataCollector->collectNormalization('traceIdTwo', DateTimeNormalizer::class, 1.0);
- $dataCollector->collectNormalization('traceIdTwo', DateTimeNormalizer::class, 2.0);
- $dataCollector->collectNormalization('traceIdTwo', ObjectNormalizer::class, 5.0);
- $dataCollector->collectNormalization('traceIdTwo', ObjectNormalizer::class, 10.0);
+ $dataCollector->collectNormalization('traceIdTwo', DateTimeNormalizer::class, 1.0, 'default');
+ $dataCollector->collectNormalization('traceIdTwo', DateTimeNormalizer::class, 2.0, 'default');
+ $dataCollector->collectNormalization('traceIdTwo', ObjectNormalizer::class, 5.0, 'default');
+ $dataCollector->collectNormalization('traceIdTwo', ObjectNormalizer::class, 10.0, 'default');
$dataCollector->lateCollect();
$collectedData = $dataCollector->getData();
@@ -189,18 +195,18 @@ public function testCollectEncoding()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectEncode('traceIdOne', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectDecode('traceIdTwo', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
+ $dataCollector->collectEncode('traceIdOne', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectDecode('traceIdTwo', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
- $dataCollector->collectEncoding('traceIdOne', JsonEncoder::class, 1.0);
- $dataCollector->collectEncoding('traceIdOne', JsonEncoder::class, 2.0);
- $dataCollector->collectEncoding('traceIdOne', CsvEncoder::class, 5.0);
- $dataCollector->collectEncoding('traceIdOne', CsvEncoder::class, 10.0);
+ $dataCollector->collectEncoding('traceIdOne', JsonEncoder::class, 1.0, 'default');
+ $dataCollector->collectEncoding('traceIdOne', JsonEncoder::class, 2.0, 'default');
+ $dataCollector->collectEncoding('traceIdOne', CsvEncoder::class, 5.0, 'default');
+ $dataCollector->collectEncoding('traceIdOne', CsvEncoder::class, 10.0, 'default');
- $dataCollector->collectDecoding('traceIdTwo', JsonEncoder::class, 1.0);
- $dataCollector->collectDecoding('traceIdTwo', JsonEncoder::class, 2.0);
- $dataCollector->collectDecoding('traceIdTwo', CsvEncoder::class, 5.0);
- $dataCollector->collectDecoding('traceIdTwo', CsvEncoder::class, 10.0);
+ $dataCollector->collectDecoding('traceIdTwo', JsonEncoder::class, 1.0, 'default');
+ $dataCollector->collectDecoding('traceIdTwo', JsonEncoder::class, 2.0, 'default');
+ $dataCollector->collectDecoding('traceIdTwo', CsvEncoder::class, 5.0, 'default');
+ $dataCollector->collectDecoding('traceIdTwo', CsvEncoder::class, 10.0, 'default');
$dataCollector->lateCollect();
$collectedData = $dataCollector->getData();
@@ -245,13 +251,13 @@ public function testCountHandled()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectNormalize('traceIdThree', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectDenormalize('traceIdFour', 'data', 'type', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectEncode('traceIdFive', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectDecode('traceIdSix', 'data', 'format', ['foo' => 'bar'], 20.0, $caller);
- $dataCollector->collectSerialize('traceIdSeven', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
+ $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectNormalize('traceIdThree', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectDenormalize('traceIdFour', 'data', 'type', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectEncode('traceIdFive', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectDecode('traceIdSix', 'data', 'format', ['foo' => 'bar'], 20.0, $caller, 'default');
+ $dataCollector->collectSerialize('traceIdSeven', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
$dataCollector->lateCollect();
@@ -264,13 +270,13 @@ public function testGetTotalTime()
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
- $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 2.0, $caller);
- $dataCollector->collectNormalize('traceIdThree', 'data', 'format', ['foo' => 'bar'], 3.0, $caller);
- $dataCollector->collectDenormalize('traceIdFour', 'data', 'type', 'format', ['foo' => 'bar'], 4.0, $caller);
- $dataCollector->collectEncode('traceIdFive', 'data', 'format', ['foo' => 'bar'], 5.0, $caller);
- $dataCollector->collectDecode('traceIdSix', 'data', 'format', ['foo' => 'bar'], 6.0, $caller);
- $dataCollector->collectSerialize('traceIdSeven', 'data', 'format', ['foo' => 'bar'], 7.0, $caller);
+ $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
+ $dataCollector->collectDeserialize('traceIdTwo', 'data', 'type', 'format', ['foo' => 'bar'], 2.0, $caller, 'default');
+ $dataCollector->collectNormalize('traceIdThree', 'data', 'format', ['foo' => 'bar'], 3.0, $caller, 'default');
+ $dataCollector->collectDenormalize('traceIdFour', 'data', 'type', 'format', ['foo' => 'bar'], 4.0, $caller, 'default');
+ $dataCollector->collectEncode('traceIdFive', 'data', 'format', ['foo' => 'bar'], 5.0, $caller, 'default');
+ $dataCollector->collectDecode('traceIdSix', 'data', 'format', ['foo' => 'bar'], 6.0, $caller, 'default');
+ $dataCollector->collectSerialize('traceIdSeven', 'data', 'format', ['foo' => 'bar'], 7.0, $caller, 'default');
$dataCollector->lateCollect();
@@ -282,7 +288,7 @@ public function testReset()
$dataCollector = new SerializerDataCollector();
$caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
- $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller);
+ $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 1.0, $caller, 'default');
$dataCollector->lateCollect();
$this->assertNotSame([], $dataCollector->getData());
@@ -295,10 +301,10 @@ public function testDoNotCollectPartialTraces()
{
$dataCollector = new SerializerDataCollector();
- $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 1.0);
- $dataCollector->collectDenormalization('traceIdTwo', DateTimeNormalizer::class, 1.0);
- $dataCollector->collectEncoding('traceIdThree', CsvEncoder::class, 10.0);
- $dataCollector->collectDecoding('traceIdFour', JsonEncoder::class, 1.0);
+ $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 1.0, 'default');
+ $dataCollector->collectDenormalization('traceIdTwo', DateTimeNormalizer::class, 1.0, 'default');
+ $dataCollector->collectEncoding('traceIdThree', CsvEncoder::class, 10.0, 'default');
+ $dataCollector->collectDecoding('traceIdFour', JsonEncoder::class, 1.0, 'default');
$dataCollector->lateCollect();
@@ -312,6 +318,84 @@ public function testDoNotCollectPartialTraces()
$this->assertSame([], $data['decode']);
}
+ public function testNamedSerializers()
+ {
+ $dataCollector = new SerializerDataCollector();
+
+ $caller = ['name' => 'Foo.php', 'file' => 'src/Foo.php', 'line' => 123];
+ $dataCollector->collectNormalization('traceIdOne', DateTimeNormalizer::class, 3.0, 'default');
+ $dataCollector->collectEncoding('traceIdOne', CsvEncoder::class, 4.0, 'default');
+ $dataCollector->collectSerialize('traceIdOne', 'data', 'format', ['foo' => 'bar'], 7.0, $caller, 'default');
+ $dataCollector->collectNormalization('traceIdTwo', ObjectNormalizer::class, 3.0, 'default');
+ $dataCollector->collectNormalize('traceIdTwo', 'data', 'format', ['foo' => 'bar'], 5.0, $caller, 'default');
+
+ $dataCollector->collectEncoding('traceIdThree', JsonEncoder::class, 4.0, 'api');
+ $dataCollector->collectEncode('traceIdThree', 'data', 'format', ['foo' => 'bar'], 5.0, $caller, 'api');
+ $dataCollector->collectDenormalization('traceIdFour', DateTimeNormalizer::class, 3.0, 'api');
+ $dataCollector->collectDecoding('traceIdFour', CsvEncoder::class, 4.0, 'api');
+ $dataCollector->collectDeserialize('traceIdFour', 'data', 'type', 'format', ['foo' => 'bar'], 7.0, $caller, 'api');
+ $dataCollector->collectDenormalization('traceIdFive', ObjectNormalizer::class, 3.0, 'api');
+ $dataCollector->collectDenormalize('traceIdFive', 'data', 'type', 'format', ['foo' => 'bar'], 5.0, $caller, 'api');
+ $dataCollector->collectDecoding('traceIdSix', JsonEncoder::class, 4.0, 'api');
+ $dataCollector->collectDecode('traceIdSix', 'data', 'format', ['foo' => 'bar'], 5.0, $caller, 'api');
+
+ $dataCollector->lateCollect();
+
+ $this->assertSame(6, $dataCollector->getHandledCount());
+
+ $collectedData = $dataCollector->getData();
+
+ $this->assertSame('default', $collectedData['serialize'][0]['name']);
+ $this->assertSame('DateTimeNormalizer', $collectedData['serialize'][0]['normalizer']['class']);
+ $this->assertSame('CsvEncoder', $collectedData['serialize'][0]['encoder']['class']);
+ $this->assertSame('default', $collectedData['normalize'][0]['name']);
+ $this->assertSame('ObjectNormalizer', $collectedData['normalize'][0]['normalizer']['class']);
+
+ $this->assertSame('api', $collectedData['encode'][0]['name']);
+ $this->assertSame('JsonEncoder', $collectedData['encode'][0]['encoder']['class']);
+ $this->assertSame('api', $collectedData['deserialize'][0]['name']);
+ $this->assertSame('DateTimeNormalizer', $collectedData['deserialize'][0]['normalizer']['class']);
+ $this->assertSame('CsvEncoder', $collectedData['deserialize'][0]['encoder']['class']);
+ $this->assertSame('api', $collectedData['denormalize'][0]['name']);
+ $this->assertSame('ObjectNormalizer', $collectedData['denormalize'][0]['normalizer']['class']);
+ $this->assertSame('api', $collectedData['decode'][0]['name']);
+ $this->assertSame('JsonEncoder', $collectedData['decode'][0]['encoder']['class']);
+
+ $this->assertSame(['default', 'api'], $dataCollector->getSerializerNames());
+
+ $this->assertSame(2, $dataCollector->getHandledCount('default'));
+
+ $collectedData = $dataCollector->getData('default');
+
+ $this->assertSame('default', $collectedData['serialize'][0]['name']);
+ $this->assertSame('DateTimeNormalizer', $collectedData['serialize'][0]['normalizer']['class']);
+ $this->assertSame('CsvEncoder', $collectedData['serialize'][0]['encoder']['class']);
+ $this->assertSame('default', $collectedData['normalize'][0]['name']);
+ $this->assertSame('ObjectNormalizer', $collectedData['normalize'][0]['normalizer']['class']);
+
+ $this->assertEmpty($collectedData['encode']);
+ $this->assertEmpty($collectedData['deserialize']);
+ $this->assertEmpty($collectedData['denormalize']);
+ $this->assertEmpty($collectedData['decode']);
+
+ $this->assertSame(4, $dataCollector->getHandledCount('api'));
+
+ $collectedData = $dataCollector->getData('api');
+
+ $this->assertEmpty($collectedData['serialize']);
+ $this->assertEmpty($collectedData['normalize']);
+
+ $this->assertSame('api', $collectedData['encode'][0]['name']);
+ $this->assertSame('JsonEncoder', $collectedData['encode'][0]['encoder']['class']);
+ $this->assertSame('api', $collectedData['deserialize'][0]['name']);
+ $this->assertSame('DateTimeNormalizer', $collectedData['deserialize'][0]['normalizer']['class']);
+ $this->assertSame('CsvEncoder', $collectedData['deserialize'][0]['encoder']['class']);
+ $this->assertSame('api', $collectedData['denormalize'][0]['name']);
+ $this->assertSame('ObjectNormalizer', $collectedData['denormalize'][0]['normalizer']['class']);
+ $this->assertSame('api', $collectedData['decode'][0]['name']);
+ $this->assertSame('JsonEncoder', $collectedData['decode'][0]['encoder']['class']);
+ }
+
/**
* Cast cloned vars to be able to test nested values.
*/
diff --git a/Tests/Debug/TraceableEncoderTest.php b/Tests/Debug/TraceableEncoderTest.php
index ec38c0ef5..2ac0b8f1f 100644
--- a/Tests/Debug/TraceableEncoderTest.php
+++ b/Tests/Debug/TraceableEncoderTest.php
@@ -36,12 +36,14 @@ public function testForwardsToEncoder()
->with('data', 'format', $this->isType('array'))
->willReturn('decoded');
- $this->assertSame('encoded', (new TraceableEncoder($encoder, new SerializerDataCollector()))->encode('data', 'format'));
- $this->assertSame('decoded', (new TraceableEncoder($decoder, new SerializerDataCollector()))->decode('data', 'format'));
+ $this->assertSame('encoded', (new TraceableEncoder($encoder, new SerializerDataCollector(), 'default'))->encode('data', 'format'));
+ $this->assertSame('decoded', (new TraceableEncoder($decoder, new SerializerDataCollector(), 'default'))->decode('data', 'format'));
}
public function testCollectEncodingData()
{
+ $serializerName = uniqid('name', true);
+
$encoder = $this->createMock(EncoderInterface::class);
$decoder = $this->createMock(DecoderInterface::class);
@@ -49,14 +51,14 @@ public function testCollectEncodingData()
$dataCollector
->expects($this->once())
->method('collectEncoding')
- ->with($this->isType('string'), $encoder::class, $this->isType('float'));
+ ->with($this->isType('string'), $encoder::class, $this->isType('float'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectDecoding')
- ->with($this->isType('string'), $decoder::class, $this->isType('float'));
+ ->with($this->isType('string'), $decoder::class, $this->isType('float'), $serializerName);
- (new TraceableEncoder($encoder, $dataCollector))->encode('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
- (new TraceableEncoder($decoder, $dataCollector))->decode('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
+ (new TraceableEncoder($encoder, $dataCollector, $serializerName))->encode('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
+ (new TraceableEncoder($decoder, $dataCollector, $serializerName))->decode('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
}
public function testNotCollectEncodingDataIfNoDebugTraceId()
@@ -68,22 +70,22 @@ public function testNotCollectEncodingDataIfNoDebugTraceId()
$dataCollector->expects($this->never())->method('collectEncoding');
$dataCollector->expects($this->never())->method('collectDecoding');
- (new TraceableEncoder($encoder, $dataCollector))->encode('data', 'format');
- (new TraceableEncoder($decoder, $dataCollector))->decode('data', 'format');
+ (new TraceableEncoder($encoder, $dataCollector, 'default'))->encode('data', 'format');
+ (new TraceableEncoder($decoder, $dataCollector, 'default'))->decode('data', 'format');
}
public function testCannotEncodeIfNotEncoder()
{
$this->expectException(\BadMethodCallException::class);
- (new TraceableEncoder($this->createMock(DecoderInterface::class), new SerializerDataCollector()))->encode('data', 'format');
+ (new TraceableEncoder($this->createMock(DecoderInterface::class), new SerializerDataCollector(), 'default'))->encode('data', 'format');
}
public function testCannotDecodeIfNotDecoder()
{
$this->expectException(\BadMethodCallException::class);
- (new TraceableEncoder($this->createMock(EncoderInterface::class), new SerializerDataCollector()))->decode('data', 'format');
+ (new TraceableEncoder($this->createMock(EncoderInterface::class), new SerializerDataCollector(), 'default'))->decode('data', 'format');
}
public function testSupports()
@@ -94,8 +96,8 @@ public function testSupports()
$decoder = $this->createMock(DecoderInterface::class);
$decoder->method('supportsDecoding')->willReturn(true);
- $traceableEncoder = new TraceableEncoder($encoder, new SerializerDataCollector());
- $traceableDecoder = new TraceableEncoder($decoder, new SerializerDataCollector());
+ $traceableEncoder = new TraceableEncoder($encoder, new SerializerDataCollector(), 'default');
+ $traceableDecoder = new TraceableEncoder($decoder, new SerializerDataCollector(), 'default');
$this->assertTrue($traceableEncoder->supportsEncoding('data'));
$this->assertTrue($traceableDecoder->supportsDecoding('data'));
diff --git a/Tests/Debug/TraceableNormalizerTest.php b/Tests/Debug/TraceableNormalizerTest.php
index 307bc7b6f..56c161392 100644
--- a/Tests/Debug/TraceableNormalizerTest.php
+++ b/Tests/Debug/TraceableNormalizerTest.php
@@ -38,12 +38,14 @@ public function testForwardsToNormalizer()
->with('data', 'type', 'format', $this->isType('array'))
->willReturn('denormalized');
- $this->assertSame('normalized', (new TraceableNormalizer($normalizer, new SerializerDataCollector()))->normalize('data', 'format'));
- $this->assertSame('denormalized', (new TraceableNormalizer($denormalizer, new SerializerDataCollector()))->denormalize('data', 'type', 'format'));
+ $this->assertSame('normalized', (new TraceableNormalizer($normalizer, new SerializerDataCollector(), 'default'))->normalize('data', 'format'));
+ $this->assertSame('denormalized', (new TraceableNormalizer($denormalizer, new SerializerDataCollector(), 'default'))->denormalize('data', 'type', 'format'));
}
public function testCollectNormalizationData()
{
+ $serializerName = uniqid('name', true);
+
$normalizer = $this->createMock(NormalizerInterface::class);
$normalizer->method('getSupportedTypes')->willReturn(['*' => false]);
$denormalizer = $this->createMock(DenormalizerInterface::class);
@@ -53,14 +55,14 @@ public function testCollectNormalizationData()
$dataCollector
->expects($this->once())
->method('collectNormalization')
- ->with($this->isType('string'), $normalizer::class, $this->isType('float'));
+ ->with($this->isType('string'), $normalizer::class, $this->isType('float'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectDenormalization')
- ->with($this->isType('string'), $denormalizer::class, $this->isType('float'));
+ ->with($this->isType('string'), $denormalizer::class, $this->isType('float'), $serializerName);
- (new TraceableNormalizer($normalizer, $dataCollector))->normalize('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
- (new TraceableNormalizer($denormalizer, $dataCollector))->denormalize('data', 'type', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
+ (new TraceableNormalizer($normalizer, $dataCollector, $serializerName))->normalize('data', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
+ (new TraceableNormalizer($denormalizer, $dataCollector, $serializerName))->denormalize('data', 'type', 'format', [TraceableSerializer::DEBUG_TRACE_ID => 'debug']);
}
public function testNotCollectNormalizationDataIfNoDebugTraceId()
@@ -74,22 +76,22 @@ public function testNotCollectNormalizationDataIfNoDebugTraceId()
$dataCollector->expects($this->never())->method('collectNormalization');
$dataCollector->expects($this->never())->method('collectDenormalization');
- (new TraceableNormalizer($normalizer, $dataCollector))->normalize('data', 'format');
- (new TraceableNormalizer($denormalizer, $dataCollector))->denormalize('data', 'type', 'format');
+ (new TraceableNormalizer($normalizer, $dataCollector, 'default'))->normalize('data', 'format');
+ (new TraceableNormalizer($denormalizer, $dataCollector, 'default'))->denormalize('data', 'type', 'format');
}
public function testCannotNormalizeIfNotNormalizer()
{
$this->expectException(\BadMethodCallException::class);
- (new TraceableNormalizer($this->createMock(DenormalizerInterface::class), new SerializerDataCollector()))->normalize('data');
+ (new TraceableNormalizer($this->createMock(DenormalizerInterface::class), new SerializerDataCollector(), 'default'))->normalize('data');
}
public function testCannotDenormalizeIfNotDenormalizer()
{
$this->expectException(\BadMethodCallException::class);
- (new TraceableNormalizer($this->createMock(NormalizerInterface::class), new SerializerDataCollector()))->denormalize('data', 'type');
+ (new TraceableNormalizer($this->createMock(NormalizerInterface::class), new SerializerDataCollector(), 'default'))->denormalize('data', 'type');
}
public function testSupports()
@@ -102,8 +104,8 @@ public function testSupports()
$denormalizer->method('getSupportedTypes')->willReturn(['*' => false]);
$denormalizer->method('supportsDenormalization')->willReturn(true);
- $traceableNormalizer = new TraceableNormalizer($normalizer, new SerializerDataCollector());
- $traceableDenormalizer = new TraceableNormalizer($denormalizer, new SerializerDataCollector());
+ $traceableNormalizer = new TraceableNormalizer($normalizer, new SerializerDataCollector(), 'default');
+ $traceableDenormalizer = new TraceableNormalizer($denormalizer, new SerializerDataCollector(), 'default');
$this->assertTrue($traceableNormalizer->supportsNormalization('data'));
$this->assertTrue($traceableDenormalizer->supportsDenormalization('data', 'type'));
diff --git a/Tests/Debug/TraceableSerializerTest.php b/Tests/Debug/TraceableSerializerTest.php
index ea3c851c6..d697b270f 100644
--- a/Tests/Debug/TraceableSerializerTest.php
+++ b/Tests/Debug/TraceableSerializerTest.php
@@ -56,7 +56,7 @@ public function testForwardsToSerializer()
->with('data', 'format', $this->isType('array'))
->willReturn('decoded');
- $traceableSerializer = new TraceableSerializer($serializer, new SerializerDataCollector());
+ $traceableSerializer = new TraceableSerializer($serializer, new SerializerDataCollector(), 'default');
$this->assertSame('serialized', $traceableSerializer->serialize('data', 'format'));
$this->assertSame('deserialized', $traceableSerializer->deserialize('data', 'type', 'format'));
@@ -68,33 +68,35 @@ public function testForwardsToSerializer()
public function testCollectData()
{
+ $serializerName = uniqid('name', true);
+
$dataCollector = $this->createMock(SerializerDataCollector::class);
$dataCollector
->expects($this->once())
->method('collectSerialize')
- ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectDeserialize')
- ->with($this->isType('string'), 'data', 'type', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'type', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectNormalize')
- ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectDenormalize')
- ->with($this->isType('string'), 'data', 'type', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'type', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectEncode')
- ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
$dataCollector
->expects($this->once())
->method('collectDecode')
- ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'));
+ ->with($this->isType('string'), 'data', 'format', $this->isType('array'), $this->isType('float'), $this->isType('array'), $serializerName);
- $traceableSerializer = new TraceableSerializer(new Serializer(), $dataCollector);
+ $traceableSerializer = new TraceableSerializer(new Serializer(), $dataCollector, $serializerName);
$traceableSerializer->serialize('data', 'format');
$traceableSerializer->deserialize('data', 'type', 'format');
@@ -117,7 +119,7 @@ public function testAddDebugTraceIdInContext()
});
}
- $traceableSerializer = new TraceableSerializer($serializer, new SerializerDataCollector());
+ $traceableSerializer = new TraceableSerializer($serializer, new SerializerDataCollector(), 'default');
$traceableSerializer->serialize('data', 'format');
$traceableSerializer->deserialize('data', 'format', 'type');
diff --git a/Tests/DependencyInjection/SerializerPassTest.php b/Tests/DependencyInjection/SerializerPassTest.php
index a15322a1b..88ec02b87 100644
--- a/Tests/DependencyInjection/SerializerPassTest.php
+++ b/Tests/DependencyInjection/SerializerPassTest.php
@@ -17,7 +17,10 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Serializer\Debug\TraceableEncoder;
use Symfony\Component\Serializer\Debug\TraceableNormalizer;
+use Symfony\Component\Serializer\Debug\TraceableSerializer;
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
+use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
+use Symfony\Component\Serializer\SerializerInterface;
/**
* Tests for the SerializerPass class.
@@ -97,7 +100,33 @@ public function testBindSerializerDefaultContext()
$this->assertEquals($context, $container->getDefinition('serializer')->getArgument('$defaultContext'));
}
- public function testNormalizersAndEncodersAreDecoredAndOrderedWhenCollectingData()
+ /**
+ * @testWith [{}, {}]
+ * [{"serializer.default_context": {"enable_max_depth": true}}, {"enable_max_depth": true}]
+ * [{".serializer.circular_reference_handler": "foo"}, {"circular_reference_handler": "foo"}]
+ * [{".serializer.max_depth_handler": "bar"}, {"max_depth_handler": "bar"}]
+ * [{"serializer.default_context": {"enable_max_depth": true}, ".serializer.circular_reference_handler": "foo", ".serializer.max_depth_handler": "bar"}, {"enable_max_depth": true, "circular_reference_handler": "foo", "max_depth_handler": "bar"}]
+ */
+ public function testBindObjectNormalizerDefaultContext(array $parameters, array $context)
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->register('serializer')->setArguments([null, null, []]);
+ $container->getParameterBag()->add($parameters);
+ $definition = $container->register('serializer.normalizer.object')
+ ->setClass(ObjectNormalizer::class)
+ ->addTag('serializer.normalizer')
+ ->addTag('serializer.encoder')
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $bindings = $definition->getBindings();
+ $this->assertEquals($bindings['array $defaultContext'], new BoundArgument($context, false));
+ }
+
+ public function testNormalizersAndEncodersAreDecoratedAndOrderedWhenCollectingData()
{
$container = new ContainerBuilder();
@@ -117,9 +146,560 @@ public function testNormalizersAndEncodersAreDecoredAndOrderedWhenCollectingData
$this->assertEquals(TraceableNormalizer::class, $traceableNormalizerDefinition->getClass());
$this->assertEquals(new Reference('n'), $traceableNormalizerDefinition->getArgument(0));
$this->assertEquals(new Reference('serializer.data_collector'), $traceableNormalizerDefinition->getArgument(1));
+ $this->assertSame('default', $traceableNormalizerDefinition->getArgument(2));
$this->assertEquals(TraceableEncoder::class, $traceableEncoderDefinition->getClass());
$this->assertEquals(new Reference('e'), $traceableEncoderDefinition->getArgument(0));
$this->assertEquals(new Reference('serializer.data_collector'), $traceableEncoderDefinition->getArgument(1));
+ $this->assertSame('default', $traceableEncoderDefinition->getArgument(2));
+ }
+
+ /**
+ * @dataProvider provideDefaultSerializerTagsData
+ */
+ public function testDefaultSerializerTagsAreResolvedCorrectly(
+ array $normalizerTagAttributes,
+ array $encoderTagAttributes,
+ array $expectedNormalizerTags,
+ array $expectedEncoderTags,
+ ) {
+ $container = new ContainerBuilder();
+
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', []);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n0')->addTag('serializer.normalizer', ['serializer' => 'default']);
+ $container->register('e0')->addTag('serializer.encoder', ['serializer' => 'default']);
+
+ $normalizerDefinition = $container->register('n1')->addTag('serializer.normalizer', $normalizerTagAttributes);
+ $encoderDefinition = $container->register('e1')->addTag('serializer.encoder', $encoderTagAttributes);
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertSame($expectedNormalizerTags, $normalizerDefinition->getTag('serializer.normalizer.default'));
+ $this->assertSame($expectedEncoderTags, $encoderDefinition->getTag('serializer.encoder.default'));
+ }
+
+ public static function provideDefaultSerializerTagsData(): iterable
+ {
+ yield 'include no name' => [
+ [],
+ [],
+ [[]],
+ [[]],
+ ];
+
+ yield 'include name' => [
+ ['serializer' => 'default'],
+ ['serializer' => 'default'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'include built-in with different name' => [
+ ['built_in' => true, 'serializer' => 'api'],
+ ['built_in' => true, 'serializer' => 'api'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'include no name with priority' => [
+ ['priority' => 200],
+ ['priority' => 100],
+ [['priority' => 200]],
+ [['priority' => 100]],
+ ];
+
+ yield 'include name with priority' => [
+ ['serializer' => 'default', 'priority' => 200],
+ ['serializer' => 'default', 'priority' => 100],
+ [['priority' => 200]],
+ [['priority' => 100]],
+ ];
+
+ yield 'include wildcard' => [
+ ['serializer' => '*'],
+ ['serializer' => '*'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'is unique when built-in with name' => [
+ ['built_in' => true, 'serializer' => 'default'],
+ ['built_in' => true, 'serializer' => 'default'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'do not include different name' => [
+ ['serializer' => 'api'],
+ ['serializer' => 'api'],
+ [],
+ [],
+ ];
+ }
+
+ /**
+ * @dataProvider provideNamedSerializerTagsData
+ */
+ public function testNamedSerializerTagsAreResolvedCorrectly(
+ array $config,
+ array $normalizerTagAttributes,
+ array $encoderTagAttributes,
+ array $expectedNormalizerTags,
+ array $expectedEncoderTags,
+ ) {
+ $container = new ContainerBuilder();
+
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', ['api' => $config]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n0')->addTag('serializer.normalizer', ['serializer' => ['default', 'api']]);
+ $container->register('e0')->addTag('serializer.encoder', ['serializer' => ['default', 'api']]);
+
+ $normalizerDefinition = $container->register('n1')->addTag('serializer.normalizer', $normalizerTagAttributes);
+ $encoderDefinition = $container->register('e1')->addTag('serializer.encoder', $encoderTagAttributes);
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertSame($expectedNormalizerTags, $normalizerDefinition->getTag('serializer.normalizer.api'));
+ $this->assertSame($expectedEncoderTags, $encoderDefinition->getTag('serializer.encoder.api'));
+ }
+
+ public static function provideNamedSerializerTagsData(): iterable
+ {
+ yield 'include built-in' => [
+ ['include_built_in_normalizers' => true, 'include_built_in_encoders' => true],
+ ['built_in' => true],
+ ['built_in' => true],
+ [[]],
+ [[]],
+ ];
+
+ yield 'include built-in normalizers only' => [
+ ['include_built_in_normalizers' => true, 'include_built_in_encoders' => false],
+ ['built_in' => true],
+ ['built_in' => true],
+ [[]],
+ [],
+ ];
+
+ yield 'include built-in encoders only' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => true],
+ ['built_in' => true],
+ ['built_in' => true],
+ [],
+ [[]],
+ ];
+
+ yield 'include name' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => false],
+ ['serializer' => 'api'],
+ ['serializer' => 'api'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'include name with priority' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => false],
+ ['serializer' => 'api', 'priority' => 200],
+ ['serializer' => 'api', 'priority' => 100],
+ [['priority' => 200]],
+ [['priority' => 100]],
+ ];
+
+ yield 'include wildcard' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => false],
+ ['serializer' => '*'],
+ ['serializer' => '*'],
+ [[]],
+ [[]],
+ ];
+
+ yield 'do not include when include built-in not set' => [
+ [],
+ ['built_in' => true],
+ ['built_in' => true],
+ [],
+ [],
+ ];
+
+ yield 'do not include not built-in and no name' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => false],
+ [],
+ [],
+ [],
+ [],
+ ];
+
+ yield 'do not include different name' => [
+ ['include_built_in_normalizers' => false, 'include_built_in_encoders' => false],
+ ['serializer' => 'api2'],
+ ['serializer' => 'api2'],
+ [],
+ [],
+ ];
+ }
+
+ public function testMultipleNamedSerializerTagsAreResolvedCorrectly()
+ {
+ $container = new ContainerBuilder();
+
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => [],
+ 'api2' => [],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n0')->addTag('serializer.normalizer', ['serializer' => 'default']);
+ $container->register('e0')->addTag('serializer.encoder', ['serializer' => 'default']);
+
+ $normalizerDefinition = $container->register('n1')->addTag('serializer.normalizer', ['serializer' => ['api', 'api2']]);
+ $encoderDefinition = $container->register('e1')
+ ->addTag('serializer.encoder', ['serializer' => ['api', 'api2']])
+ ->addTag('serializer.encoder', ['serializer' => ['api', 'api2'], 'priority' => 100])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertTrue($normalizerDefinition->hasTag('serializer.normalizer.api'));
+ $this->assertCount(1, $normalizerDefinition->getTag('serializer.normalizer.api'));
+ $this->assertTrue($normalizerDefinition->hasTag('serializer.normalizer.api2'));
+ $this->assertCount(1, $normalizerDefinition->getTag('serializer.normalizer.api2'));
+
+ $this->assertTrue($encoderDefinition->hasTag('serializer.encoder.api'));
+ $this->assertCount(2, $encoderDefinition->getTag('serializer.encoder.api'));
+ $this->assertTrue($encoderDefinition->hasTag('serializer.encoder.api2'));
+ $this->assertCount(2, $encoderDefinition->getTag('serializer.encoder.api2'));
+ }
+
+ public function testThrowExceptionWhenNoNormalizersForNamedSerializers()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => [],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n0')->addTag('serializer.normalizer');
+ $container->register('e0')->addTag('serializer.encoder', ['serializer' => '*']);
+
+ $serializerPass = new SerializerPass();
+
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('The named serializer "api" requires at least one registered normalizer. Tag the normalizers as "serializer.normalizer" with the "serializer" attribute set to "api".');
+
+ $serializerPass->process($container);
+ }
+
+ public function testThrowExceptionWhenNoEncodersForNamedSerializers()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => [],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n0')->addTag('serializer.normalizer', ['serializer' => '*']);
+ $container->register('e0')->addTag('serializer.encoder');
+
+ $serializerPass = new SerializerPass();
+
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('The named serializer "api" requires at least one registered encoder. Tag the encoders as "serializer.encoder" with the "serializer" attribute set to "api".');
+
+ $serializerPass->process($container);
+ }
+
+ /**
+ * @testWith [null]
+ * ["some.converter"]
+ */
+ public function testChildNameConverterIsNotBuiltWhenExpected(?string $nameConverter)
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.name_converter', $nameConverter);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => ['name_converter' => $nameConverter],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n')->addTag('serializer.normalizer', ['serializer' => '*']);
+ $container->register('e')->addTag('serializer.encoder', ['serializer' => '*']);
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertFalse($container->hasDefinition('serializer.name_converter.metadata_aware.'.ContainerBuilder::hash($nameConverter)));
+ }
+
+ /**
+ * @dataProvider provideChildNameConverterCases
+ */
+ public function testChildNameConverterIsBuiltWhenExpected(
+ ?string $defaultSerializerNameConverter,
+ ?string $namedSerializerNameConverter,
+ string $nameConverterIdExists,
+ string $nameConverterIdDoesNotExist,
+ array $nameConverterArguments,
+ ) {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.name_converter', $defaultSerializerNameConverter);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => ['name_converter' => $namedSerializerNameConverter],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n')->addTag('serializer.normalizer', ['serializer' => '*']);
+ $container->register('e')->addTag('serializer.encoder', ['serializer' => '*']);
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertFalse($container->hasDefinition($nameConverterIdExists));
+ $this->assertTrue($container->hasDefinition($nameConverterIdDoesNotExist));
+ $this->assertEquals($nameConverterArguments, $container->getDefinition($nameConverterIdDoesNotExist)->getArguments());
+ }
+
+ public static function provideChildNameConverterCases(): iterable
+ {
+ $withNull = 'serializer.name_converter.metadata_aware.'.ContainerBuilder::hash(null);
+ $withConverter = 'serializer.name_converter.metadata_aware.'.ContainerBuilder::hash('some.converter');
+
+ yield [null, 'some.converter', $withNull, $withConverter, [new Reference('some.converter')]];
+ yield ['some.converter', null, $withConverter, $withNull, []];
+ }
+
+ /**
+ * @dataProvider provideDifferentNamedSerializerConfigsCases
+ */
+ public function testNamedSerializersCreateNewServices(
+ array $defaultSerializerDefaultContext,
+ ?string $defaultSerializerNameConverter,
+ array $namedSerializerConfig,
+ string $nameConverterId,
+ ) {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('serializer.default_context', $defaultSerializerDefaultContext);
+ $container->setParameter('.serializer.name_converter', $defaultSerializerNameConverter);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => $namedSerializerConfig,
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n')
+ ->addArgument(new Reference('serializer.name_converter.metadata_aware'))
+ ->addTag('serializer.normalizer', ['serializer' => '*'])
+ ;
+ $container->register('e')
+ ->addArgument(new Reference('serializer.name_converter.metadata_aware'))
+ ->addTag('serializer.encoder', ['serializer' => '*'])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertEquals([new Reference('n.api')], $container->getDefinition('serializer.api')->getArgument(0));
+ $this->assertEquals(new Reference($nameConverterId), $container->getDefinition('n.api')->getArgument(0));
+ $this->assertEquals([new Reference('e.api')], $container->getDefinition('serializer.api')->getArgument(1));
+ $this->assertEquals(new Reference($nameConverterId), $container->getDefinition('e.api')->getArgument(0));
+ }
+
+ public static function provideDifferentNamedSerializerConfigsCases(): iterable
+ {
+ yield [
+ ['a' => true, 'b' => 3],
+ null,
+ ['default_context' => ['c' => 3, 'a' => true]],
+ 'serializer.name_converter.metadata_aware',
+ ];
+ yield [
+ [],
+ 'some.converter',
+ ['name_converter' => null],
+ 'serializer.name_converter.metadata_aware.'.ContainerBuilder::hash(null),
+ ];
+ yield [
+ ['a' => true, 'b' => 3],
+ null,
+ ['default_context' => ['c' => 3, 'a' => true], 'name_converter' => 'some.converter'],
+ 'serializer.name_converter.metadata_aware.'.ContainerBuilder::hash('some.converter'),
+ ];
+ }
+
+ public function testServicesAreOrderedAccordingToPriorityForNamedSerializers()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => [],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n2')
+ ->addTag('serializer.normalizer', ['serializer' => '*', 'priority' => 100])
+ ->addTag('serializer.encoder', ['serializer' => '*', 'priority' => 100])
+ ;
+ $container->register('n1')
+ ->addTag('serializer.normalizer', ['serializer' => 'api', 'priority' => 200])
+ ->addTag('serializer.encoder', ['serializer' => 'api', 'priority' => 200])
+ ;
+ $container->register('n3')
+ ->addTag('serializer.normalizer', ['serializer' => 'api'])
+ ->addTag('serializer.encoder', ['serializer' => 'api'])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertTrue($container->hasDefinition('serializer.api'));
+ $definition = $container->getDefinition('serializer.api');
+
+ $expected = [
+ new Reference('n1.api'),
+ new Reference('n2.api'),
+ new Reference('n3.api'),
+ ];
+ $this->assertEquals($expected, $definition->getArgument(0));
+ $this->assertEquals($expected, $definition->getArgument(1));
+ }
+
+ public function testBindSerializerDefaultContextToNamedSerializers()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => ['default_context' => $defaultContext = ['enable_max_depth' => true]],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null, []]);
+ $definition = $container->register('n1')
+ ->addTag('serializer.normalizer', ['serializer' => '*'])
+ ->addTag('serializer.encoder', ['serializer' => '*'])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $bindings = $definition->getBindings();
+ $this->assertArrayHasKey('array $defaultContext', $bindings);
+ $this->assertEquals($bindings['array $defaultContext'], new BoundArgument([], false));
+
+ $bindings = $container->getDefinition('n1.api')->getBindings();
+ $this->assertArrayHasKey('array $defaultContext', $bindings);
+ $this->assertEquals($bindings['array $defaultContext'], new BoundArgument($defaultContext, false));
+ $this->assertArrayNotHasKey('$defaultContext', $container->getDefinition('serializer')->getArguments());
+ $this->assertEquals($defaultContext, $container->getDefinition('serializer.api')->getArgument('$defaultContext'));
+ }
+
+ /**
+ * @testWith [{}, {}, {}]
+ * [{"enable_max_depth": true}, {}, {"enable_max_depth": true}]
+ * [{}, {".serializer.circular_reference_handler": "foo"}, {"circular_reference_handler": "foo"}]
+ * [{}, {".serializer.max_depth_handler": "bar"}, {"max_depth_handler": "bar"}]
+ * [{"enable_max_depth": true}, {".serializer.circular_reference_handler": "foo", ".serializer.max_depth_handler": "bar"}, {"enable_max_depth": true, "circular_reference_handler": "foo", "max_depth_handler": "bar"}]
+ */
+ public function testBindNamedSerializerObjectNormalizerDefaultContext(array $defaultContext, array $parameters, array $context)
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => ['default_context' => $defaultContext],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null, []]);
+ $container->getParameterBag()->add($parameters);
+ $container->register('serializer.normalizer.object')
+ ->setClass(ObjectNormalizer::class)
+ ->addTag('serializer.normalizer', ['serializer' => '*'])
+ ->addTag('serializer.encoder', ['serializer' => '*'])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $bindings = $container->getDefinition('serializer.normalizer.object.api')->getBindings();
+ $this->assertArrayHasKey('array $defaultContext', $bindings);
+ $this->assertEquals($bindings['array $defaultContext'], new BoundArgument($context, false));
+ }
+
+ public function testNamedSerializersAreRegistered()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.debug', false);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => [],
+ 'api2' => [],
+ ]);
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n')->addTag('serializer.normalizer', ['serializer' => '*']);
+ $container->register('e')->addTag('serializer.encoder', ['serializer' => '*']);
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $this->assertFalse($container->hasAlias(\sprintf('%s $defaultSerializer', SerializerInterface::class)));
+
+ $this->assertTrue($container->hasDefinition('serializer.api'));
+ $this->assertTrue($container->hasAlias(\sprintf('%s $apiSerializer', SerializerInterface::class)));
+ $this->assertTrue($container->hasDefinition('serializer.api2'));
+ $this->assertTrue($container->hasAlias(\sprintf('%s $api2Serializer', SerializerInterface::class)));
+ }
+
+ public function testNormalizersAndEncodersAreDecoratedAndOrderedWhenCollectingDataForNamedSerializers()
+ {
+ $container = new ContainerBuilder();
+
+ $container->setParameter('kernel.debug', true);
+ $container->setParameter('.serializer.named_serializers', [
+ 'api' => ['default_context' => ['enable_max_depth' => true]],
+ ]);
+ $container->register('serializer.data_collector');
+
+ $container->register('serializer')->setArguments([null, null]);
+ $container->register('n')->addTag('serializer.normalizer', ['serializer' => '*']);
+ $container->register('e')->addTag('serializer.encoder', ['serializer' => '*']);
+
+ $container->register('debug.serializer', TraceableSerializer::class)
+ ->setDecoratedService('serializer')
+ ->setArguments([
+ new Reference('debug.serializer.inner'),
+ new Reference('serializer.data_collector'),
+ 'default',
+ ])
+ ;
+
+ $serializerPass = new SerializerPass();
+ $serializerPass->process($container);
+
+ $traceableNormalizerDefinition = $container->getDefinition('.debug.serializer.normalizer.n.api');
+ $traceableEncoderDefinition = $container->getDefinition('.debug.serializer.encoder.e.api');
+
+ $traceableSerializerDefinition = $container->getDefinition('debug.serializer.api');
+ $this->assertSame('serializer.api', $traceableSerializerDefinition->getDecoratedService()[0]);
+ $this->assertEquals(new Reference('debug.serializer.api.inner'), $traceableSerializerDefinition->getArgument(0));
+ $this->assertSame('api', $traceableSerializerDefinition->getArgument(2));
+
+ $this->assertEquals(TraceableNormalizer::class, $traceableNormalizerDefinition->getClass());
+ $this->assertEquals(new Reference('n.api'), $traceableNormalizerDefinition->getArgument(0));
+ $this->assertEquals(new Reference('serializer.data_collector'), $traceableNormalizerDefinition->getArgument(1));
+ $this->assertSame('api', $traceableNormalizerDefinition->getArgument(2));
+
+ $this->assertEquals(TraceableEncoder::class, $traceableEncoderDefinition->getClass());
+ $this->assertEquals(new Reference('e.api'), $traceableEncoderDefinition->getArgument(0));
+ $this->assertEquals(new Reference('serializer.data_collector'), $traceableEncoderDefinition->getArgument(1));
+ $this->assertSame('api', $traceableEncoderDefinition->getArgument(2));
}
}
diff --git a/Tests/Encoder/CsvEncoderTest.php b/Tests/Encoder/CsvEncoderTest.php
index c0be73a8b..048d790b0 100644
--- a/Tests/Encoder/CsvEncoderTest.php
+++ b/Tests/Encoder/CsvEncoderTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -20,6 +21,8 @@
*/
class CsvEncoderTest extends TestCase
{
+ use ExpectUserDeprecationMessageTrait;
+
private CsvEncoder $encoder;
protected function setUp(): void
@@ -149,7 +152,6 @@ public function testEncodeCustomSettings()
$this->encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);
@@ -175,7 +177,6 @@ public function testEncodeCustomSettingsPassedInContext()
, $this->encoder->encode($value, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
@@ -185,7 +186,6 @@ public function testEncodeCustomSettingsPassedInConstructor()
$encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);
$value = ['a' => 'he\'llo', 'c' => ['d' => 'foo']];
@@ -574,7 +574,6 @@ public function testDecodeCustomSettings()
$this->encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);
@@ -596,7 +595,6 @@ public function testDecodeCustomSettingsPassedInContext()
, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
@@ -606,7 +604,6 @@ public function testDecodeCustomSettingsPassedInConstructor()
$encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
- CsvEncoder::ESCAPE_CHAR_KEY => '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
CsvEncoder::AS_COLLECTION_KEY => true, // Can be removed in 5.0
]);
@@ -710,4 +707,26 @@ public function testEndOfLinePassedInConstructor()
$encoder = new CsvEncoder([CsvEncoder::END_OF_LINE => "\r\n"]);
$this->assertSame("foo,bar\r\nhello,test\r\n", $encoder->encode($value, 'csv'));
}
+
+ /**
+ * @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/Encoder/XmlEncoderTest.php b/Tests/Encoder/XmlEncoderTest.php
index 5be6be232..0eb332e80 100644
--- a/Tests/Encoder/XmlEncoderTest.php
+++ b/Tests/Encoder/XmlEncoderTest.php
@@ -39,46 +39,39 @@ protected function setUp(): void
$this->encoder->setSerializer($serializer);
}
- public function testEncodeScalar()
+ /**
+ * @dataProvider validEncodeProvider
+ */
+ public function testEncode(string $expected, mixed $data, array $context = [])
{
- $obj = new ScalarDummy();
- $obj->xmlFoo = 'foo';
-
- $expected = ''."\n".
- 'foo'."\n";
-
- $this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
+ $this->assertSame($expected, $this->encoder->encode($data, 'xml', $context));
}
- public function testEncodeArrayObject()
- {
- $obj = new \ArrayObject(['foo' => 'bar']);
-
- $expected = ''."\n".
- 'bar'."\n";
-
- $this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
- }
-
- public function testEncodeEmptyArrayObject()
+ /**
+ * @return iterable
+ */
+ public static function validEncodeProvider(): iterable
{
- $obj = new \ArrayObject();
+ $obj = new ScalarDummy();
+ $obj->xmlFoo = 'foo';
- $expected = ''."\n".
- ''."\n";
+ yield 'encode scalar' => [
+ ''."\n"
+ .'foo'."\n",
+ $obj,
+ ];
- $this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
- }
+ yield 'encode array object' => [
+ ''."\n"
+ .'bar'."\n",
+ new \ArrayObject(['foo' => 'bar']),
+ ];
- public function testDocTypeIsNotAllowed()
- {
- $this->expectException(UnexpectedValueException::class);
- $this->expectExceptionMessage('Document types are not allowed.');
- $this->encoder->decode('', 'foo');
- }
+ yield 'encode empty array object' => [
+ ''."\n".''."\n",
+ new \ArrayObject(),
+ ];
- public function testAttributes()
- {
$obj = new ScalarDummy();
$obj->xmlFoo = [
'foo-bar' => [
@@ -100,7 +93,9 @@ public function testAttributes()
'@sring' => 'a',
],
];
- $expected = ''."\n".
+
+ yield 'attributes' => [
+ ''."\n".
''.
''.
'Test'.
@@ -110,12 +105,10 @@ public function testAttributes()
'3'.
'b'.
''.
- ''."\n";
- $this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
- }
+ ''."\n",
+ $obj,
+ ];
- public function testElementNameValid()
- {
$obj = new ScalarDummy();
$obj->xmlFoo = [
'foo-bar' => 'a',
@@ -123,70 +116,54 @@ public function testElementNameValid()
'föo_bär' => 'a',
];
- $expected = ''."\n".
+ yield 'element name valid' => [
+ ''."\n".
''.
'a'.
'a'.
'a'.
- ''."\n";
-
- $this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
- }
+ ''."\n",
+ $obj,
+ ];
- public function testEncodeSimpleXML()
- {
$xml = simplexml_load_string('Peter');
$array = ['person' => $xml];
- $expected = ''."\n".
- 'Peter'."\n";
-
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
- }
+ yield 'encode SimpleXML' => [
+ ''."\n".
+ 'Peter'."\n",
+ $array,
+ ];
- public function testEncodeXmlAttributes()
- {
$xml = simplexml_load_string('Peter');
$array = ['person' => $xml];
- $expected = ''."\n".
- 'Peter'."\n";
-
- $context = [
- 'xml_version' => '1.1',
- 'xml_encoding' => 'utf-8',
- 'xml_standalone' => true,
+ yield 'encode XML attributes' => [
+ ''."\n".
+ 'Peter'."\n",
+ $array,
+ [
+ 'xml_version' => '1.1',
+ 'xml_encoding' => 'utf-8',
+ 'xml_standalone' => true,
+ ],
];
- $this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
- }
-
- public function testEncodeRemovingEmptyTags()
- {
- $array = ['person' => ['firstname' => 'Peter', 'lastname' => null]];
-
- $expected = ''."\n".
- 'Peter'."\n";
-
- $context = ['remove_empty_tags' => true];
-
- $this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
- }
-
- public function testEncodeNotRemovingEmptyTags()
- {
- $array = ['person' => ['firstname' => 'Peter', 'lastname' => null]];
-
- $expected = ''."\n".
- 'Peter'."\n";
+ yield 'encode removing empty tags' => [
+ ''."\n".
+ 'Peter'."\n",
+ ['person' => ['firstname' => 'Peter', 'lastname' => null]],
+ ['remove_empty_tags' => true],
+ ];
- $this->assertSame($expected, $this->encoder->encode($array, 'xml'));
- }
+ yield 'encode not removing empty tags' => [
+ ''."\n".
+ 'Peter'."\n",
+ ['person' => ['firstname' => 'Peter', 'lastname' => null]],
+ ];
- public function testContext()
- {
- $array = ['person' => ['name' => 'George Abitbol', 'age' => null]];
- $expected = <<<'XML'
+ yield 'encode with context' => [
+ <<<'XML'
@@ -195,128 +172,139 @@ public function testContext()
-XML;
+XML,
+ ['person' => ['name' => 'George Abitbol', 'age' => null]],
+ [
+ 'xml_format_output' => true,
+ 'save_options' => \LIBXML_NOEMPTYTAG,
+ ],
+ ];
- $context = [
- 'xml_format_output' => true,
- 'save_options' => \LIBXML_NOEMPTYTAG,
+ yield 'encode scalar root attributes' => [
+ ''."\n".
+ 'Paul'."\n",
+ [
+ '#' => 'Paul',
+ '@eye-color' => 'brown',
+ ],
];
- $this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
- }
+ yield 'encode root attributes' => [
+ ''."\n".
+ 'Paul'."\n",
+ [
+ 'firstname' => 'Paul',
+ '@eye-color' => 'brown',
+ ],
+ ];
- public function testEncodeScalarRootAttributes()
- {
- $array = [
- '#' => 'Paul',
- '@eye-color' => 'brown',
+ yield 'encode with CDATA wrapping with default pattern #1' => [
+ ''."\n".
+ ']]>'."\n",
+ ['firstname' => 'Paul & Martha '],
];
- $expected = ''."\n".
- 'Paul'."\n";
+ yield 'encode with CDATA wrapping with default pattern #2' => [
+ ''."\n".
+ 'O\'Donnel'."\n",
+ ['lastname' => 'O\'Donnel'],
+ ];
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
- }
+ yield 'encode with CDATA wrapping with default pattern #3' => [
+ ''."\n".
+ ''."\n",
+ ['firstname' => 'Paul & Martha'],
+ ];
- public function testEncodeRootAttributes()
- {
- $array = [
- 'firstname' => 'Paul',
- '@eye-color' => 'brown',
+ yield 'encode with CDATA wrapping with custom pattern #1' => [
+ ''."\n".
+ ']]>'."\n",
+ ['firstname' => 'Paul & Martha '],
+ ['cdata_wrapping_pattern' => '/[<>&"\']/'],
];
- $expected = ''."\n".
- 'Paul'."\n";
+ yield 'encode with CDATA wrapping with custom pattern #2' => [
+ ''."\n".
+ ''."\n",
+ ['lastname' => 'O\'Donnel'],
+ ['cdata_wrapping_pattern' => '/[<>&"\']/'],
+ ];
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
- }
+ yield 'encode with CDATA wrapping with custom pattern #3' => [
+ ''."\n".
+ 'Paul and Martha'."\n",
+ ['firstname' => 'Paul and Martha'],
+ ['cdata_wrapping_pattern' => '/[<>&"\']/'],
+ ];
- /**
- * @dataProvider encodeCdataWrappingWithDefaultPattern
- */
- public function testEncodeCdataWrappingWithDefaultPattern($input, $expected)
- {
- $this->assertEquals($expected, $this->encoder->encode($input, 'xml'));
- }
+ yield 'enable CDATA wrapping' => [
+ ''."\n".
+ ']]>'."\n",
+ ['firstname' => 'Paul & Martha '],
+ ['cdata_wrapping' => true],
+ ];
- public static function encodeCdataWrappingWithDefaultPattern()
- {
- return [
- [
- ['firstname' => 'Paul and Martha'],
- ''."\n".'Paul and Martha'."\n",
- ],
- [
- ['lastname' => 'O\'Donnel'],
- ''."\n".'O\'Donnel'."\n",
- ],
- [
- ['firstname' => 'Paul & Martha '],
- ''."\n".']]>'."\n",
- ],
+ yield 'disable CDATA wrapping' => [
+ ''."\n".
+ 'Paul & Martha <or Me>'."\n",
+ ['firstname' => 'Paul & Martha '],
+ ['cdata_wrapping' => false],
];
- }
- /**
- * @dataProvider encodeCdataWrappingWithCustomPattern
- */
- public function testEncodeCdataWrappingWithCustomPattern($input, $expected)
- {
- $this->assertEquals($expected, $this->encoder->encode($input, 'xml', ['cdata_wrapping_pattern' => '/[<>&"\']/']));
- }
+ yield 'encode scalar with attribute' => [
+ ''."\n".
+ 'Peter'."\n",
+ ['person' => ['@eye-color' => 'brown', '#' => 'Peter']],
+ ];
- public static function encodeCdataWrappingWithCustomPattern()
- {
- return [
- [
- ['firstname' => 'Paul and Martha'],
- ''."\n".'Paul and Martha'."\n",
- ],
- [
- ['lastname' => 'O\'Donnel'],
- ''."\n".''."\n",
- ],
- [
- ['firstname' => 'Paul & Martha '],
- ''."\n".']]>'."\n",
- ],
+ yield 'encode' => [
+ self::getXmlSource(),
+ self::getObject(),
+ ];
+
+ yield 'encode with namespace' => [
+ self::getNamespacedXmlSource(),
+ self::getNamespacedArray(),
];
}
- public function testEnableCdataWrapping()
+ public function testEncodeSerializerXmlRootNodeNameOption()
{
+ $options = ['xml_root_node_name' => 'test'];
+ $this->encoder = new XmlEncoder();
+ $serializer = new Serializer([], ['xml' => new XmlEncoder()]);
+ $this->encoder->setSerializer($serializer);
+
$array = [
- 'firstname' => 'Paul & Martha ',
+ 'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
];
$expected = ''."\n".
- ']]>'."\n";
+ 'Peter'."\n";
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml', ['cdata_wrapping' => true]));
+ $this->assertSame($expected, $serializer->serialize($array, 'xml', $options));
}
- public function testDisableCdataWrapping()
+ public function testEncodeTraversableWhenNormalizable()
{
- $array = [
- 'firstname' => 'Paul & Martha ',
- ];
+ $this->encoder = new XmlEncoder();
+ $serializer = new Serializer([new CustomNormalizer()], ['xml' => new XmlEncoder()]);
+ $this->encoder->setSerializer($serializer);
- $expected = ''."\n".
- 'Paul & Martha <or Me>'."\n";
+ $expected = <<<'XML'
+
+normalizedFoonormalizedBar
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml', ['cdata_wrapping' => false]));
+XML;
+
+ $this->assertSame($expected, $serializer->serialize(new NormalizableTraversableDummy(), 'xml'));
}
- public function testEncodeScalarWithAttribute()
+ public function testDocTypeIsNotAllowed()
{
- $array = [
- 'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
- ];
-
- $expected = ''."\n".
- 'Peter'."\n";
-
- $this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
+ $this->expectException(UnexpectedValueException::class);
+ $this->expectExceptionMessage('Document types are not allowed.');
+ $this->encoder->decode('', 'foo');
}
public function testDecodeScalar()
@@ -324,7 +312,7 @@ public function testDecodeScalar()
$source = ''."\n".
'foo'."\n";
- $this->assertEquals('foo', $this->encoder->decode($source, 'xml'));
+ $this->assertSame('foo', $this->encoder->decode($source, 'xml'));
}
public function testDecodeBigDigitAttributes()
@@ -425,54 +413,6 @@ public function testDoesNotTypeCastStringsStartingWith0()
$this->assertSame('018', $data['@a']);
}
- public function testEncode()
- {
- $source = $this->getXmlSource();
- $obj = $this->getObject();
-
- $this->assertEquals($source, $this->encoder->encode($obj, 'xml'));
- }
-
- public function testEncodeWithNamespace()
- {
- $source = $this->getNamespacedXmlSource();
- $array = $this->getNamespacedArray();
-
- $this->assertEquals($source, $this->encoder->encode($array, 'xml'));
- }
-
- public function testEncodeSerializerXmlRootNodeNameOption()
- {
- $options = ['xml_root_node_name' => 'test'];
- $this->encoder = new XmlEncoder();
- $serializer = new Serializer([], ['xml' => new XmlEncoder()]);
- $this->encoder->setSerializer($serializer);
-
- $array = [
- 'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
- ];
-
- $expected = ''."\n".
- 'Peter'."\n";
-
- $this->assertEquals($expected, $serializer->serialize($array, 'xml', $options));
- }
-
- public function testEncodeTraversableWhenNormalizable()
- {
- $this->encoder = new XmlEncoder();
- $serializer = new Serializer([new CustomNormalizer()], ['xml' => new XmlEncoder()]);
- $this->encoder->setSerializer($serializer);
-
- $expected = <<<'XML'
-
-normalizedFoonormalizedBar
-
-XML;
-
- $this->assertEquals($expected, $serializer->serialize(new NormalizableTraversableDummy(), 'xml'));
- }
-
public function testEncodeException()
{
$this->expectException(NotEncodableValueException::class);
@@ -671,8 +611,8 @@ public function testDecodeIgnoreComments()
XML;
$expected = ['person' => [
- ['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
- ['firstname' => 'Damien', 'lastname' => 'Clay'],
+ ['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
+ ['firstname' => 'Damien', 'lastname' => 'Clay'],
]];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
@@ -695,8 +635,8 @@ public function testDecodeIgnoreDocumentType()
XML;
$expected = ['person' => [
- ['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
- ['firstname' => 'Damien', 'lastname' => 'Clay'],
+ ['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
+ ['firstname' => 'Damien', 'lastname' => 'Clay'],
]];
$this->assertEquals($expected, $this->encoder->decode(
$source,
@@ -730,8 +670,8 @@ public function testDecodePreserveComments()
$this->encoder->setSerializer($serializer);
$expected = ['person' => [
- ['firstname' => 'Benjamin', 'lastname' => 'Alexandre', '#comment' => ' This comment should be decoded. '],
- ['firstname' => 'Damien', 'lastname' => 'Clay'],
+ ['firstname' => 'Benjamin', 'lastname' => 'Alexandre', '#comment' => ' This comment should be decoded. '],
+ ['firstname' => 'Damien', 'lastname' => 'Clay'],
]];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
@@ -816,7 +756,7 @@ public function testDecodeEmptyXml()
$this->encoder->decode(' ', 'xml');
}
- protected function getXmlSource()
+ protected static function getXmlSource(): string
{
return ''."\n".
''.
@@ -829,7 +769,7 @@ protected function getXmlSource()
''."\n";
}
- protected function getNamespacedXmlSource()
+ protected static function getNamespacedXmlSource(): string
{
return ''."\n".
''.
@@ -842,7 +782,7 @@ protected function getNamespacedXmlSource()
''."\n";
}
- protected function getNamespacedArray()
+ protected static function getNamespacedArray(): array
{
return [
'@xmlns' => 'http://www.w3.org/2005/Atom',
@@ -876,7 +816,10 @@ protected function getNamespacedArray()
];
}
- protected function getObject()
+ /**
+ * @return Dummy
+ */
+ protected static function getObject(): object
{
$obj = new Dummy();
$obj->foo = 'foo';
@@ -1050,14 +993,14 @@ private function createMockDateTimeNormalizer(): MockObject&NormalizerInterface
private function createXmlWithDateTime(): string
{
- return sprintf('
+ return \sprintf('
%s
', $this->exampleDateTimeString);
}
private function createXmlWithDateTimeField(): string
{
- return sprintf('
+ return \sprintf('
', $this->exampleDateTimeString);
}
diff --git a/Tests/Fixtures/Attributes/GroupDummy.php b/Tests/Fixtures/Attributes/GroupDummy.php
index 749e841a5..41457d796 100644
--- a/Tests/Fixtures/Attributes/GroupDummy.php
+++ b/Tests/Fixtures/Attributes/GroupDummy.php
@@ -12,7 +12,7 @@
namespace Symfony\Component\Serializer\Tests\Fixtures\Attributes;
use Symfony\Component\Serializer\Attribute\Groups;
-use Symfony\Component\Serializer\Tests\Fixtures\ChildOfGroupsAnnotationDummy;
+use Symfony\Component\Serializer\Tests\Fixtures\ChildOfGroupsAttributeDummy;
/**
* @author Kévin Dunglas
@@ -23,7 +23,7 @@ class GroupDummy extends GroupDummyParent implements GroupDummyInterface
private $foo;
#[Groups(['b', 'c', 'name_converter'])]
protected $bar;
- #[ChildOfGroupsAnnotationDummy]
+ #[ChildOfGroupsAttributeDummy]
protected $quux;
private $fooBar;
private $symfony;
diff --git a/Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations.php b/Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAttributes.php
similarity index 85%
rename from Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations.php
rename to Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAttributes.php
index 21abb870b..5d3e8f47f 100644
--- a/Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations.php
+++ b/Tests/Fixtures/Attributes/IgnoreDummyAdditionalGetterWithoutIgnoreAttributes.php
@@ -2,7 +2,7 @@
namespace Symfony\Component\Serializer\Tests\Fixtures\Attributes;
-class IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations
+class IgnoreDummyAdditionalGetterWithoutIgnoreAttributes
{
private $myValue;
diff --git a/Tests/Fixtures/ChildOfGroupsAnnotationDummy.php b/Tests/Fixtures/ChildOfGroupsAttributeDummy.php
similarity index 82%
rename from Tests/Fixtures/ChildOfGroupsAnnotationDummy.php
rename to Tests/Fixtures/ChildOfGroupsAttributeDummy.php
index 9a163012f..4fc81fa9d 100644
--- a/Tests/Fixtures/ChildOfGroupsAnnotationDummy.php
+++ b/Tests/Fixtures/ChildOfGroupsAttributeDummy.php
@@ -5,7 +5,7 @@
use Symfony\Component\Serializer\Attribute\Groups;
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
-final class ChildOfGroupsAnnotationDummy extends Groups
+final class ChildOfGroupsAttributeDummy extends Groups
{
public function __construct()
{
diff --git a/Tests/Fixtures/DummyObjectWithEnumProperty.php b/Tests/Fixtures/DummyObjectWithEnumProperty.php
index f2677195f..70c6cff7b 100644
--- a/Tests/Fixtures/DummyObjectWithEnumProperty.php
+++ b/Tests/Fixtures/DummyObjectWithEnumProperty.php
@@ -2,8 +2,6 @@
namespace Symfony\Component\Serializer\Tests\Fixtures;
-use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
-
class DummyObjectWithEnumProperty
{
public StringBackedEnumDummy $get;
diff --git a/Tests/Mapping/Factory/CacheMetadataFactoryTest.php b/Tests/Mapping/Factory/CacheMetadataFactoryTest.php
index 6db0b95ae..e18dd707f 100644
--- a/Tests/Mapping/Factory/CacheMetadataFactoryTest.php
+++ b/Tests/Mapping/Factory/CacheMetadataFactoryTest.php
@@ -68,7 +68,7 @@ public function testInvalidClassThrowsException()
public function testAnonymousClass()
{
- $anonymousObject = new class() {
+ $anonymousObject = new class {
};
$metadata = new ClassMetadata($anonymousObject::class);
diff --git a/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php b/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php
index 20b057211..40dcb5015 100644
--- a/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php
+++ b/Tests/Mapping/Factory/ClassMetadataFactoryCompilerTest.php
@@ -27,7 +27,7 @@ final class ClassMetadataFactoryCompilerTest extends TestCase
protected function setUp(): void
{
- $this->dumpPath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_serializer_metadata.'.uniqid('CompiledClassMetadataFactory', true).'.php';
+ $this->dumpPath = tempnam(sys_get_temp_dir(), 'sf_serializer_metadata_');
}
protected function tearDown(): void
diff --git a/Tests/Mapping/Loader/AttributeLoaderTest.php b/Tests/Mapping/Loader/AttributeLoaderTest.php
index 5a078bf36..2af244a6f 100644
--- a/Tests/Mapping/Loader/AttributeLoaderTest.php
+++ b/Tests/Mapping/Loader/AttributeLoaderTest.php
@@ -34,7 +34,7 @@
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\GroupDummyParent;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummyAdditionalGetter;
-use Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations;
+use Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummyAdditionalGetterWithoutIgnoreAttributes;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\MaxDepthDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedNameDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedPathDummy;
@@ -163,7 +163,7 @@ public function testLoadContextsPropertiesPromoted()
public function testThrowsOnContextOnInvalidMethod()
{
$this->expectException(MappingException::class);
- $this->expectExceptionMessage(sprintf('Context on "%s::badMethod()" cannot be added', BadMethodContextDummy::class));
+ $this->expectExceptionMessage(\sprintf('Context on "%s::badMethod()" cannot be added', BadMethodContextDummy::class));
$loader = $this->getLoaderForContextMapping();
@@ -182,7 +182,7 @@ public function testCanHandleUnrelatedIgnoredMethods()
$this->assertSame(['id'], array_keys($metadata->getAttributesMetadata()));
}
- public function testIgnoreGetterWithRequiredParameterIfIgnoreAnnotationIsUsed()
+ public function testIgnoreGetterWithRequiredParameterIfIgnoreAttributeIsUsed()
{
$classMetadata = new ClassMetadata(IgnoreDummyAdditionalGetter::class);
$this->getLoaderForContextMapping()->loadClassMetadata($classMetadata);
@@ -192,9 +192,9 @@ public function testIgnoreGetterWithRequiredParameterIfIgnoreAnnotationIsUsed()
self::assertArrayHasKey('extraValue2', $attributes);
}
- public function testIgnoreGetterWithRequiredParameterIfIgnoreAnnotationIsNotUsed()
+ public function testIgnoreGetterWithRequiredParameterIfIgnoreAttributeIsNotUsed()
{
- $classMetadata = new ClassMetadata(IgnoreDummyAdditionalGetterWithoutIgnoreAnnotations::class);
+ $classMetadata = new ClassMetadata(IgnoreDummyAdditionalGetterWithoutIgnoreAttributes::class);
$this->getLoaderForContextMapping()->loadClassMetadata($classMetadata);
$attributes = $classMetadata->getAttributesMetadata();
diff --git a/Tests/NameConverter/SnakeCaseToCamelCaseNameConverterTest.php b/Tests/NameConverter/SnakeCaseToCamelCaseNameConverterTest.php
new file mode 100644
index 000000000..2d2799e2c
--- /dev/null
+++ b/Tests/NameConverter/SnakeCaseToCamelCaseNameConverterTest.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Serializer\Tests\NameConverter;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Serializer\Exception\UnexpectedPropertyException;
+use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
+use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;
+
+/**
+ * @author Kévin Dunglas
+ * @author Aurélien Pillevesse
+ */
+class SnakeCaseToCamelCaseNameConverterTest extends TestCase
+{
+ public function testInterface()
+ {
+ $attributeMetadata = new SnakeCaseToCamelCaseNameConverter();
+ $this->assertInstanceOf(NameConverterInterface::class, $attributeMetadata);
+ }
+
+ /**
+ * @dataProvider Symfony\Component\Serializer\Tests\NameConverter\CamelCaseToSnakeCaseNameConverterTest::attributeProvider
+ */
+ public function testNormalize($underscored, $camelCased, $useLowerCamelCase)
+ {
+ $nameConverter = new SnakeCaseToCamelCaseNameConverter(null, $useLowerCamelCase);
+ $this->assertEquals($camelCased, $nameConverter->normalize($underscored));
+ }
+
+ /**
+ * @dataProvider Symfony\Component\Serializer\Tests\NameConverter\CamelCaseToSnakeCaseNameConverterTest::attributeProvider
+ */
+ public function testDenormalize($underscored, $camelCased, $useLowerCamelCase)
+ {
+ $nameConverter = new SnakeCaseToCamelCaseNameConverter(null, $useLowerCamelCase);
+ $this->assertEquals($underscored, $nameConverter->denormalize($camelCased));
+ }
+
+ public function testDenormalizeWithContext()
+ {
+ $nameConverter = new SnakeCaseToCamelCaseNameConverter(null, true);
+ $denormalizedValue = $nameConverter->denormalize('lastName', null, null, [SnakeCaseToCamelCaseNameConverter::REQUIRE_CAMEL_CASE_PROPERTIES => true]);
+
+ $this->assertSame('last_name', $denormalizedValue);
+ }
+
+ public function testErrorDenormalizeWithContext()
+ {
+ $nameConverter = new SnakeCaseToCamelCaseNameConverter(null, true);
+
+ $this->expectException(UnexpectedPropertyException::class);
+ $nameConverter->denormalize('last_name', null, null, [SnakeCaseToCamelCaseNameConverter::REQUIRE_CAMEL_CASE_PROPERTIES => true]);
+ }
+}
diff --git a/Tests/Normalizer/AbstractNormalizerTest.php b/Tests/Normalizer/AbstractNormalizerTest.php
index 3108fe3c6..74ca3d6d6 100644
--- a/Tests/Normalizer/AbstractNormalizerTest.php
+++ b/Tests/Normalizer/AbstractNormalizerTest.php
@@ -271,7 +271,7 @@ public function testVariadicConstructorDenormalization()
public static function getNormalizerWithCustomNameConverter()
{
$extractor = new PhpDocExtractor();
- $nameConverter = new class() implements NameConverterInterface {
+ $nameConverter = new class implements NameConverterInterface {
public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string
{
return ucfirst($propertyName);
diff --git a/Tests/Normalizer/AbstractObjectNormalizerTest.php b/Tests/Normalizer/AbstractObjectNormalizerTest.php
index 27f3c2084..270b65f33 100644
--- a/Tests/Normalizer/AbstractObjectNormalizerTest.php
+++ b/Tests/Normalizer/AbstractObjectNormalizerTest.php
@@ -529,7 +529,7 @@ public function testDenormalizeWithDiscriminatorMapUsesCorrectClassname()
{
$factory = new ClassMetadataFactory(new AttributeLoader());
- $loaderMock = new class() implements ClassMetadataFactoryInterface {
+ $loaderMock = new class implements ClassMetadataFactoryInterface {
public function getMetadataFor($value): ClassMetadataInterface
{
if (AbstractDummy::class === $value) {
@@ -564,7 +564,7 @@ public function testDenormalizeWithDiscriminatorMapAndObjectToPopulateUsesCorrec
{
$factory = new ClassMetadataFactory(new AttributeLoader());
- $loaderMock = new class() implements ClassMetadataFactoryInterface {
+ $loaderMock = new class implements ClassMetadataFactoryInterface {
public function getMetadataFor($value): ClassMetadataInterface
{
if (AbstractDummy::class === $value) {
@@ -617,7 +617,7 @@ public function hasMetadataFor($value): bool
public function testDenormalizeWithNestedDiscriminatorMap()
{
- $classDiscriminatorResolver = new class() implements ClassDiscriminatorResolverInterface {
+ $classDiscriminatorResolver = new class implements ClassDiscriminatorResolverInterface {
public function getMappingForClass(string $class): ?ClassDiscriminatorMapping
{
return match ($class) {
@@ -870,7 +870,7 @@ public function testDenormalizeWithNumberAsSerializedNameAndNoArrayReindex()
'99' => 'baz',
];
- $obj = new class() {
+ $obj = new class {
#[SerializedName('1')]
public $foo;
@@ -894,7 +894,7 @@ public function testDenormalizeWithCorrectOrderOfAttributeAndProperty()
],
];
- $obj = new class() {
+ $obj = new class {
#[SerializedPath('[data][id]')]
public $id;
};
@@ -905,7 +905,7 @@ public function testDenormalizeWithCorrectOrderOfAttributeAndProperty()
public function testNormalizeBasedOnAllowedAttributes()
{
- $normalizer = new class() extends AbstractObjectNormalizer {
+ $normalizer = new class extends AbstractObjectNormalizer {
public function getSupportedTypes(?string $format): array
{
return ['*' => false];
@@ -985,7 +985,7 @@ public function testProvidingContextCacheKeyGeneratesSameChildContextCacheKey()
$foobar->bar = 'bar';
$foobar->baz = 'baz';
- $normalizer = new class() extends AbstractObjectNormalizerDummy {
+ $normalizer = new class extends AbstractObjectNormalizerDummy {
public $childContextCacheKey;
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
@@ -1025,7 +1025,7 @@ public function testChildContextKeepsOriginalContextCacheKey()
$foobar->bar = 'bar';
$foobar->baz = 'baz';
- $normalizer = new class() extends AbstractObjectNormalizerDummy {
+ $normalizer = new class extends AbstractObjectNormalizerDummy {
public $childContextCacheKey;
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
@@ -1060,7 +1060,7 @@ public function testChildContextCacheKeyStaysFalseWhenOriginalCacheKeyIsFalse()
$foobar->bar = 'bar';
$foobar->baz = 'baz';
- $normalizer = new class() extends AbstractObjectNormalizerDummy {
+ $normalizer = new class extends AbstractObjectNormalizerDummy {
public $childContextCacheKey;
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
@@ -1090,7 +1090,7 @@ protected function createChildContext(array $parentContext, string $attribute, ?
public function testDenormalizeXmlScalar()
{
- $normalizer = new class() extends AbstractObjectNormalizer {
+ $normalizer = new class extends AbstractObjectNormalizer {
public function __construct()
{
parent::__construct(null, new MetadataAwareNameConverter(new ClassMetadataFactory(new AttributeLoader())));
@@ -1249,7 +1249,7 @@ public static function provideDenormalizeWithFilterBoolData(): array
public function testDenormalizeArrayObject()
{
- $normalizer = new class() extends AbstractObjectNormalizerDummy {
+ $normalizer = new class extends AbstractObjectNormalizerDummy {
public function __construct()
{
parent::__construct(null, null, new PhpDocExtractor());
diff --git a/Tests/Normalizer/ConstraintViolationListNormalizerTest.php b/Tests/Normalizer/ConstraintViolationListNormalizerTest.php
index bb69392f5..1d0afb3cb 100644
--- a/Tests/Normalizer/ConstraintViolationListNormalizerTest.php
+++ b/Tests/Normalizer/ConstraintViolationListNormalizerTest.php
@@ -50,23 +50,23 @@ public function testNormalize()
'detail' => 'd: a
4: 1',
'violations' => [
- [
- 'propertyPath' => 'd',
- 'title' => 'a',
- 'template' => 'b',
- 'type' => 'urn:uuid:f',
- 'parameters' => [
- 'value' => 'foo',
- ],
- ],
- [
- 'propertyPath' => '4',
- 'title' => '1',
- 'template' => '2',
- 'type' => 'urn:uuid:6',
- 'parameters' => [],
+ [
+ 'propertyPath' => 'd',
+ 'title' => 'a',
+ 'template' => 'b',
+ 'type' => 'urn:uuid:f',
+ 'parameters' => [
+ 'value' => 'foo',
],
],
+ [
+ 'propertyPath' => '4',
+ 'title' => '1',
+ 'template' => '2',
+ 'type' => 'urn:uuid:6',
+ 'parameters' => [],
+ ],
+ ],
];
$this->assertEquals($expected, $this->normalizer->normalize($list));
diff --git a/Tests/Normalizer/DateTimeNormalizerTest.php b/Tests/Normalizer/DateTimeNormalizerTest.php
index 5dbf36fbe..81219652b 100644
--- a/Tests/Normalizer/DateTimeNormalizerTest.php
+++ b/Tests/Normalizer/DateTimeNormalizerTest.php
@@ -232,6 +232,8 @@ public function testSupportsDenormalization()
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeInterface::class));
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class));
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeImmutable::class));
+ $this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', DateTimeImmutableChild::class));
+ $this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', DateTimeChild::class));
$this->assertFalse($this->normalizer->supportsDenormalization('foo', 'Bar'));
}
@@ -241,6 +243,10 @@ public function testDenormalize()
$this->assertEquals(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeImmutable::class));
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize(' 2016-01-01T00:00:00+00:00 ', \DateTime::class));
+ $this->assertEquals(new DateTimeImmutableChild('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', DateTimeImmutableChild::class));
+ $this->assertEquals(new DateTimeImmutableChild('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', DateTimeImmutableChild::class));
+ $this->assertEquals(new DateTimeChild('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', DateTimeChild::class));
+ $this->assertEquals(new DateTimeChild('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize(' 2016-01-01T00:00:00+00:00 ', DateTimeChild::class));
$this->assertEquals(new \DateTimeImmutable('2023-05-06T17:35:34.000000+0000', new \DateTimeZone('UTC')), $this->normalizer->denormalize(1683394534, \DateTimeImmutable::class, null, [DateTimeNormalizer::FORMAT_KEY => 'U']));
$this->assertEquals(new \DateTimeImmutable('2023-05-06T17:35:34.123400+0000', new \DateTimeZone('UTC')), $this->normalizer->denormalize(1683394534.1234, \DateTimeImmutable::class, null, [DateTimeNormalizer::FORMAT_KEY => 'U.u']));
}
@@ -387,3 +393,11 @@ public function testDenormalizeFormatMismatchThrowsException()
$this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class, null, [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d|']);
}
}
+
+class DateTimeChild extends \DateTime
+{
+}
+
+class DateTimeImmutableChild extends \DateTimeImmutable
+{
+}
diff --git a/Tests/Normalizer/Features/CallbacksTestTrait.php b/Tests/Normalizer/Features/CallbacksTestTrait.php
index 09e2f8867..3a9191ae8 100644
--- a/Tests/Normalizer/Features/CallbacksTestTrait.php
+++ b/Tests/Normalizer/Features/CallbacksTestTrait.php
@@ -59,7 +59,7 @@ public function testNormalizeCallbacksWithNoConstructorArgument($callbacks, $val
{
$normalizer = $this->getNormalizerForCallbacksWithPropertyTypeExtractor();
- $obj = new class() extends CallbacksObject {
+ $obj = new class extends CallbacksObject {
public function __construct()
{
}
@@ -101,7 +101,7 @@ public function testDenormalizeCallbacksWithNoConstructorArgument($callbacks, $v
{
$normalizer = $this->getNormalizerForCallbacksWithPropertyTypeExtractor();
- $objWithNoConstructorArgument = new class() extends CallbacksObject {
+ $objWithNoConstructorArgument = new class extends CallbacksObject {
public function __construct()
{
}
diff --git a/Tests/Normalizer/Features/CircularReferenceTestTrait.php b/Tests/Normalizer/Features/CircularReferenceTestTrait.php
index d02e245f7..85720bcfe 100644
--- a/Tests/Normalizer/Features/CircularReferenceTestTrait.php
+++ b/Tests/Normalizer/Features/CircularReferenceTestTrait.php
@@ -42,7 +42,7 @@ public function testUnableToNormalizeCircularReference(array $defaultContext, ar
$obj = $this->getSelfReferencingModel();
$this->expectException(CircularReferenceException::class);
- $this->expectExceptionMessage(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d).', $obj::class, $expectedLimit));
+ $this->expectExceptionMessage(\sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d).', $obj::class, $expectedLimit));
$normalizer->normalize($obj, null, $context);
}
diff --git a/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php b/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php
index 72652f340..0a5f6f249 100644
--- a/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php
+++ b/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php
@@ -64,10 +64,10 @@ public function testConstructorWithMissingData()
$normalizer = $this->getDenormalizerForConstructArguments();
try {
$normalizer->denormalize($data, ConstructorArgumentsObject::class);
- self::fail(sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentsException::class));
+ self::fail(\sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentsException::class));
} catch (MissingConstructorArgumentsException $e) {
self::assertSame(ConstructorArgumentsObject::class, $e->getClass());
- self::assertSame(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$foo", "$baz".', ConstructorArgumentsObject::class), $e->getMessage());
+ self::assertSame(\sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$foo", "$baz".', ConstructorArgumentsObject::class), $e->getMessage());
self::assertSame(['foo', 'baz'], $e->getMissingConstructorArguments());
}
}
diff --git a/Tests/Normalizer/MapDenormalizationTest.php b/Tests/Normalizer/MapDenormalizationTest.php
index ea4515955..75ecbccb9 100644
--- a/Tests/Normalizer/MapDenormalizationTest.php
+++ b/Tests/Normalizer/MapDenormalizationTest.php
@@ -187,7 +187,7 @@ public function testNullableAbstractObject()
private function getSerializer()
{
- $loaderMock = new class() implements ClassMetadataFactoryInterface {
+ $loaderMock = new class implements ClassMetadataFactoryInterface {
public function getMetadataFor($value): ClassMetadataInterface
{
if (AbstractDummyValue::class === $value) {
diff --git a/Tests/Normalizer/ObjectNormalizerTest.php b/Tests/Normalizer/ObjectNormalizerTest.php
index 600fd7cd5..d45586b44 100644
--- a/Tests/Normalizer/ObjectNormalizerTest.php
+++ b/Tests/Normalizer/ObjectNormalizerTest.php
@@ -747,7 +747,7 @@ public function testDoesntHaveIssuesWithUnionConstTypes()
$normalizer = new ObjectNormalizer(null, null, null, $extractor);
$serializer = new Serializer([new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer]);
- $this->assertSame('bar', $serializer->denormalize(['foo' => 'bar'], (new class() {
+ $this->assertSame('bar', $serializer->denormalize(['foo' => 'bar'], (new class {
/** @var self::*|null */
public $foo;
})::class)->foo);
@@ -782,15 +782,15 @@ public function testDenormalizeFalsePseudoType()
public function testAdvancedNameConverter()
{
- $nameConverter = new class() implements AdvancedNameConverterInterface {
+ $nameConverter = new class implements AdvancedNameConverterInterface {
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']);
+ return \sprintf('%s-%s-%s-%s', $propertyName, $class, $format, $context['foo']);
}
public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string
{
- return sprintf('%s-%s-%s-%s', $propertyName, $class, $format, $context['foo']);
+ return \sprintf('%s-%s-%s-%s', $propertyName, $class, $format, $context['foo']);
}
};
@@ -976,7 +976,7 @@ public function testNormalizeWithMethodNamesSimilarToAccessors()
'tell' => true,
'class' => true,
'responsibility' => true,
- 123 => 321
+ 123 => 321,
], $normalized);
}
}
diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php
index 9ac85920e..ecdae436e 100644
--- a/Tests/Normalizer/PropertyNormalizerTest.php
+++ b/Tests/Normalizer/PropertyNormalizerTest.php
@@ -336,12 +336,16 @@ public function testGroupsDenormalizeWithNameConverter()
$this->assertEquals(
$obj,
- $this->normalizer->denormalize([
- 'bar' => null,
- 'foo_bar' => '@dunglas',
- 'symfony' => '@coopTilleuls',
- 'coop_tilleuls' => 'les-tilleuls.coop',
- ], GroupDummy::class, null, [PropertyNormalizer::GROUPS => ['name_converter']])
+ $this->normalizer->denormalize(
+ [
+ 'bar' => null,
+ 'foo_bar' => '@dunglas',
+ 'symfony' => '@coopTilleuls',
+ 'coop_tilleuls' => 'les-tilleuls.coop',
+ ],
+ GroupDummy::class, null,
+ [PropertyNormalizer::GROUPS => ['name_converter']]
+ )
);
}
@@ -401,13 +405,19 @@ public function testDenormalizeNonExistingAttribute()
{
$this->assertEquals(
new PropertyDummy(),
- $this->normalizer->denormalize(['non_existing' => true], PropertyDummy::class)
+ $this->normalizer->denormalize(
+ ['non_existing' => true],
+ PropertyDummy::class
+ )
);
}
public function testDenormalizeShouldIgnoreStaticProperty()
{
- $obj = $this->normalizer->denormalize(['outOfScope' => true], PropertyDummy::class);
+ $obj = $this->normalizer->denormalize(
+ ['outOfScope' => true],
+ PropertyDummy::class
+ );
$this->assertEquals(new PropertyDummy(), $obj);
$this->assertEquals('out_of_scope', PropertyDummy::$outOfScope);
@@ -446,7 +456,8 @@ public function testInheritedPropertiesSupport()
public function testMultiDimensionObject()
{
$normalizer = $this->getDenormalizerForTypeEnforcement();
- $root = $normalizer->denormalize([
+ $root = $normalizer->denormalize(
+ [
'children' => [[
['foo' => 'one', 'bar' => 'two'],
['foo' => 'three', 'bar' => 'four'],
@@ -463,7 +474,7 @@ public function testMultiDimensionObject()
RootDummy::class,
'any'
);
- $this->assertEquals($root::class, RootDummy::class);
+ $this->assertSame(RootDummy::class, $root::class);
// children (two dimension array)
$this->assertCount(1, $root->children);
@@ -531,7 +542,13 @@ public function testDenormalizeWithDiscriminator()
$denormalized = new PropertyDiscriminatedDummyTwo();
$denormalized->url = 'url';
- $this->assertEquals($denormalized, $normalizer->denormalize(['type' => 'two', 'url' => 'url'], PropertyDummyInterface::class));
+ $this->assertEquals(
+ $denormalized,
+ $normalizer->denormalize(
+ ['type' => 'two', 'url' => 'url'],
+ PropertyDummyInterface::class
+ )
+ );
}
}
diff --git a/Tests/Normalizer/UidNormalizerTest.php b/Tests/Normalizer/UidNormalizerTest.php
index 1471074a0..734b15b48 100644
--- a/Tests/Normalizer/UidNormalizerTest.php
+++ b/Tests/Normalizer/UidNormalizerTest.php
@@ -47,8 +47,8 @@ public static function normalizeProvider()
{
$uidFormats = [null, 'canonical', 'base58', 'base32', 'rfc4122'];
$data = [
- [
- UuidV1::fromString('9b7541de-6f87-11ea-ab3c-9da9a81562fc'),
+ [
+ UuidV1::fromString('9b7541de-6f87-11ea-ab3c-9da9a81562fc'),
'9b7541de-6f87-11ea-ab3c-9da9a81562fc',
'9b7541de-6f87-11ea-ab3c-9da9a81562fc',
'LCQS8f2p5SDSiAt9V7ZYnF',
diff --git a/Tests/SerializerTest.php b/Tests/SerializerTest.php
index 0a0622576..8fd0ff885 100644
--- a/Tests/SerializerTest.php
+++ b/Tests/SerializerTest.php
@@ -65,7 +65,6 @@
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumProperty;
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrNull;
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithVariadicParameter;
-use Symfony\Component\Serializer\Tests\Fixtures\DummyWithVariadicProperty;
use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy;
use Symfony\Component\Serializer\Tests\Fixtures\FooImplementationDummy;
use Symfony\Component\Serializer\Tests\Fixtures\FooInterfaceDummyDenormalizer;
@@ -428,7 +427,7 @@ public function testDeserializeAndSerializeAbstractObjectsWithTheClassMetadataDi
$example = new AbstractDummyFirstChild('foo-value', 'bar-value');
$example->setQuux(new DummyFirstChildQuux('quux'));
- $loaderMock = new class() implements ClassMetadataFactoryInterface {
+ $loaderMock = new class implements ClassMetadataFactoryInterface {
public function getMetadataFor($value): ClassMetadataInterface
{
if (AbstractDummy::class === $value) {
@@ -609,10 +608,10 @@ public static function provideObjectOrCollectionTests()
$data['c2'] = new \ArrayObject(['nested' => new \ArrayObject(['k' => 'v'])]);
$data['d1'] = new \ArrayObject(['nested' => []]);
$data['d2'] = new \ArrayObject(['nested' => ['k' => 'v']]);
- $data['e1'] = new class() {
+ $data['e1'] = new class {
public $map = [];
};
- $data['e2'] = new class() {
+ $data['e2'] = new class {
public $map = ['k' => 'v'];
};
$data['f1'] = new class(new \ArrayObject()) {
@@ -1216,7 +1215,7 @@ public function testCollectDenormalizationErrors2(?ClassMetadataFactory $classMe
'useMessageForUser' => false,
'message' => 'The type of the "string" attribute for class "Symfony\\Component\\Serializer\\Tests\\Fixtures\\Php74Full" must be one of "string" ("null" given).',
],
- ];
+ ];
$this->assertSame($expected, $exceptionsAsArray);
}
@@ -1466,8 +1465,8 @@ public function testCollectDenormalizationErrorsWithWrongPropertyWithoutConstruc
try {
$serializer->deserialize('{"get": "POST"}', DummyObjectWithEnumProperty::class, 'json', [
- DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
- ]);
+ DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
+ ]);
} catch (\Throwable $e) {
$this->assertInstanceOf(PartialDenormalizationException::class, $e);
}
diff --git a/composer.json b/composer.json
index d7bef296b..d8809fa07 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
"symfony/cache": "^6.4|^7.0",
"symfony/config": "^6.4|^7.0",
"symfony/console": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/dependency-injection": "^7.2",
"symfony/error-handler": "^6.4|^7.0",
"symfony/filesystem": "^6.4|^7.0",
"symfony/form": "^6.4|^7.0",
@@ -38,7 +38,7 @@
"symfony/property-access": "^6.4|^7.0",
"symfony/property-info": "^6.4|^7.0",
"symfony/translation-contracts": "^2.5|^3",
- "symfony/type-info": "^7.1.5",
+ "symfony/type-info": "^7.1",
"symfony/uid": "^6.4|^7.0",
"symfony/validator": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0",
@@ -51,7 +51,6 @@
"symfony/dependency-injection": "<6.4",
"symfony/property-access": "<6.4",
"symfony/property-info": "<6.4",
- "symfony/type-info": "<7.1.5",
"symfony/uid": "<6.4",
"symfony/validator": "<6.4",
"symfony/yaml": "<6.4"