8000 Add COLLECT_EXTRA_ATTRIBUTES_ERRORS and full deserialization path · symfony/symfony@a202da2 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit a202da2

Browse files
committed
Add COLLECT_EXTRA_ATTRIBUTES_ERRORS and full deserialization path
1 parent c2af1fd commit a202da2

18 files changed

+498
-103
lines changed

UPGRADE-6.2.md

Lines changed: 65 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,99 @@
1-
UPGRADE FROM 6.1 to 6.2
2-
=======================
1+
# UPGRADE FROM 6.1 to 6.2
32

4-
Config
5-
------
3+
## Config
64

7-
* Deprecate calling `NodeBuilder::setParent()` without any arguments
5+
- Deprecate calling `NodeBuilder::setParent()` without any arguments
86

9-
Console
10-
-------
7+
## Console
118

12-
* Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments
13-
* Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)`
14-
* Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)`
9+
- Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments
10+
- Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)`
11+
- Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)`
1512

16-
DependencyInjection
17-
-------------------
13+
## DependencyInjection
1814

19-
* Change the signature of `ContainerAwareInterface::setContainer()` to `setContainer(?ContainerInterface)`
20-
* Deprecate calling `ContainerAwareTrait::setContainer()` without arguments
21-
* Deprecate using numeric parameter names
15+
- Change the signature of `ContainerAwareInterface::setContainer()` to `setContainer(?ContainerInterface)`
16+
- Deprecate calling `ContainerAwareTrait::setContainer()` without arguments
17+
- Deprecate using numeric parameter names
2218

23-
Form
24-
----
19+
## Form
2520

26-
* Deprecate calling `Button/Form::setParent()`, `ButtonBuilder/FormConfigBuilder::setDataMapper()`, `TransformationFailedException::setInvalidMessage()` without arguments
27-
* Change the signature of `FormConfigBuilderInterface::setDataMapper()` to `setDataMapper(?DataMapperInterface)`
28-
* Change the signature of `FormInterface::setParent()` to `setParent(?self)`
21+
- Deprecate calling `Button/Form::setParent()`, `ButtonBuilder/FormConfigBuilder::setDataMapper()`, `TransformationFailedException::setInvalidMessage()` without arguments
22+
- Change the signature of `FormConfigBuilderInterface::setDataMapper()` to `setDataMapper(?DataMapperInterface)`
23+
- Change the signature of `FormInterface::setParent()` to `setParent(?self)`
2924

30-
FrameworkBundle
31-
---------------
25+
## FrameworkBundle
3226

33-
* Deprecate the `Symfony\Component\Serializer\Normalizer\ObjectNormalizer` and
34-
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` autowiring aliases, type-hint against
35-
`Symfony\Component\Serializer\Normalizer\NormalizerInterface` or implement `NormalizerAwareInterface` instead
36-
* Deprecate `AbstractController::renderForm()`, use `render()` instead
27+
- Deprecate the `Symfony\Component\Serializer\Normalizer\ObjectNormalizer` and
28+
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` autowiring aliases, type-hint against
29+
`Symfony\Component\Serializer\Normalizer\NormalizerInterface` or implement `NormalizerAwareInterface` instead
30+
- Deprecate `AbstractController::renderForm()`, use `render()` instead
3731

38-
HttpFoundation
39-
--------------
32+
## HttpFoundation
4033

41-
* Deprecate `Request::getContentType()`, use `Request::getContentTypeFormat()` instead
42-
* Deprecate calling `JsonResponse::setCallback()`, `Response::setExpires/setLastModified/setEtag()`, `MockArraySessionStorage/NativeSessionStorage::setMetadataBag()`, `NativeSessionStorage::setSaveHandler()` without arguments
34+
- Deprecate `Request::getContentType()`, use `Request::getContentTypeFormat()` instead
35+
- Deprecate calling `JsonResponse::setCallback()`, `Response::setExpires/setLastModified/setEtag()`, `MockArraySessionStorage/NativeSessionStorage::setMetadataBag()`, `NativeSessionStorage::setSaveHandler()` without arguments
4336

44-
HttpKernel
45-
----------
37+
## HttpKernel
4638

