Skip to content

Commit 3c9ddd6

Browse files
committed
Merge branch '6.3' into 6.4
* 6.3: Describe how to create a custom constraint with options
2 parents 28f9d08 + 53cbda4 commit 3c9ddd6

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

validation/custom_constraint.rst

+145
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,151 @@ then your validator is already registered as a service and :doc:`tagged </servic
217217
with the necessary ``validator.constraint_validator``. This means you can
218218
:ref:`inject services or configuration <services-constructor-injection>` like any other service.
219219

220+
Constraint Validators with Custom Options
221+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222+
223+
If you want to add some configuration options to your custom constraint, first
224+
define those options as public properties on the constraint class::
225+
226+
// src/Validator/Foo.php
227+
namespace App\Validator;
228+
229+
use Symfony\Component\Validator\Constraint;
230+
231+
#[\Attribute]
232+
class Foo extends Constraint
233+
{
234+
public $mandatoryFooOption;
235+
public $message = 'This value is invalid';
236+
public $optionalBarOption = false;
237+
238+
public function __construct(
239+
$mandatoryFooOption,
240+
string $message = null,
241+
bool $optionalBarOption = null,
242+
array $groups = null,
243+
$payload = null,
244+
array $options = []
245+
) {
246+
if (\is_array($mandatoryFooOption)) {
247+
$options = array_merge($mandatoryFooOption, $options);
248+
} elseif (null !== $mandatoryFooOption) {
249+
$options['value'] = $mandatoryFooOption;
250+
}
251+
252+
parent::__construct($options, $groups, $payload);
253+
254+
$this->message = $message ?? $this->message;
255+
$this->optionalBarOption = $optionalBarOption ?? $this->optionalBarOption;
256+
}
257+
258+
public function getDefaultOption()
259+
{
260+
return 'mandatoryFooOption';
261+
}
262+
263+
public function getRequiredOptions()
264+
{
265+
return ['mandatoryFooOption'];
266+
}
267+
}
268+
269+
Then, inside the validator class you can access these options directly via the
270+
constraint class passes to the ``validate()`` method::
271+
272+
class FooValidator extends ConstraintValidator
273+
{
274+
public function validate($value, Constraint $constraint)
275+
{
276+
// access any option of the constraint
277+
if ($constraint->optionalBarOption) {
278+
// ...
279+
}
280+
281+
// ...
282+
}
283+
}
284+
285+
When using this constraint in your own application, you can pass the value of
286+
the custom options like you pass any other option in built-in constraints:
287+
288+
.. configuration-block::
289+
290+
.. code-block:: php-attributes
291+
292+
// src/Entity/AcmeEntity.php
293+
namespace App\Entity;
294+
295+
use App\Validator as AcmeAssert;
296+
use Symfony\Component\Validator\Constraints as Assert;
297+
298+
class AcmeEntity
299+
{
300+
// ...
301+
302+
#[Assert\NotBlank]
303+
#[AcmeAssert\Foo(
304+
mandatoryFooOption: 'bar',
305+
optionalBarOption: true
306+
)]
307+
protected $name;
308+
309+
// ...
310+
}
311+
312+
.. code-block:: yaml
313+
314+
# config/validator/validation.yaml
315+
App\Entity\AcmeEntity:
316+
properties:
317+
name:
318+
- NotBlank: ~
319+
- App\Validator\Foo:
320+
mandatoryFooOption: bar
321+
optionalBarOption: true
322+
323+
.. code-block:: xml
324+
325+
<!-- config/validator/validation.xml -->
326+
<?xml version="1.0" encoding="UTF-8" ?>
327+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
328+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
329+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
330+
331+
<class name="App\Entity\AcmeEntity">
332+
<property name="name">
333+
<constraint name="NotBlank"/>
334+
<constraint name="App\Validator\Foo">
335+
<option name="mandatoryFooOption">bar</option>
336+
<option name="optionalBarOption">true</option>
337+
</constraint>
338+
</property>
339+
</class>
340+
</constraint-mapping>
341+
342+
.. code-block:: php
343+
344+
// src/Entity/AcmeEntity.php
345+
namespace App\Entity;
346+
347+
use App\Validator\ContainsAlphanumeric;
348+
use Symfony\Component\Validator\Constraints\NotBlank;
349+
use Symfony\Component\Validator\Mapping\ClassMetadata;
350+
351+
class AcmeEntity
352+
{
353+
public $name;
354+
355+
public static function loadValidatorMetadata(ClassMetadata $metadata)
356+
{
357+
$metadata->addPropertyConstraint('name', new NotBlank());
358+
$metadata->addPropertyConstraint('name', new Foo([
359+
'mandatoryFooOption' => 'bar',
360+
'optionalBarOption' => true,
361+
]));
362+
}
363+
}
364+
220365
Create a Reusable Set of Constraints
221366
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222367

0 commit comments

Comments
 (0)