@@ -217,6 +217,151 @@ then your validator is already registered as a service and :doc:`tagged </servic
217
217
with the necessary ``validator.constraint_validator ``. This means you can
218
218
:ref: `inject services or configuration <services-constructor-injection >` like any other service.
219
219
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
+
220
365
Create a Reusable Set of Constraints
221
366
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
367
0 commit comments