47-
* Deprecate `ArgumentValueResolverInterface`, use `ValueResolverInterface` instead
48-
* Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments
39+
- Deprecate `ArgumentValueResolverInterface`, use `ValueResolverInterface` instead
40+
- Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments
4941

50-
Ldap
51-
----
42+
## Ldap
5243

53-
* Deprecate `{username}` parameter use in favour of `{user_identifier}`
44+
- Deprecate `{username}` parameter use in favour of `{user_identifier}`
5445

55-
Mailer
56-
------
46+
## Mailer
5747

58-
* Deprecate the `OhMySMTP` transport, use `MailPace` instead
48+
- Deprecate the `OhMySMTP` transport, use `MailPace` instead
5949

60-
Mime
61-
----
50+
## Mime
6251

63-
* Deprecate calling `Message::setBody()` without arguments
52+
- Deprecate calling `Message::setBody()` without arguments
6453

65-
PropertyAccess
66-
--------------
54+
## PropertyAccess
6755

68-
* Deprecate calling `PropertyAccessorBuilder::setCacheItemPool()` without arguments
69-
* Implementing the `PropertyPathInterface` without implementing the `isNullSafe()` method is deprecated
56+
- Deprecate calling `PropertyAccessorBuilder::setCacheItemPool()` without arguments
57+
- Implementing the `PropertyPathInterface` without implementing the `isNullSafe()` method is deprecated
7058

71-
Messenger
72-
--------
59+
## Messenger
7360

74-
* Deprecate `MessageHandlerInterface` and `MessageSubscriberInterface`, use the `AsMessageHandler` attribute instead
61+
- Deprecate `MessageHandlerInterface` and `MessageSubscriberInterface`, use the `AsMessageHandler` attribute instead
7562

76-
Security
77-
--------
63+
## Security
7864

