|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\Validator\Mapping; |
|
13 |
|
14 use Symfony\Component\Validator\Constraint; |
|
15 use Symfony\Component\Validator\Constraints\Valid; |
|
16 use Symfony\Component\Validator\Exception\ConstraintDefinitionException; |
|
17 use Symfony\Component\Validator\Exception\GroupDefinitionException; |
|
18 |
|
19 /** |
|
20 * Represents all the configured constraints on a given class. |
|
21 * |
|
22 * @author Bernhard Schussek <bernhard.schussek@symfony.com> |
|
23 * @author Fabien Potencier <fabien@symfony.com> |
|
24 */ |
|
25 class ClassMetadata extends ElementMetadata |
|
26 { |
|
27 public $name; |
|
28 public $defaultGroup; |
|
29 public $members = array(); |
|
30 public $properties = array(); |
|
31 public $getters = array(); |
|
32 public $groupSequence = array(); |
|
33 private $reflClass; |
|
34 |
|
35 /** |
|
36 * Constructs a metadata for the given class |
|
37 * |
|
38 * @param string $class |
|
39 */ |
|
40 public function __construct($class) |
|
41 { |
|
42 $this->name = $class; |
|
43 // class name without namespace |
|
44 if (false !== $nsSep = strrpos($class, '\\')) { |
|
45 $this->defaultGroup = substr($class, $nsSep + 1); |
|
46 } else { |
|
47 $this->defaultGroup = $class; |
|
48 } |
|
49 } |
|
50 |
|
51 /** |
|
52 * Returns the properties to be serialized |
|
53 * |
|
54 * @return array |
|
55 */ |
|
56 public function __sleep() |
|
57 { |
|
58 return array_merge(parent::__sleep(), array( |
|
59 'getters', |
|
60 'groupSequence', |
|
61 'members', |
|
62 'name', |
|
63 'properties', |
|
64 'defaultGroup' |
|
65 )); |
|
66 } |
|
67 |
|
68 /** |
|
69 * Returns the fully qualified name of the class |
|
70 * |
|
71 * @return string The fully qualified class name |
|
72 */ |
|
73 public function getClassName() |
|
74 { |
|
75 return $this->name; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Returns the name of the default group for this class |
|
80 * |
|
81 * For each class, the group "Default" is an alias for the group |
|
82 * "<ClassName>", where <ClassName> is the non-namespaced name of the |
|
83 * class. All constraints implicitly or explicitly assigned to group |
|
84 * "Default" belong to both of these groups, unless the class defines |
|
85 * a group sequence. |
|
86 * |
|
87 * If a class defines a group sequence, validating the class in "Default" |
|
88 * will validate the group sequence. The constraints assigned to "Default" |
|
89 * can still be validated by validating the class in "<ClassName>". |
|
90 * |
|
91 * @return string The name of the default group |
|
92 */ |
|
93 public function getDefaultGroup() |
|
94 { |
|
95 return $this->defaultGroup; |
|
96 } |
|
97 |
|
98 /** |
|
99 * {@inheritDoc} |
|
100 */ |
|
101 public function addConstraint(Constraint $constraint) |
|
102 { |
|
103 if (!in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets())) { |
|
104 throw new ConstraintDefinitionException(sprintf( |
|
105 'The constraint %s cannot be put on classes', |
|
106 get_class($constraint) |
|
107 )); |
|
108 } |
|
109 |
|
110 $constraint->addImplicitGroupName($this->getDefaultGroup()); |
|
111 |
|
112 parent::addConstraint($constraint); |
|
113 } |
|
114 |
|
115 /** |
|
116 * Adds a constraint to the given property. |
|
117 * |
|
118 * @param string $property The name of the property |
|
119 * @param Constraint $constraint The constraint |
|
120 * |
|
121 * @return ClassMetadata This object |
|
122 */ |
|
123 public function addPropertyConstraint($property, Constraint $constraint) |
|
124 { |
|
125 if (!isset($this->properties[$property])) { |
|
126 $this->properties[$property] = new PropertyMetadata($this->getClassName(), $property); |
|
127 |
|
128 $this->addMemberMetadata($this->properties[$property]); |
|
129 } |
|
130 |
|
131 $constraint->addImplicitGroupName($this->getDefaultGroup()); |
|
132 |
|
133 $this->properties[$property]->addConstraint($constraint); |
|
134 |
|
135 return $this; |
|
136 } |
|
137 |
|
138 /** |
|
139 * Adds a constraint to the getter of the given property. |
|
140 * |
|
141 * The name of the getter is assumed to be the name of the property with an |
|
142 * uppercased first letter and either the prefix "get" or "is". |
|
143 * |
|
144 * @param string $property The name of the property |
|
145 * @param Constraint $constraint The constraint |
|
146 * |
|
147 * @return ClassMetadata This object |
|
148 */ |
|
149 public function addGetterConstraint($property, Constraint $constraint) |
|
150 { |
|
151 if (!isset($this->getters[$property])) { |
|
152 $this->getters[$property] = new GetterMetadata($this->getClassName(), $property); |
|
153 |
|
154 $this->addMemberMetadata($this->getters[$property]); |
|
155 } |
|
156 |
|
157 $constraint->addImplicitGroupName($this->getDefaultGroup()); |
|
158 |
|
159 $this->getters[$property]->addConstraint($constraint); |
|
160 |
|
161 return $this; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Merges the constraints of the given metadata into this object. |
|
166 * |
|
167 * @param ClassMetadata $source The source metadata |
|
168 */ |
|
169 public function mergeConstraints(ClassMetadata $source) |
|
170 { |
|
171 foreach ($source->getConstraints() as $constraint) { |
|
172 $this->addConstraint(clone $constraint); |
|
173 } |
|
174 |
|
175 foreach ($source->getConstrainedProperties() as $property) { |
|
176 foreach ($source->getMemberMetadatas($property) as $member) { |
|
177 $member = clone $member; |
|
178 |
|
179 foreach ($member->getConstraints() as $constraint) { |
|
180 $constraint->addImplicitGroupName($this->getDefaultGroup()); |
|
181 } |
|
182 |
|
183 $this->addMemberMetadata($member); |
|
184 |
|
185 if (!$member->isPrivate()) { |
|
186 $property = $member->getPropertyName(); |
|
187 |
|
188 if ($member instanceof PropertyMetadata && !isset($this->properties[$property])) { |
|
189 $this->properties[$property] = $member; |
|
190 } else if ($member instanceof GetterMetadata && !isset($this->getters[$property])) { |
|
191 $this->getters[$property] = $member; |
|
192 } |
|
193 } |
|
194 } |
|
195 } |
|
196 } |
|
197 |
|
198 /** |
|
199 * Adds a member metadata |
|
200 * |
|
201 * @param MemberMetadata $metadata |
|
202 */ |
|
203 protected function addMemberMetadata(MemberMetadata $metadata) |
|
204 { |
|
205 $property = $metadata->getPropertyName(); |
|
206 |
|
207 $this->members[$property][] = $metadata; |
|
208 } |
|
209 |
|
210 /** |
|
211 * Returns true if metadatas of members is present for the given property. |
|
212 * |
|
213 * @param string $property The name of the property |
|
214 * |
|
215 * @return Boolean |
|
216 */ |
|
217 public function hasMemberMetadatas($property) |
|
218 { |
|
219 return array_key_exists($property, $this->members); |
|
220 } |
|
221 |
|
222 /** |
|
223 * Returns all metadatas of members describing the given property |
|
224 * |
|
225 * @param string $property The name of the property |
|
226 * @array of MemberMetadata |
|
227 */ |
|
228 public function getMemberMetadatas($property) |
|
229 { |
|
230 return $this->members[$property]; |
|
231 } |
|
232 |
|
233 /** |
|
234 * Returns all properties for which constraints are defined. |
|
235 * |
|
236 * @return array An array of property names |
|
237 */ |
|
238 public function getConstrainedProperties() |
|
239 { |
|
240 return array_keys($this->members); |
|
241 } |
|
242 |
|
243 /** |
|
244 * Sets the default group sequence for this class. |
|
245 * |
|
246 * @param array $groups An array of group names |
|
247 */ |
|
248 public function setGroupSequence(array $groups) |
|
249 { |
|
250 if (in_array(Constraint::DEFAULT_GROUP, $groups, true)) { |
|
251 throw new GroupDefinitionException(sprintf('The group "%s" is not allowed in group sequences', Constraint::DEFAULT_GROUP)); |
|
252 } |
|
253 |
|
254 if (!in_array($this->getDefaultGroup(), $groups, true)) { |
|
255 throw new GroupDefinitionException(sprintf('The group "%s" is missing in the group sequence', $this->getDefaultGroup())); |
|
256 } |
|
257 |
|
258 $this->groupSequence = $groups; |
|
259 |
|
260 return $this; |
|
261 } |
|
262 |
|
263 /** |
|
264 * Returns whether this class has an overridden default group sequence. |
|
265 * |
|
266 * @return Boolean |
|
267 */ |
|
268 public function hasGroupSequence() |
|
269 { |
|
270 return count($this->groupSequence) > 0; |
|
271 } |
|
272 |
|
273 /** |
|
274 * Returns the default group sequence for this class. |
|
275 * |
|
276 * @return array An array of group names |
|
277 */ |
|
278 public function getGroupSequence() |
|
279 { |
|
280 return $this->groupSequence; |
|
281 } |
|
282 |
|
283 /** |
|
284 * Returns a ReflectionClass instance for this class. |
|
285 * |
|
286 * @return ReflectionClass |
|
287 */ |
|
288 public function getReflectionClass() |
|
289 { |
|
290 if (!$this->reflClass) { |
|
291 $this->reflClass = new \ReflectionClass($this->getClassName()); |
|
292 } |
|
293 |
|
294 return $this->reflClass; |
|
295 } |
|
296 } |