Skip to content

[Validator] deprecate passing choices as $options argument to Choice constraint #61255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
deprecate passing choices as $options argument to Choice constraint
  • Loading branch information
xabbuh authored and nicolas-grekas committed Jul 29, 2025
commit 08678a45e750f8e39d7f50d8b7c6a0229e2be3b6
11 changes: 6 additions & 5 deletions UPGRADE-7.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ Translation
Validator
---------

* Deprecate passing a list of choices to the first argument of the `Choice` constraint. Use the `choices` option instead
* Deprecate `getRequiredOptions()` and `getDefaultOption()` methods of the `All`, `AtLeastOneOf`, `CardScheme`, `Collection`,
`CssColor`, `Expression`, `Regex`, `Sequentially`, `Type`, and `When` constraints
* Deprecate evaluating options in the base `Constraint` class. Initialize properties in the constructor of the concrete constraint
class instead.
class instead

*Before*

Expand Down Expand Up @@ -97,7 +98,7 @@ Validator
}
```

* Deprecate the `getRequiredOptions()` method of the base `Constraint` class. Use mandatory constructor arguments instead.
* Deprecate the `getRequiredOptions()` method of the base `Constraint` class. Use mandatory constructor arguments instead

*Before*

Expand Down Expand Up @@ -137,10 +138,10 @@ Validator
}
}
```
* Deprecate the `normalizeOptions()` and `getDefaultOption()` methods of the base `Constraint` class without replacements.
Overriding them in child constraint will not have any effects starting with Symfony 8.0.
* Deprecate the `normalizeOptions()` and `getDefaultOption()` methods of the base `Constraint` class without replacements;
overriding them in child constraint will not have any effects starting with Symfony 8.0
* Deprecate passing an array of options to the `Composite` constraint class. Initialize the properties referenced with `getNestedConstraints()`
in child classes before calling the constructor of `Composite`.
in child classes before calling the constructor of `Composite`

*Before*

Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
7.4
---