79-
* Add maximum username length enforcement of 4096 characters in `UserBadge` to
80-
prevent [session storage flooding](https://symfony.com/blog/cve-2016-4423-large-username-storage-in-session)
81-
* Deprecate the `Symfony\Component\Security\Core\Security` class and service, use `Symfony\Bundle\SecurityBundle\Security\Security` instead
82-
* Passing empty username or password parameter when using `JsonLoginAuthenticator` is not supported anymore
83-
* Add `$lifetime` parameter to `LoginLinkHandlerInterface::createLoginLink()`
84-
* Change the signature of `TokenStorageInterface::setToken()` to `setToken(?TokenInterface $token)`
85-
* Deprecate calling `TokenStorage::setToken()` or `UsageTrackingTokenStorage::setToken()` without arguments
65+
- Add maximum username length enforcement of 4096 characters in `UserBadge` to
66+
prevent [session storage flooding](https://symfony.com/blog/cve-2016-4423-large-username-storage-in-session)
8667

87-
Serializer
88-
----------
68+
## Serializer
8969

90-
* Deprecate calling `AttributeMetadata::setSerializedName()`, `ClassMetadata::setClassDiscriminatorMapping()` without arguments
91-
* Change the signature of `AttributeMetadataInterface::setSerializedName()` to `setSerializedName(?string)`
92-
* Change the signature of `ClassMetadataInterface::setClassDiscriminatorMapping()` to `setClassDiscriminatorMapping(?ClassDiscriminatorMapping)`
70+
- Deprecate the `Symfony\Component\Security\Core\Security` class and service, use `Symfony\Bundle\SecurityBundle\Security\Security` instead
71+
- Passing empty username or password parameter when using `JsonLoginAuthenticator` is not supported anymore
72+
- Add `$lifetime` parameter to `LoginLinkHandlerInterface::createLoginLink()`
73+
- Change the signature of `TokenStorageInterface::setToken()` to `setToken(?TokenInterface $token)`
74+
- Deprecate calling `TokenStorage::setToken()` or `UsageTrackingTokenStorage::setToken()` without arguments
9375

94-
Validator
95-
---------
76+
## Serializer
9677

97-
* Deprecate the `loose` e-mail validation mode, use `html5` instead
78+
- Deprecate calling `AttributeMetadata::setSerializedName()`, `ClassMetadata::setClassDiscriminatorMapping()` without arguments
79+
- Change the signature of `AttributeMetadataInterface::setSerializedName()` to `setSerializedName(?string)`
80+
- Change the signature of `ClassMetadataInterface::setClassDiscriminatorMapping()` to `setClassDiscriminatorMapping(?ClassDiscriminatorMapping)`
81+
- Deprecate `PartialDenormalizationException::getErrors()`, call `getNotNormalizableValueErrors()` instead
9882

99-
VarDumper
100-
---------
83+
## Validator
10184

102-
* Deprecate calling `VarDumper::setHandler()` without arguments
85+
- Deprecate the `loose` e-mail validation mode, use `html5` instead
10386

104-
Workflow
105-
--------
87+
## VarDumper
10688

107-
* The `Registry` is marked as internal and should not be used directly. use a tagged locator instead
108-
```
109-
tagged_locator('workflow', 'name')
110-
```
111-
* The first argument of `WorkflowDumpCommand` should be a `ServiceLocator` of
112-
all workflows indexed by names
113-
* Deprecate calling `Definition::setInitialPlaces()` without arguments
89+
- Deprecate calling `VarDumper::setHandler()` without arguments
90+
91+
## Workflow
92+
93+
- The `Registry` is marked as internal and should not be used directly. use a tagged locator instead
94+
```
95+
tagged_locator('workflow', 'name')
96+
```
97+
- The first argument of `WorkflowDumpCommand` should be a `ServiceLocator` of
98+
all workflows indexed by names
99+
- Deprecate calling `Definition::setInitialPlaces()` without arguments

src/Symfony/Component/Console/Helper/Table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public function setHeaders(array $headers): static
192192
/**
193193
* @return $this
194194
*/
195-
public function setRows(array $rows)
195+
public function setRows(array $rows): static
196196
{
197197
$this->rows = [];
198198

src/Symfony/Component/PropertyAccess/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Deprecate calling `PropertyAccessorBuilder::setCacheItemPool()` without arguments
88
* Added method `isNullSafe()` to `PropertyPathInterface`
9+
* Add `Symfony\Component\PropertyAccess\PropertyPath::append()`
910

1011
6.0
1112
---

src/Symfony/Component/PropertyAccess/PropertyPath.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,29 @@ public function isNullSafe(int $index): bool
203203

204204
return $this->isNullSafe[$index];
205205
}
206+
207+
/**
208+
* Utility method for dealing with property paths.
209+
* For more extensive functionality, use instances of this class.
210+
*
211+
* Appends a path to a given property path.
212+
*
213+
* If the base path is empty, the appended path will be returned unchanged.
214+
* If the base path is not empty, and the appended path starts with a
215+
* squared opening bracket ("["), the concatenation of the two paths is
216+
* returned. Otherwise, the concatenation of the two paths is returned,
217+
* separated by a dot (".").
218+
*/
219+
public static function append(string $basePath, string $subPath): string
220+
{
221+
if ('' !== $subPath) {
222+
if ('[' === $subPath[0]) {
223+
return $basePath.$subPath;
224+
}
225+
226+
return '' !== $basePath ? $basePath.'.'.$subPath : $subPath;
227+
}
228+
229+
return $basePath;
230+
}
206231
}

src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,24 @@ public function testIsIndexDoesNotAcceptNegativeIndices()
170170

171171
$propertyPath->isIndex(-1);
172172
}
173+
174+
/**
175+
* @dataProvider provideAppendPaths
176+
*/
177+
public function testAppend($basePath, $subPath, $expectedPath, $message)
178+
{
179+
$this->assertSame($expectedPath, PropertyPath::append($basePath, $subPath), $message);
180+
}
181+
182+
public function provideAppendPaths()
183+
{
184+
return [
185+
['foo', '', 'foo', 'It returns the basePath if subPath is empty'],
186+
['', 'bar', 'bar', 'It returns the subPath if basePath is empty'],
187+
['foo', 'bar', 'foo.bar', 'It append the subPath to the basePath'],
188+
['foo', '[bar]', 'foo[bar]', 'It does not include the dot separator if subPath uses the array notation'],
189+
['0', 'bar', '0.bar', 'Leading zeros are kept.'],
190+
['0', 1, '0.1', 'Numeric subpaths do not cause PHP 7.4 errors.'],
191+
];
192+
}
173193
}

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CHANGELOG
1111
* Change the signature of `AttributeMetadataInterface::setSerializedName()` to `setSerializedName(?string)`
1212
* Change the signature of `ClassMetadataInterface::setClassDiscriminatorMapping()` to `setClassDiscriminatorMapping(?ClassDiscriminatorMapping)`
1313
* Add option YamlEncoder::YAML_INDENTATION to YamlEncoder constructor options to configure additional indentation for each level of nesting. This allows configuring indentation in the service configuration.
14+
* Add `COLLECT_EXTRA_ATTRIBUTES_ERRORS` option to `Serializer` to collect errors from nested denormalizations
15+
* Deprecate `PartialDenormalizationException::getErrors()`, call `getNotNormalizableValueErrors()` instead
1416

