Skip to content

Commit a2a82fc

Browse files
wuchen90wouterj
authored andcommitted
[Validator] Add the Conditional constraint and validator docs
1 parent 942fd56 commit a2a82fc

File tree

2 files changed

+289
-0
lines changed

2 files changed

+289
-0
lines changed

reference/constraints.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Validation Constraints Reference
7272
constraints/Compound
7373
constraints/Callback
7474
constraints/Expression
75+
constraints/When
7576
constraints/All
7677
constraints/UserPassword
7778
constraints/NotCompromisedPassword

reference/constraints/When.rst

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
When
2+
====
3+
4+
.. versionadded:: 6.2
5+
6+
The ``When`` constraint was introduced in Symfony 6.2.
7+
8+
This constraint allows you to apply constraints validation only if the
9+
provided expression returns true. See `Basic Usage`_ for an example.
10+
11+
========== ===================================================================
12+
Applies to :ref:`class <validation-class-target>`
13+
or :ref:`property/method <validation-property-target>`
14+
Options - `expression`_
15+
- `constraints`_
16+
- `groups`_
17+
- `payload`_
18+
- `values`_
19+
Class :class:`Symfony\\Component\\Validator\\Constraints\\When`
20+
Validator :class:`Symfony\\Component\\Validator\\Constraints\\WhenValidator`
21+
========== ===================================================================
22+
23+
Basic Usage
24+
-----------
25+
26+
Imagine you have a class ``Discount`` with ``type`` and ``value``
27+
properties::
28+
29+
// src/Model/Discount.php
30+
namespace App\Model;
31+
32+
class Discount
33+
{
34+
private ?string $type;
35+
36+
private ?int $value;
37+
38+
// ...
39+
40+
public function getType(): ?string
41+
{
42+
return $this->type;
43+
}
44+
45+
public function getValue(): ?int
46+
{
47+
return $this->value;
48+
}
49+
}
50+
51+
To validate the object, you have some requirements:
52+
53+
A) If ``type`` is ``percent``, then ``value`` must be less than or equal 100;
54+
B) If ``type`` is ``absolute``, then ``value`` can be anything;
55+
C) No matter the value of ``type``, the ``value`` must be greater than 0.
56+
57+
One way to accomplish this is with the When constraint:
58+
59+
.. configuration-block::
60+
61+
.. code-block:: php-attributes
62+
63+
// src/Model/Discount.php
64+
namespace App\Model;
65+
66+
use Symfony\Component\Validator\Constraints as Assert;
67+
68+
class Discount
69+
{
70+
#[Assert\GreaterThan(0)]
71+
#[Assert\When(
72+
expression: 'this.type == "percent"',
73+
constraints: [
74+
new Assert\LessThanOrEqual(100, message: 'The value should be between 1 and 100!')
75+
],
76+
)]
77+
private ?int $value;
78+
79+
// ...
80+
}
81+
82+
.. code-block:: yaml
83+
84+
# config/validator/validation.yaml
85+
App\Model\Discount:
86+
properties:
87+
value:
88+
- GreaterThan: 0
89+
- When:
90+
expression: "this.type == 'percent'"
91+
constraints:
92+
- LessThanOrEqual:
93+
value: 100
94+
message: "The value should be between 1 and 100!"
95+
96+
.. code-block:: xml
97+
98+
<!-- config/validator/validation.xml -->
99+
<?xml version="1.0" encoding="UTF-8" ?>
100+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
101+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
102+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
103+
<class name="App\Model\Discount">
104+
<property name="value">
105+
<constraint name="GreaterThan">0</constraint>
106+
<constraint name="When">
107+
<option name="expression">
108+
this.type == 'percent'
109+
</option>
110+
<option name="constraints">
111+
<constraint name="LessThanOrEqual">
112+
<option name="value">100</option>
113+
<option name="message">The value should be between 1 and 100!</option>
114+
</constraint>
115+
</option>
116+
</constraint>
117+
</property>
118+
</class>
119+
</constraint-mapping>
120+
121+
.. code-block:: php
122+
123+
// src/Model/Discount.php
124+
namespace App\Model;
125+
126+
use Symfony\Component\Validator\Constraints as Assert;
127+
use Symfony\Component\Validator\Mapping\ClassMetadata;
128+
129+
class Discount
130+
{
131+
public static function loadValidatorMetadata(ClassMetadata $metadata)
132+
{
133+
$metadata->addPropertyConstraint('value', new Assert\GreaterThan(0));
134+
$metadata->addPropertyConstraint('value', new Assert\When([
135+
'expression' => 'this.type == "percent"',
136+
'constraints' => [
137+
new Assert\LessThanOrEqual([
138+
'value' => 100,
139+
'message' => 'The value should be between 1 and 100!',
140+
]),
141+
],
142+
]));
143+
}
144+
145+
// ...
146+
}
147+
148+
The `expression`_ option is the expression that must return true in order
149+
to trigger the validation of the attached constraints. To learn more about
150+
the expression language syntax, see :doc:`/components/expression_language/syntax`.
151+
152+
For more information about the expression and what variables are available
153+
to you, see the `expression`_ option details below.
154+
155+
Options
156+
-------
157+
158+
``expression``
159+
~~~~~~~~~~~~~~
160+
161+
**type**: ``string``
162+
163+
The condition written with the expression language syntax that will be evaluated.
164+
If the expression evaluates to a falsey value (i.e. using ``==``, not ``===``),
165+
validation of constraints won't be triggered.
166+
167+
To learn more about the expression language syntax, see
168+
:doc:`/components/expression_language/syntax`.
169+
170+
Depending on how you use the constraint, you have access to 1 or 2 variables
171+
in your expression:
172+
173+
``this``
174+
The object being validated (e.g. an instance of Discount).
175+
``value``
176+
The value of the property being validated (only available when
177+
the constraint is applied to a property).
178+
179+
The ``value`` variable can be used when you want to execute more complex
180+
validation based on its value:
181+
182+
.. configuration-block::
183+
184+
.. code-block:: php-attributes
185+
186+
// src/Model/Discount.php
187+
namespace App\Model;
188+
189+
use Symfony\Component\Validator\Constraints as Assert;
190+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
191+
192+
class Discount
193+
{
194+
#[Assert\When(
195+
expression: 'value == "percent"',
196+
constraints: [new Assert\Callback('doComplexValidation')],
197+
)]
198+
private ?string $type;
199+
// ...
200+
201+
public function doComplexValidation(ExecutionContextInterface $context, $payload)
202+
{
203+
// ...
204+
}
205+
}
206+
207+
.. code-block:: yaml
208+
209+
# config/validator/validation.yaml
210+
App\Model\Discount:
211+
properties:
212+
type:
213+
- When:
214+
expression: "value == 'percent'"
215+
constraints:
216+
- Callback: doComplexValidation
217+
218+
.. code-block:: xml
219+
220+
<!-- config/validator/validation.xml -->
221+
<?xml version="1.0" encoding="UTF-8" ?>
222+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
223+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
224+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
225+
<class name="App\Model\Discount">
226+
<property name="type">
227+
<constraint name="When">
228+
<option name="expression">
229+
value == 'percent'
230+
</option>
231+
<option name="constraints">
232+
<constraint name="Callback">
233+
<option name="callback">doComplexValidation</option>
234+
</constraint>
235+
</option>
236+
</constraint>
237+
</property>
238+
</class>
239+
</constraint-mapping>
240+
241+
.. code-block:: php
242+
243+
// src/Model/Discount.php
244+
namespace App\Model;
245+
246+
use Symfony\Component\Validator\Constraints as Assert;
247+
use Symfony\Component\Validator\Mapping\ClassMetadata;
248+
249+
class Discount
250+
{
251+
// ...
252+
253+
public static function loadValidatorMetadata(ClassMetadata $metadata)
254+
{
255+
$metadata->addPropertyConstraint('type', new Assert\When([
256+
'expression' => 'value == "percent"',
257+
'constraints' => [
258+
new Assert\Callback('doComplexValidation'),
259+
],
260+
]));
261+
}
262+
263+
public function doComplexValidation(ExecutionContextInterface $context, $payload)
264+
{
265+
// ...
266+
}
267+
}
268+
269+
You can also pass custom variables using the `values`_ option.
270+
271+
``constraints``
272+
~~~~~~~~~~~~~~~
273+
274+
**type**: ``array``
275+
276+
The constraints that are applied if the expression returns true.
277+
278+
.. include:: /reference/constraints/_groups-option.rst.inc
279+
280+
.. include:: /reference/constraints/_payload-option.rst.inc
281+
282+
``values``
283+
~~~~~~~~~~
284+
285+
**type**: ``array`` **default**: ``[]``
286+
287+
The values of the custom variables used in the expression. Values can be of any
288+
type (numeric, boolean, strings, null, etc.)

0 commit comments

Comments
 (0)