Skip to content

Commit e842a59

Browse files
committed
[Validator] Add the Conditional constraint and validator docs
1 parent 942fd56 commit e842a59

File tree

2 files changed

+295
-0
lines changed

2 files changed

+295
-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: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
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 or equal 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\LessThanOrEqual(100, message: 'The value should be between 1 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+
- LessThanOrEqual:
94+
value: 100
95+
message: "The value should be between 1 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="LessThanOrEqual">
115+
<option name="value">100</option>
116+
<option name="message">The value should be between 1 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\LessThanOrEqual([
141+
'value' => 100,
142+
'message' => 'The value should be between 1 and 100!',
143+
]),
144+
],
145+
]));
146+
}
147+
148+
// ...
149+
}
150+
151+
The :ref:`expression <reference-constraint-expression-option>` option is the
152+
expression that must return true in order to trigger the validation of the attached constraints.
153+
To learn more about the expression language syntax, see
154+
:doc:`/components/expression_language/syntax`.
155+
156+
For more information about the expression and what variables are available
157+
to you, see the :ref:`expression <reference-constraint-expression-option>`
158+
option details below.
159+
160+
Options
161+
-------
162+
163+
.. _reference-constraint-expression-option:
164+
165+
``expression``
166+
~~~~~~~~~~~~~~
167+
168+
**type**: ``string``
169+
170+
The condition written with the expression language syntax that will be evaluated.
171+
If the expression evaluates to a false value (using ``==``, not ``===``),
172+
validation of constraints won't be triggered.
173+
174+
To learn more about the expression language syntax, see
175+
:doc:`/components/expression_language/syntax`.
176+
177+
Inside of the expression, you have access to up to 2 variables:
178+
179+
Depending on how you use the constraint, you have access to 1 or 2 variables
180+
in your expression:
181+
182+
* ``this``: The object being validated (e.g. an instance of Discount);
183+
* ``value``: The value of the property being validated (only available when
184+
the constraint is applied directly to a property);
185+
186+
The ``value`` variable can be used when you want to execute more complex validation based on its value:
187+
188+
.. configuration-block::
189+
190+
.. code-block:: php-attributes
191+
192+
// src/Model/Discount.php
193+
namespace App\Model;
194+
195+
use Symfony\Component\Validator\Constraints as Assert;
196+
use Symfony\Component\Validator\Context\ExecutionContextInterface;
197+
198+
class Discount
199+
{
200+
#[Assert\When(
201+
expression: 'value == "percent"',
202+
constraints: [new Assert\Callback('doComplexValidation')],
203+
)]
204+
private ?string $type;
205+
// ...
206+
207+
public function doComplexValidation(ExecutionContextInterface $context, $payload)
208+
{
209+
// ...
210+
}
211+
}
212+
213+
.. code-block:: yaml
214+
215+
# config/validator/validation.yaml
216+
App\Model\Discount:
217+
properties:
218+
type:
219+
- When:
220+
expression: "value == 'percent'"
221+
constraints:
222+
- Callback: doComplexValidation
223+
224+
.. code-block:: xml
225+
226+
<!-- config/validator/validation.xml -->
227+
<?xml version="1.0" encoding="UTF-8" ?>
228+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
229+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
230+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
231+
<class name="App\Model\Discount">
232+
<property name="type">
233+
<constraint name="When">
234+
<option name="expression">
235+
value == 'percent'
236+
</option>
237+
<option name="constraints">
238+
<constraint name="Callback">
239+
<option name="callback">doComplexValidation</option>
240+
</constraint>
241+
</option>
242+
</constraint>
243+
</property>
244+
</class>
245+
</constraint-mapping>
246+
247+
.. code-block:: php
248+
249+
// src/Model/Discount.php
250+
namespace App\Model;
251+
252+
use Symfony\Component\Validator\Constraints as Assert;
253+
use Symfony\Component\Validator\Mapping\ClassMetadata;
254+
255+
class Discount
256+
{
257+
public static function loadValidatorMetadata(ClassMetadata $metadata)
258+
{
259+
$metadata->addPropertyConstraint('type', new Assert\When([
260+
'expression' => 'value == "percent"',
261+
'constraints' => [
262+
new Assert\Callback('doComplexValidation'),
263+
],
264+
]));
265+
}
266+
267+
public function doComplexValidation(ExecutionContextInterface $context, $payload)
268+
{
269+
// ...
270+
}
271+
272+
// ...
273+
}
274+
275+
.. _reference-constraint-constraints-option:
276+
277+
``constraints``
278+
~~~~~~~~~~~~~~~
279+
280+
**type**: ``array``
281+
282+
The constraints that are applied if the expression returns true.
283+
284+
.. include:: /reference/constraints/_groups-option.rst.inc
285+
286+
.. include:: /reference/constraints/_payload-option.rst.inc
287+
288+
``values``
289+
~~~~~~~~~~
290+
291+
**type**: ``array`` **default**: ``[]``
292+
293+
The values of the custom variables used in the expression. Values can be of any
294+
type (numeric, boolean, strings, null, etc.)

0 commit comments

Comments
 (0)