1
1
Traverse
2
2
========
3
3
4
- Objects do not validate nested objects by default unless explicitly using
5
- this constraint .
6
- If only specific nested objects should be validated by cascade, consider
7
- using the :doc: ` /reference/constraints/Valid ` instead .
4
+ Object properties are only validated if they are accessible, either by being
5
+ public or having public accessor methods (e.g. a public getter) .
6
+ If your object needs to be traversed to validate its data, you can use this
7
+ constraint .
8
8
9
9
+----------------+-------------------------------------------------------------------------------------+
10
10
| Applies to | :ref: `class <validation-class-target >` |
@@ -17,51 +17,85 @@ using the :doc:`/reference/constraints/Valid` instead.
17
17
Basic Usage
18
18
-----------
19
19
20
- In the following example, create three classes ``Book ``, ``Author `` and
21
- ``Editor `` that all have constraints on their properties. Furthermore,
22
- ``Book `` stores an ``Author `` and an ``Editor `` instance that must be
23
- valid too. Instead of adding the ``Valid `` constraint to both fields,
24
- configure the ``Traverse `` constraint on the ``Book `` class.
20
+ In the following example, create two classes ``BookCollection `` and ``Book ``
21
+ that all have constraints on their properties.
25
22
26
23
.. configuration-block ::
27
24
28
25
.. code-block :: php-annotations
29
26
30
- // src/Entity/Book .php
27
+ // src/Entity/BookCollection .php
31
28
namespace App\Entity;
32
29
30
+ use Doctrine\Collections\ArrayCollection;
31
+ use Doctrine\Collections\Collection
33
32
use Doctrine\ORM\Mapping as ORM;
34
33
use Symfony\Component\Validator\Constraints as Assert;
35
34
36
35
/**
37
36
* @ORM\Entity
38
37
* @Assert\Traverse
39
38
*/
40
- class Book
39
+ class BookCollection implements \IteratorAggregate
41
40
{
42
41
/**
43
- * @var Author
42
+ * @var string
44
43
*
45
- * @ORM\ManyToOne(targetEntity="App\Entity\Author")
44
+ * @ORM\Column
45
+ *
46
+ * @Assert\NotBlank
46
47
*/
47
- protected $author ;
48
+ protected $name = '' ;
48
49
49
50
/**
50
- * @var Editor
51
+ * @var Collection|Book[]
51
52
*
52
- * @ORM\ManyToOne (targetEntity="App\Entity\Editor ")
53
+ * @ORM\ManyToMany (targetEntity="App\Entity\Book ")
53
54
*/
54
- protected $editor ;
55
+ protected $books ;
55
56
56
- // ...
57
+ // some other properties
58
+
59
+ public function __construct()
60
+ {
61
+ $this->books = new ArrayCollection();
62
+ }
63
+
64
+ // ... setter for name, adder and remover for books
65
+
66
+ // the name can be validated by calling the getter
67
+ public function getName(): string
68
+ {
69
+ return $this->name;
70
+ }
71
+
72
+ /**
73
+ * @return \Generator|Book[] The books for a given author
74
+ */
75
+ public function getBooksForAuthor(Author $author): iterable
76
+ {
77
+ foreach ($this->books as $book) {
78
+ if ($book->isAuthoredBy($author)) {
79
+ yield $book;
80
+ }
81
+ }
82
+ }
83
+
84
+ // neither the method above nor any other specific getter
85
+ // could be used to validated all nested books;
86
+ // this object needs to be traversed to call the iterator
87
+ public function getIterator()
88
+ {
89
+ return $this->books->getIterator();
90
+ }
57
91
}
58
92
59
93
.. code-block :: yaml
60
94
61
- # config/validator/validation.yaml
62
- App\Entity\Book :
95
+ # config/validator/validation.yml
96
+ App\Entity\BookCollection :
63
97
constraints :
64
- - Symfony\Component\Validator\Constraints\ Traverse : ~
98
+ - Traverse : ~
65
99
66
100
.. code-block :: xml
67
101
@@ -71,28 +105,105 @@ configure the ``Traverse`` constraint on the ``Book`` class.
71
105
xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
72
106
xsi : schemaLocation =" http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd" >
73
107
74
- <class name =" App\Entity\Book " >
75
- <constraint name =" Symfony\Component\Validator\Constraints\ Traverse" />
108
+ <class name =" App\Entity\BookCollection " >
109
+ <constraint name =" Traverse" />
76
110
</class >
77
111
</constraint-mapping >
78
112
79
113
.. code-block :: php
80
114
81
- // src/Entity/Book .php
115
+ // src/Entity/BookCollection .php
82
116
namespace App\Entity;
83
117
84
118
use Symfony\Component\Validator\Constraints as Assert;
85
119
use Symfony\Component\Validator\Mapping\ClassMetadata;
86
120
87
- class Book
121
+ class BookCollection
88
122
{
123
+ // ...
124
+
89
125
public static function loadValidatorMetadata(ClassMetadata $metadata)
90
126
{
91
127
$metadata->addConstraint(new Assert\Traverse());
92
128
}
93
129
}
94
130
131
+ When the object implements ``\Traversable `` (like here with its child
132
+ ``\IteratorAggregate ``), its traversal strategy will implicitly be set and the
133
+ object will be iterated over without defining the constraint.
134
+ It's mostly useful to add it to be explicit or to disable the traversal using
135
+ the ``traverse `` option.
136
+ If a public getter exists to return the inner books collection like
137
+ ``getBooks(): Collection ``, the :doc: `/reference/constraints/Valid ` constraint
138
+ can be used on the ``$books `` property instead.
139
+
95
140
Options
96
141
-------
97
142
143
+ The ``groups `` option is not available for this constraint.
144
+
145
+
146
+ ``traverse ``
147
+ ~~~~~~~~~~~~
148
+
149
+ **type **: ``bool `` **default **: ``true ``
150
+
151
+ Instances of ``\Traversable `` are traversed by default, use this option to
152
+ disable validating:
153
+
154
+ .. configuration-block ::
155
+
156
+ .. code-block :: php-annotations
157
+
158
+ // src/Entity/BookCollection.php
159
+
160
+ // ... same as above
161
+
162
+ /**
163
+ * ...
164
+ * @Assert\Traverse(false)
165
+ */
166
+ class BookCollection implements \IteratorAggregate
167
+ {
168
+ // ...
169
+ }
170
+
171
+ .. code-block :: yaml
172
+
173
+ # config/validator/validation.yml
174
+ App\Entity\BookCollection :
175
+ constraints :
176
+ - Traverse : false
177
+
178
+ .. code-block :: xml
179
+
180
+ <!-- config/validator/validation.xml -->
181
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
182
+ <constraint-mapping xmlns =" http://symfony.com/schema/dic/constraint-mapping"
183
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
184
+ xsi : schemaLocation =" http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd" >
185
+
186
+ <class name =" App\Entity\BookCollection" >
187
+ <constraint name =" Traverse" >false</constraint >
188
+ </class >
189
+ </constraint-mapping >
190
+
191
+ .. code-block :: php
192
+
193
+ // src/Entity/BookCollection.php
194
+ namespace App\Entity;
195
+
196
+ use Symfony\Component\Validator\Constraints as Assert;
197
+ use Symfony\Component\Validator\Mapping\ClassMetadata;
198
+
199
+ class BookCollection
200
+ {
201
+ // ...
202
+
203
+ public static function loadValidatorMetadata(ClassMetadata $metadata)
204
+ {
205
+ $metadata->addConstraint(new Assert\Traverse(false));
206
+ }
207
+ }
208
+
98
209
.. include :: /reference/constraints/_payload-option.rst.inc
0 commit comments