1517
6.1
1618
---

src/Symfony/Component/Serializer/Context/SerializerContextBuilder.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Serializer\Context;
1313

14+
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
1415
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
1516
use Symfony\Component\Serializer\Serializer;
1617

@@ -36,4 +37,9 @@ public function withCollectDenormalizationErrors(?bool $collectDenormalizationEr
3637
{
3738
return $this->with(DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS, $collectDenormalizationErrors);
3839
}
40+
41+
public function withCollectExtraAttributesErrors(?bool $collectExtraAttributesErrors): static
42+
{
43+
return $this->with(DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS, $collectExtraAttributesErrors);
44+
}
3945
}

src/Symfony/Component/Serializer/Exception/PartialDenormalizationException.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,45 @@
1717
class PartialDenormalizationException extends UnexpectedValueException
1818
{
1919
private $data;
20-
private $errors;
20+
/**
21+
* @var NotNormalizableValueException[]
22+
*/
23+
private array $notNormalizableErrors;
24+
private ?ExtraAttributesException $extraAttributesError = null;
2125

22-
public function __construct($data, array $errors)
26+
public function __construct($data, array $notNormalizableErrors, array $extraAttributesErrors = [])
2327
{
2428
$this->data = $data;
25-
$this->errors = $errors;
29+
$this->notNormalizableErrors = $notNormalizableErrors;
30+
$extraAttributes = [];
31+
foreach ($extraAttributesErrors as $error) {
32+
\array_push($extraAttributes, ...$error->getExtraAttributes());
33+
}
34+
if (\count($extraAttributes) > 0) {
35+
$this->extraAttributesError = new ExtraAttributesException($extraAttributes);
36+
}
2637
}
2738

2839
public function getData()
2940
{
3041
return $this->data;
3142
}
3243

44+
/**
45+
* @deprecated Use getNotNormalizableValueErrors() instead.
46+
*/
3347
public function getErrors(): array
3448
{
35-
return $this->errors;
49+
return $this->getNotNormalizableValueErrors();
50+
}
51+
52+
public function getNotNormalizableValueErrors(): array
53+
{
54+
return $this->notNormalizableErrors;
55+
}
56+
57+
public function getExtraAttributesError(): ?ExtraAttributesException
58+
{
59+
return $this->extraAttributesError;
3660
}
3761
}

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2323
use Symfony\Component\Serializer\SerializerAwareInterface;
2424
use Symfony\Component\Serializer\SerializerAwareTrait;
25+
use Symfony\Component\Serializer\Util\PropertyPath;
2526

2627
/**
2728
* Normalizer implementation.
@@ -505,7 +506,7 @@ protected function getAttributeNormalizationContext(object $object, string $attr
505506
*/
506507
protected function getAttributeDenormalizationContext(string $class, string $attribute, array $context): array
507508
{
508-
$context['deserialization_path'] = ($context['deserialization_path'] ?? false) ? $context['deserialization_path'].'.'.$attribute : $attribute;
509+
$context['deserialization_path'] = PropertyPath::append($context['deserialization_path'] ?? '', $attribute);
509510

510511
if (null === $metadata = $this->getAttributeMetadata($class, $attribute)) {
511512
return $context;

0 commit comments

Comments
 (0)