Skip to content

Commit ee91124

Browse files
committed
deprecate handling options in the base Constraint class
1 parent c83c34e commit ee91124

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+673
-179
lines changed

UPGRADE-7.4.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,130 @@ Security
3939
* Deprecate callable firewall listeners, extend `AbstractListener` or implement `FirewallListenerInterface` instead
4040
* Deprecate `AbstractListener::__invoke`
4141
* Deprecate `LazyFirewallContext::__invoke()`
42+
43+
Validator
44+
---------
45+
46+
* Deprecate evaluating options in the base `Constraint` class. Initialize properties in the constructor of the concrete constraint
47+
class instead.
48+
49+
*Before*
50+
51+
```php
52+
class CustomConstraint extends Constraint
53+
{
54+
public $option1;
55+
public $option2;
56+
57+
public function __construct(?array $options = null)
58+
{
59+
parent::__construct($options);
60+
}
61+
}
62+
```
63+
64+
*After*
65+
66+
```php
67+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
68+
69+
class CustomConstraint extends Constraint
70+
{
71+
public $option1;
72+
public $option2;
73+
74+
#[HasNamedArguments]
75+
public function __construct($option1 = null, $option2 = null, ?array $groups = null, mixed $payload = null)
76+
{
77+
parent::__construct(null, $groups, $payload);
78+
79+
$this->option1 = $option1;
80+
$this->option2 = $option2;
81+
}
82+
}
83+
```
84+
85+
* Deprecate the `getRequiredOptions()` method of the base `Constraint` class. Use mandatory constructor arguments instead.
86+
87+
*Before*
88+
89+
```php
90+
class CustomConstraint extends Constraint
91+
{
92+
public $option1;
93+
public $option2;
94+
95+
public function __construct(?array $options = null)
96+
{
97+
parent::__construct($options);
98+
}
99+
100+
public function getRequiredOptions()
101+
{
102+
return ['option1'];
103+
}
104+
}
105+
```
106+
107+
*After*
108+
109+
```php
110+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
111+
112+
class CustomConstraint extends Constraint
113+
{
114+
public $option1;
115+
public $option2;
116+
117+
#[HasNamedArguments]
118+
public function __construct($option1, $option2 = null, ?array $groups = null, mixed $payload = null)
119+
{
120+
parent::__construct(null, $groups, $payload);
121+
122+
$this->option1 = $option1;
123+
$this->option2 = $option2;
124+
}
125+
}
126+
```
127+
* Deprecate the `normalizeOptions()` and `getDefaultOption()` methods of the base `Constraint` class without replacements.
128+
Overriding them in child constraint will not have any effects starting with Symfony 8.0.
129+
* Deprecate passing an array of options to the `Composite` constraint class. Initialize the properties referenced with `getNestedConstraints()`
130+
in child classes before calling the constructor of `Composite`.
131+
132+
*Before*
133+
134+
```php
135+
class CustomCompositeConstraint extends Composite
136+
{
137+
public array $constraints = [];
138+
139+
public function __construct(?array $options = null)
140+
{
141+
parent::__construct($options);
142+
}
143+
144+
protected function getCompositeOption(): string
145+
{
146+
return 'constraints';
147+
}
148+
}
149+
```
150+
151+
*After*
152+
153+
```php
154+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
155+
156+
class CustomCompositeConstraint extends Composite
157+
{
158+
public array $constraints = [];
159+
160+
#[HasNamedArguments]
161+
public function __construct(array $constraints, ?array $groups = null, mixed $payload = null)
162+
{
163+
$this->constraints = $constraints;
164+
165+
parent::__construct(null, $groups, $payload);
166+
}
167+
}
168+
```

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,21 @@ public function __construct(
6666
trigger_deprecation('symfony/validator', '7.3', 'Passing an array of options to configure the "%s" constraint is deprecated, use named arguments instead.', static::class);
6767

6868
$options = array_merge($fields, $options ?? []);
69+
$fields = null;
6970
} else {
7071
if (\is_array($options)) {
7172
trigger_deprecation('symfony/validator', '7.3', 'Passing an array of options to configure the "%s" constraint is deprecated, use named arguments instead.', static::class);
73+
74+
$options['fields'] = $fields;
75+
$fields = null;
7276
} else {
73-
$options = [];
77+
$options = null;
7478
}
75-
76-
$options['fields'] = $fields;
7779
}
7880

