Skip to content

Commit c71a1d7

Browse files
committed
[Validator] Add the Conditional constraint and validator docs
1 parent 944a6ed commit c71a1d7

File tree

2 files changed

+294
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)