2
2
single: Validation; Custom constraints
3
3
4
4
How to create a Custom Validation Constraint
5
- --------------------------------------------
5
+ ============================================
6
6
7
7
You can create a custom constraint by extending the base constraint class,
8
- :class: `Symfony\\ Component\\ Validator\\ Constraint `. Options for your
9
- constraint are represented as public properties on the constraint class. For
10
- example, the :doc: `Url</reference/constraints/Url> ` constraint includes
11
- the ``message `` and ``protocols `` properties:
8
+ :class: `Symfony\\ Component\\ Validator\\ Constraint `.
9
+ As an example we're going to create a simple validator that checks if string
10
+ contains only alphanumeric characters.
12
11
13
- .. code-block :: php
12
+ Creating Constraint class
13
+ -------------------------
14
14
15
- namespace Symfony\Component\Validator\Constraints;
15
+ First you need to create a Constraint class and extend :class: `Symfony\\ Component\\ Validator\\ Constraint `::
16
+
17
+ namespace Acme\D emoBundle\V alidator\C onstraints;
16
18
17
19
use Symfony\C omponent\V alidator\C onstraint;
18
20
19
21
/**
20
22
* @Annotation
21
23
*/
22
- class Protocol extends Constraint
24
+ class ContainsAlphanumeric extends Constraint
23
25
{
24
- public $message = 'This value is not a valid protocol';
25
- public $protocols = array('http', 'https', 'ftp', 'ftps');
26
+ public $message = 'Missing at least one alphanumeric character in "%string%" string';
26
27
}
27
28
28
29
.. note ::
29
30
30
31
The ``@Annotation `` annotation is necessary for this new constraint in
31
32
order to make it available for use in classes via annotations.
33
+ Options for your constraint are represented as public properties on the constraint class.
32
34
35
+ Creating Validator itself
36
+ -------------------------
37
+
33
38
As you can see, a constraint class is fairly minimal. The actual validation is
34
39
performed by a another "constraint validator" class. The constraint validator
35
40
class is specified by the constraint's ``validatedBy() `` method, which
36
- includes some simple default logic:
37
-
38
- .. code-block :: php
41
+ includes some simple default logic::
39
42
40
43
// in the base Symfony\Component\Validator\Constraint class
41
44
public function validatedBy()
@@ -47,22 +50,19 @@ In other words, if you create a custom ``Constraint`` (e.g. ``MyConstraint``),
47
50
Symfony2 will automatically look for another class, ``MyConstraintValidator ``
48
51
when actually performing the validation.
49
52
50
- The validator class is also simple, and only has one required method: ``isValid ``.
51
- Furthering our example, take a look at the ``ProtocolValidator `` as an example:
52
-
53
- .. code-block :: php
53
+ The validator class is also simple, and only has one required method: ``isValid ``::
54
54
55
- namespace Symfony\Component \Validator\Constraints;
55
+ namespace Acme\DemoBundle \Validator\Constraints;
56
56
57
57
use Symfony\Component\Validator\Constraint;
58
58
use Symfony\Component\Validator\ConstraintValidator;
59
59
60
- class ProtocolValidator extends ConstraintValidator
60
+ class ContainsAlphanumericValidator extends ConstraintValidator
61
61
{
62
62
public function isValid($value, Constraint $constraint)
63
63
{
64
- if (!in_array($ value, $constraint->protocols )) {
65
- $this->setMessage($constraint->message, array('%protocols %' => $constraint->protocols) );
64
+ if (!preg_match('/^[a-zA-Za0-9]+$/', $ value, $matches )) {
65
+ $this->setMessage($constraint->message, array('%string %' => $value );
66
66
67
67
return false;
68
68
}
@@ -75,6 +75,77 @@ Furthering our example, take a look at the ``ProtocolValidator`` as an example:
75
75
76
76
Don't forget to call ``setMessage `` to construct an error message when the
77
77
value is invalid.
78
+
79
+ Using newly created validator
80
+ -----------------------------
81
+
82
+ Using custom validators is very easy, just as the ones provided by Symfony2 itself:
83
+
84
+ .. configuration-block ::
85
+
86
+ .. code-block :: yaml
87
+
88
+ # src/Acme/BlogBundle/Resources/config/validation.yml
89
+ Acme\DemoBundle\Entity\AcmeEntity :
90
+ properties :
91
+ name :
92
+ - NotBlank : ~
93
+ - Acme\DemoBundle\Validator\Constraints\ContainsAlphanumeric : ~
94
+
95
+ .. code-block :: php-annotations
96
+
97
+ // src/Acme/DemoBundle/Entity/AcmeEntity.php
98
+
99
+ use Symfony\Component\Validator\Constraints as Assert;
100
+ use Acme\DemoBundle\Validator\Constraints as AcmeAssert;
101
+
102
+ class AcmeEntity
103
+ {
104
+ // ...
105
+
106
+ /**
107
+ * @Assert\NotBlank
108
+ * @AcmeAssert\ContainsAlphanumeric
109
+ */
110
+ protected $name;
111
+
112
+ // ...
113
+ }
114
+
115
+ .. code-block :: xml
116
+
117
+ <!-- src/Acme/DemoBundle/Resources/config/validation.xml -->
118
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
119
+ <constraint-mapping xmlns =" http://symfony.com/schema/dic/constraint-mapping"
120
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
121
+ xsi : schemaLocation =" http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd" >
122
+
123
+ <class name =" Acme\DemoBundle\Entity\AcmeEntity" >
124
+ <property name =" name" >
125
+ <constraint name =" NotBlank" />
126
+ <constraint name =" Acme\DemoBundle\Validator\Constraints\ContainsAlphanumeric" />
127
+ </property >
128
+ </class >
129
+ </constraint-mapping >
130
+
131
+ .. code-block :: php
132
+
133
+ // src/Acme/DemoBundle/Entity/AcmeEntity.php
134
+
135
+ use Symfony\Component\Validator\Mapping\ClassMetadata;
136
+ use Symfony\Component\Validator\Constraints\NotBlank;
137
+ use Acme\DemoBundle\Validator\Constraints\ContainsAlphanumeric;
138
+
139
+ class AcmeEntity
140
+ {
141
+ public $name;
142
+
143
+ public static function loadValidatorMetadata(ClassMetadata $metadata)
144
+ {
145
+ $metadata->addPropertyConstraint('name', new NotBlank());
146
+ $metadata->addPropertyConstraint('name', new ContainsAlphanumeric());
147
+ }
148
+ }
78
149
79
150
Constraint Validators with Dependencies
80
151
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -142,8 +213,9 @@ With this, the validator ``isValid()`` method gets an object as its first argume
142
213
{
143
214
if ($protocol->getFoo() != $protocol->getBar()) {
144
215
145
- // bind error message on foo property
146
- $this->context->addViolationAtSubPath('foo', $constraint->getMessage(), array(), null);
216
+ $propertyPath = $this->context->getPropertyPath() . 'foo';
217
+ $this->context->setPropertyPath($propertyPath);
218
+ $this->context->addViolation($constraint->getMessage(), array(), null);
147
219
148
220
return false;
149
221
}
0 commit comments