7981
parent::__construct($options, $groups, $payload);
8082

83+
$this->fields = $fields ?? $this->fields;
8184
$this->message = $message ?? $this->message;
8285
$this->service = $service ?? $this->service;
8386
$this->em = $em ?? $this->em;

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"symfony/translation": "^6.4|^7.0|^8.0",
4242
"symfony/type-info": "^7.1|^8.0",
4343
"symfony/uid": "^6.4|^7.0|^8.0",
44-
"symfony/validator": "^6.4|^7.0|^8.0",
44+
"symfony/validator": "^7.4|^8.0",
4545
"symfony/var-dumper": "^6.4|^7.0|^8.0",
4646
"doctrine/collections": "^1.8|^2.0",
4747
"doctrine/data-fixtures": "^1.1|^2",
@@ -64,7 +64,7 @@
6464
"symfony/property-info": "<6.4",
6565
"symfony/security-bundle": "<6.4",
6666
"symfony/security-core": "<6.4",
67-
"symfony/validator": "<6.4"
67+
"symfony/validator": "<7.4"
6868
},
6969
"autoload": {
7070
"psr-4": { "Symfony\\Bridge\\Doctrine\\": "" },

src/Symfony/Component/Security/Core/Tests/Validator/Constraints/UserPasswordTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ public function testValidatedByService(UserPassword $constraint)
3535

3636
public static function provideServiceValidatedConstraints(): iterable
3737
{
38-
yield 'Doctrine style' => [new UserPassword(['service' => 'my_service'])];
39-
4038
yield 'named arguments' => [new UserPassword(service: 'my_service')];
4139

4240
$metadata = new ClassMetadata(UserPasswordDummy::class);
@@ -45,6 +43,14 @@ public static function provideServiceValidatedConstraints(): iterable
4543
yield 'attribute' => [$metadata->properties['b']->constraints[0]];
4644
}
4745

46+
/**
47+
* @group legacy
48+
*/
49+
public function testValidatedByServiceDoctrineStyle()
50+
{
51+
self::assertSame('my_service', (new UserPassword(['service' => 'my_service']))->validatedBy());
52+
}
53+
4854
public function testAttributes()
4955
{
5056
$metadata = new ClassMetadata(UserPasswordDummy::class);

src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,133 @@
11
CHANGELOG
22
=========
33

4+
7.4
5+
---
6+
7+
* Deprecate evaluating options in the base `Constraint` class. Initialize properties in the constructor of the concrete constraint
8+
class instead.
9+
10+
Before:
11+
12+
```php
13+
class CustomConstraint extends Constraint
14+
{
15+
public $option1;
16+
public $option2;
17+
18+
public function __construct(?array $options = null)
19+
{
20+
parent::__construct($options);
21+
}
22+
}
23+
```
24+
25+
After:
26+
27+
```php
28+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
29+
30+
class CustomConstraint extends Constraint
31+
{
32+
public $option1;
33+
public $option2;
34+
35+
#[HasNamedArguments]
36+
public function __construct($option1 = null, $option2 = null, ?array $groups = null, mixed $payload = null)
37+
{
38+
parent::__construct(null, $groups, $payload);
39+
40+
$this->option1 = $option1;
41+
$this->option2 = $option2;
42+
}
43+
}
44+
```
45+
46+
* Deprecate the `getRequiredOptions()` method of the base `Constraint` class. Use mandatory constructor arguments instead.
47+
48+
Before:
49+
50+
```php
51+
class CustomConstraint extends Constraint
52+
{
53+
public $option1;
54+
public $option2;
55+
56+
public function __construct(?array $options = null)
57+
{
58+
parent::__construct($options);
59+
}
60+
61+
public function getRequiredOptions()
62+
{
63+
return ['option1'];
64+
}
65+
}
66+
```
67+
68+
After:
69+
70+
```php
71+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
72+
73+
class CustomConstraint extends Constraint
74+
{
75+
public $option1;
76+
public $option2;
77+
78+
#[HasNamedArguments]
79+
public function __construct($option1, $option2 = null, ?array $groups = null, mixed $payload = null)
80+
{
81+
parent::__construct(null, $groups, $payload);
82+
83+
$this->option1 = $option1;
84+
$this->option2 = $option2;
85+
}
86+
}
87+
```
88+
* Deprecate the `normalizeOptions()` and `getDefaultOption()` methods of the base `Constraint` class without replacements.
89+
Overriding them in child constraint will not have any effects starting with Symfony 8.0.
90+
* Deprecate passing an array of options to the `Composite` constraint class. Initialize the properties referenced with `getNestedConstraints()`
91+
in child classes before calling the constructor of `Composite`.
92+
93+
Before:
94+
95+
```php
96+
class CustomCompositeConstraint extends Composite
97+
{
98+
public array $constraints = [];
99+
100+
public function __construct(?array $options = null)
101+
{
102+
parent::__construct($options);
103+
}
104+
105+
protected function getCompositeOption(): string
106+
{
107+
return 'constraints';
108+
}
109+
}
110+
```
111+
112+
After:
113+
114+
```php
115+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
116+
117+
class CustomCompositeConstraint extends Composite
118+
{
119+
public array $constraints = [];
120+
121+
#[HasNamedArguments]
122+
public function __construct(array $constraints, ?array $groups = null, mixed $payload = null)
123+
{
124+
$this->constraints = $constraints;
125+
126+
parent::__construct(null, $groups, $payload);
127+
}
128+
}
129+
```
130+
4131
7.3
5132
---
6133

src/Symfony/Component/Validator/Constraint.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ public function __construct(mixed $options = null, ?array $groups = null, mixed
110110
{
111111
unset($this->groups); // enable lazy initialization
112112

113+
if (null === $options && (\func_num_args() > 0 || (new \ReflectionMethod($this, 'getRequiredOptions'))->getDeclaringClass()->getName() === self::class)) {
114+
if (null !== $groups) {
115+
$this->groups = $groups;
116+
}
117+
$this->payload = $payload;
118+
119+
return;
120+
}
121+
122+
trigger_deprecation('symfony/validator', '7.4', 'Support for evaluating options in the base Constraint class is deprecated. Initialize properties in the constructor of %s instead.', static::class);
123+
113124
$options = $this->normalizeOptions($options);
114125
if (null !== $groups) {
115126
$options['groups'] = $groups;
@@ -122,6 +133,8 @@ public function __construct(mixed $options = null, ?array $groups = null, mixed
122133
}
123134

124135
/**
136+
* @deprecated since Symfony 7.4
137+
*
125138
* @return array<string, mixed>
126139
*/
127140
protected function normalizeOptions(mixed $options): array
@@ -241,6 +254,8 @@ public function addImplicitGroupName(string $group): void
241254
*
242255
* Override this method to define a default option.
243256
*
257+
* @deprecated since Symfony 7.4
258+
*
244259
* @see __construct()
245260
*/
246261
public function getDefaultOption(): ?string
@@ -255,6 +270,8 @@ public function getDefaultOption(): ?string
255270
*
256271
* @return string[]
257272
*
273+
* @deprecated since Symfony 7.4
274+
*
258275
* @see __construct()
259276
*/
260277
public function getRequiredOptions(): array

0 commit comments

Comments
 (0)