* Deprecate passing a list of choices to the first argument of the `Choice` constraint. Use the `choices` option instead
* Add the `min` and `max` parameter to the `Length` constraint violation
* Deprecate `getRequiredOptions()` and `getDefaultOption()` methods of the `All`, `AtLeastOneOf`, `CardScheme`, `Collection`,
`CssColor`, `Expression`, `Regex`, `Sequentially`, `Type`, and `When` constraints
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Validator/Constraints/Choice.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public function __construct(
?bool $match = null,
) {
if (\is_array($options) && $options && array_is_list($options)) {
trigger_deprecation('symfony/validator', '7.4', 'Support for passing the choices as the first argument to %s is deprecated.', static::class);
$choices ??= $options;
$options = null;
} elseif (\is_array($options) && [] !== $options) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ public function testValidateNestedAtLeaseOneOfConstraints()
new Collection([
'bar' => new AtLeastOneOf([
new Type('int'),
new Choice(['test1', 'test2']),
new Choice(choices: ['test1', 'test2']),
]),
]),
new Collection([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ChoiceDummy
#[Choice(choices: ['foo', 'bar'], message: 'myMessage')]
private $b;

#[Choice([1, 2], groups: ['my_group'], payload: 'some attached data')]
#[Choice(choices: [1, 2], groups: ['my_group'], payload: 'some attached data')]
private $c;

#[Choice(choices: ['one' => 1, 'two' => 2])]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,21 @@ public function testValidCallbackExpected()
$this->validator->validate('foobar', new Choice(callback: 'abcd'));
}

/**
* @dataProvider provideConstraintsWithChoicesArray
*/
public function testValidChoiceArray(Choice $constraint)
public function testValidChoiceArray()
{
$this->validator->validate('bar', $constraint);
$this->validator->validate('bar', new Choice(choices: ['foo', 'bar']));

$this->assertNoViolation();
}

public static function provideConstraintsWithChoicesArray(): iterable
/**
* @group legacy
*/
public function testValidChoiceArrayFirstArgument()
{
yield 'first argument' => [new Choice(['foo', 'bar'])];
yield 'named arguments' => [new Choice(choices: ['foo', 'bar'])];
$this->validator->validate('bar', new Choice(['foo', 'bar']));

$this->assertNoViolation();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\Constraints\Type;
use Symfony\Component\Validator\Exception\MappingException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader;
Expand Down Expand Up @@ -76,8 +77,6 @@ public function testLoadClassMetadata()
$expected->addConstraint(new ConstraintWithNamedArguments(['foo', 'bar']));
$expected->addConstraint(new ConstraintWithoutValueWithNamedArguments(['foo']));
$expected->addPropertyConstraint('firstName', new NotNull());
$expected->addPropertyConstraint('firstName', new Range(min: 3));
$expected->addPropertyConstraint('firstName', new Choice(['A', 'B']));
$expected->addPropertyConstraint('firstName', new All(constraints: [new NotNull(), new Range(min: 3)]));
$expected->addPropertyConstraint('firstName', new All(constraints: [new NotNull(), new Range(min: 3)]));
$expected->addPropertyConstraint('firstName', new Collection(fields: [
Expand All @@ -95,6 +94,23 @@ public function testLoadClassMetadata()
$this->assertEquals($expected, $metadata);
}

/**
* @group legacy
*/
public function testLoadClassMetadataValueOption()
{
$loader = new XmlFileLoader(__DIR__.'/constraint-mapping-value-option.xml');
$metadata = new ClassMetadata(Entity::class);

$loader->loadClassMetadata($metadata);

$expected = new ClassMetadata(Entity::class);
$expected->addPropertyConstraint('firstName', new Type(type: 'string'));
$expected->addPropertyConstraint('firstName', new Choice(choices: ['A', 'B']));

$this->assertEquals($expected, $metadata);
}

public function testLoadClassMetadataWithNonStrings()
{
$loader = new XmlFileLoader(__DIR__.'/constraint-mapping-non-strings.xml');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Constraints\Type;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;
use Symfony\Component\Validator\Tests\Dummy\DummyGroupProvider;
Expand Down Expand Up @@ -120,8 +121,6 @@ public function testLoadClassMetadata()
$expected->addConstraint(new ConstraintWithNamedArguments('foo'));
$expected->addConstraint(new ConstraintWithNamedArguments(['foo', 'bar']));
$expected->addPropertyConstraint('firstName', new NotNull());
$expected->addPropertyConstraint('firstName', new Range(min: 3));
$expected->addPropertyConstraint('firstName', new Choice(['A', 'B']));
$expected->addPropertyConstraint('firstName', new All(constraints: [new NotNull(), new Range(min: 3)]));
$expected->addPropertyConstraint('firstName', new All(constraints: [new NotNull(), new Range(min: 3)]));
$expected->addPropertyConstraint('firstName', new Collection(fields: [
Expand All @@ -139,6 +138,23 @@ public function testLoadClassMetadata()
$this->assertEquals($expected, $metadata);
}

/**
* @group legacy
*/
public function testLoadClassMetadataValueOption()
{
$loader = new YamlFileLoader(__DIR__.'/constraint-mapping-value-option.yml');
$metadata = new ClassMetadata(Entity::class);

$loader->loadClassMetadata($metadata);

$expected = new ClassMetadata(Entity::class);
$expected->addPropertyConstraint('firstName', new Type(type: 'string'));
$expected->addPropertyConstraint('firstName', new Choice(choices: ['A', 'B']));

$this->assertEquals($expected, $metadata);
}

public function testLoadClassMetadataWithConstants()
{
$loader = new YamlFileLoader(__DIR__.'/mapping-with-constants.yml');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" ?>

<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

<namespace prefix="custom">Symfony\Component\Validator\Tests\Fixtures\</namespace>

<class name="Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity">

<!-- PROPERTY CONSTRAINTS -->

<property name="firstName">

<!-- Constraint with single value -->
<constraint name="Type">string</constraint>

<!-- Constraint with multiple values -->
<constraint name="Choice">
<value>A</value>
<value>B</value>
</constraint>

</property>

</class>
</constraint-mapping>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespaces:
custom: Symfony\Component\Validator\Tests\Fixtures\

Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity:
properties:
firstName:
# Constraint with single value
- Type: string
# Constraint with multiple values
- Choice: [A, B]
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,6 @@
<!-- Constraint without value -->
<constraint name="NotNull" />

<!-- Constraint with single value -->
<constraint name="Range">
<option name="min">3</option>
</constraint>

<!-- Constraint with multiple values -->
<constraint name="Choice">
<value>A</value>
<value>B</value>
</constraint>

<!-- Constraint with child constraints -->
<constraint name="All">
<constraint name="NotNull" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity:
firstName:
# Constraint without value
- NotNull: ~
# Constraint with single value
- Range:
min: 3
# Constraint with multiple values
- Choice: [A, B]
# Constraint with child constraints
- All:
- NotNull: ~
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy