|
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; |
|
13 |
|
14 use Symfony\Component\Validator\Exception\InvalidOptionsException; |
|
15 use Symfony\Component\Validator\Exception\MissingOptionsException; |
|
16 use Symfony\Component\Validator\Exception\ConstraintDefinitionException; |
|
17 |
|
18 /** |
|
19 * Contains the properties of a constraint definition. |
|
20 * |
|
21 * A constraint can be defined on a class, an option or a getter method. |
|
22 * The Constraint class encapsulates all the configuration required for |
|
23 * validating this class, option or getter result successfully. |
|
24 * |
|
25 * Constraint instances are immutable and serializable. |
|
26 * |
|
27 * @author Bernhard Schussek <bernhard.schussek@symfony.com> |
|
28 * |
|
29 * @api |
|
30 */ |
|
31 abstract class Constraint |
|
32 { |
|
33 /** |
|
34 * The name of the group given to all constraints with no explicit group |
|
35 * @var string |
|
36 */ |
|
37 const DEFAULT_GROUP = 'Default'; |
|
38 |
|
39 /** |
|
40 * Marks a constraint that can be put onto classes |
|
41 * @var string |
|
42 */ |
|
43 const CLASS_CONSTRAINT = 'class'; |
|
44 |
|
45 /** |
|
46 * Marks a constraint that can be put onto properties |
|
47 * @var string |
|
48 */ |
|
49 const PROPERTY_CONSTRAINT = 'property'; |
|
50 |
|
51 /** |
|
52 * @var array |
|
53 */ |
|
54 public $groups = array(self::DEFAULT_GROUP); |
|
55 |
|
56 /** |
|
57 * Initializes the constraint with options. |
|
58 * |
|
59 * You should pass an associative array. The keys should be the names of |
|
60 * existing properties in this class. The values should be the value for these |
|
61 * properties. |
|
62 * |
|
63 * Alternatively you can override the method getDefaultOption() to return the |
|
64 * name of an existing property. If no associative array is passed, this |
|
65 * property is set instead. |
|
66 * |
|
67 * You can force that certain options are set by overriding |
|
68 * getRequiredOptions() to return the names of these options. If any |
|
69 * option is not set here, an exception is thrown. |
|
70 * |
|
71 * @param mixed $options The options (as associative array) |
|
72 * or the value for the default |
|
73 * option (any other type) |
|
74 * |
|
75 * @throws InvalidOptionsException When you pass the names of non-existing |
|
76 * options |
|
77 * @throws MissingOptionsException When you don't pass any of the options |
|
78 * returned by getRequiredOptions() |
|
79 * @throws ConstraintDefinitionException When you don't pass an associative |
|
80 * array, but getDefaultOption() returns |
|
81 * NULL |
|
82 * |
|
83 * @api |
|
84 */ |
|
85 public function __construct($options = null) |
|
86 { |
|
87 $invalidOptions = array(); |
|
88 $missingOptions = array_flip((array) $this->getRequiredOptions()); |
|
89 |
|
90 if (is_array($options) && count($options) == 1 && isset($options['value'])) { |
|
91 $options = $options['value']; |
|
92 } |
|
93 |
|
94 if (is_array($options) && count($options) > 0 && is_string(key($options))) { |
|
95 foreach ($options as $option => $value) { |
|
96 if (property_exists($this, $option)) { |
|
97 $this->$option = $value; |
|
98 unset($missingOptions[$option]); |
|
99 } else { |
|
100 $invalidOptions[] = $option; |
|
101 } |
|
102 } |
|
103 } else if (null !== $options && ! (is_array($options) && count($options) === 0)) { |
|
104 $option = $this->getDefaultOption(); |
|
105 |
|
106 if (null === $option) { |
|
107 throw new ConstraintDefinitionException( |
|
108 sprintf('No default option is configured for constraint %s', get_class($this)) |
|
109 ); |
|
110 } |
|
111 |
|
112 if (property_exists($this, $option)) { |
|
113 $this->$option = $options; |
|
114 unset($missingOptions[$option]); |
|
115 } else { |
|
116 $invalidOptions[] = $option; |
|
117 } |
|
118 } |
|
119 |
|
120 if (count($invalidOptions) > 0) { |
|
121 throw new InvalidOptionsException( |
|
122 sprintf('The options "%s" do not exist in constraint %s', implode('", "', $invalidOptions), get_class($this)), |
|
123 $invalidOptions |
|
124 ); |
|
125 } |
|
126 |
|
127 if (count($missingOptions) > 0) { |
|
128 throw new MissingOptionsException( |
|
129 sprintf('The options "%s" must be set for constraint %s', implode('", "', array_keys($missingOptions)), get_class($this)), |
|
130 array_keys($missingOptions) |
|
131 ); |
|
132 } |
|
133 |
|
134 $this->groups = (array) $this->groups; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Unsupported operation. |
|
139 */ |
|
140 public function __set($option, $value) |
|
141 { |
|
142 throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint %s', $option, get_class($this)), array($option)); |
|
143 } |
|
144 |
|
145 /** |
|
146 * Adds the given group if this constraint is in the Default group |
|
147 * |
|
148 * @param string $group |
|
149 * |
|
150 * @api |
|
151 */ |
|
152 public function addImplicitGroupName($group) |
|
153 { |
|
154 if (in_array(Constraint::DEFAULT_GROUP, $this->groups) && !in_array($group, $this->groups)) { |
|
155 $this->groups[] = $group; |
|
156 } |
|
157 } |
|
158 |
|
159 /** |
|
160 * Returns the name of the default option |
|
161 * |
|
162 * Override this method to define a default option. |
|
163 * |
|
164 * @return string |
|
165 * @see __construct() |
|
166 * |
|
167 * @api |
|
168 */ |
|
169 public function getDefaultOption() |
|
170 { |
|
171 return null; |
|
172 } |
|
173 |
|
174 /** |
|
175 * Returns the name of the required options |
|
176 * |
|
177 * Override this method if you want to define required options. |
|
178 * |
|
179 * @return array |
|
180 * @see __construct() |
|
181 * |
|
182 * @api |
|
183 */ |
|
184 public function getRequiredOptions() |
|
185 { |
|
186 return array(); |
|
187 } |
|
188 |
|
189 /** |
|
190 * Returns the name of the class that validates this constraint |
|
191 * |
|
192 * By default, this is the fully qualified name of the constraint class |
|
193 * suffixed with "Validator". You can override this method to change that |
|
194 * behaviour. |
|
195 * |
|
196 * @return string |
|
197 * |
|
198 * @api |
|
199 */ |
|
200 public function validatedBy() |
|
201 { |
|
202 return get_class($this).'Validator'; |
|
203 } |
|
204 |
|
205 /** |
|
206 * Returns whether the constraint can be put onto classes, properties or |
|
207 * both |
|
208 * |
|
209 * This method should return one or more of the constants |
|
210 * Constraint::CLASS_CONSTRAINT and Constraint::PROPERTY_CONSTRAINT. |
|
211 * |
|
212 * @return string|array One or more constant values |
|
213 * |
|
214 * @api |
|
215 */ |
|
216 public function getTargets() |
|
217 { |
|
218 return self::PROPERTY_CONSTRAINT; |
|
219 } |
|
220 } |