Pull merge.
[yaffs-website] / vendor / symfony / config / Definition / BaseNode.php
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\Config\Definition;
13
14 use Symfony\Component\Config\Definition\Exception\Exception;
15 use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
16 use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
17 use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
18
19 /**
20  * The base node class.
21  *
22  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
23  */
24 abstract class BaseNode implements NodeInterface
25 {
26     protected $name;
27     protected $parent;
28     protected $normalizationClosures = array();
29     protected $finalValidationClosures = array();
30     protected $allowOverwrite = true;
31     protected $required = false;
32     protected $deprecationMessage = null;
33     protected $equivalentValues = array();
34     protected $attributes = array();
35
36     /**
37      * @param string|null        $name   The name of the node
38      * @param NodeInterface|null $parent The parent of this node
39      *
40      * @throws \InvalidArgumentException if the name contains a period
41      */
42     public function __construct($name, NodeInterface $parent = null)
43     {
44         if (false !== strpos($name = (string) $name, '.')) {
45             throw new \InvalidArgumentException('The name must not contain ".".');
46         }
47
48         $this->name = $name;
49         $this->parent = $parent;
50     }
51
52     public function setAttribute($key, $value)
53     {
54         $this->attributes[$key] = $value;
55     }
56
57     public function getAttribute($key, $default = null)
58     {
59         return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
60     }
61
62     public function hasAttribute($key)
63     {
64         return isset($this->attributes[$key]);
65     }
66
67     public function getAttributes()
68     {
69         return $this->attributes;
70     }
71
72     public function setAttributes(array $attributes)
73     {
74         $this->attributes = $attributes;
75     }
76
77     public function removeAttribute($key)
78     {
79         unset($this->attributes[$key]);
80     }
81
82     /**
83      * Sets an info message.
84      *
85      * @param string $info
86      */
87     public function setInfo($info)
88     {
89         $this->setAttribute('info', $info);
90     }
91
92     /**
93      * Returns info message.
94      *
95      * @return string The info text
96      */
97     public function getInfo()
98     {
99         return $this->getAttribute('info');
100     }
101
102     /**
103      * Sets the example configuration for this node.
104      *
105      * @param string|array $example
106      */
107     public function setExample($example)
108     {
109         $this->setAttribute('example', $example);
110     }
111
112     /**
113      * Retrieves the example configuration for this node.
114      *
115      * @return string|array The example
116      */
117     public function getExample()
118     {
119         return $this->getAttribute('example');
120     }
121
122     /**
123      * Adds an equivalent value.
124      *
125      * @param mixed $originalValue
126      * @param mixed $equivalentValue
127      */
128     public function addEquivalentValue($originalValue, $equivalentValue)
129     {
130         $this->equivalentValues[] = array($originalValue, $equivalentValue);
131     }
132
133     /**
134      * Set this node as required.
135      *
136      * @param bool $boolean Required node
137      */
138     public function setRequired($boolean)
139     {
140         $this->required = (bool) $boolean;
141     }
142
143     /**
144      * Sets this node as deprecated.
145      *
146      * You can use %node% and %path% placeholders in your message to display,
147      * respectively, the node name and its complete path.
148      *
149      * @param string|null $message Deprecated message
150      */
151     public function setDeprecated($message)
152     {
153         $this->deprecationMessage = $message;
154     }
155
156     /**
157      * Sets if this node can be overridden.
158      *
159      * @param bool $allow
160      */
161     public function setAllowOverwrite($allow)
162     {
163         $this->allowOverwrite = (bool) $allow;
164     }
165
166     /**
167      * Sets the closures used for normalization.
168      *
169      * @param \Closure[] $closures An array of Closures used for normalization
170      */
171     public function setNormalizationClosures(array $closures)
172     {
173         $this->normalizationClosures = $closures;
174     }
175
176     /**
177      * Sets the closures used for final validation.
178      *
179      * @param \Closure[] $closures An array of Closures used for final validation
180      */
181     public function setFinalValidationClosures(array $closures)
182     {
183         $this->finalValidationClosures = $closures;
184     }
185
186     /**
187      * {@inheritdoc}
188      */
189     public function isRequired()
190     {
191         return $this->required;
192     }
193
194     /**
195      * Checks if this node is deprecated.
196      *
197      * @return bool
198      */
199     public function isDeprecated()
200     {
201         return null !== $this->deprecationMessage;
202     }
203
204     /**
205      * Returns the deprecated message.
206      *
207      * @param string $node the configuration node name
208      * @param string $path the path of the node
209      *
210      * @return string
211      */
212     public function getDeprecationMessage($node, $path)
213     {
214         return strtr($this->deprecationMessage, array('%node%' => $node, '%path%' => $path));
215     }
216
217     /**
218      * {@inheritdoc}
219      */
220     public function getName()
221     {
222         return $this->name;
223     }
224
225     /**
226      * {@inheritdoc}
227      */
228     public function getPath()
229     {
230         $path = $this->name;
231
232         if (null !== $this->parent) {
233             $path = $this->parent->getPath().'.'.$path;
234         }
235
236         return $path;
237     }
238
239     /**
240      * {@inheritdoc}
241      */
242     final public function merge($leftSide, $rightSide)
243     {
244         if (!$this->allowOverwrite) {
245             throw new ForbiddenOverwriteException(sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath()));
246         }
247
248         $this->validateType($leftSide);
249         $this->validateType($rightSide);
250
251         return $this->mergeValues($leftSide, $rightSide);
252     }
253
254     /**
255      * {@inheritdoc}
256      */
257     final public function normalize($value)
258     {
259         $value = $this->preNormalize($value);
260
261         // run custom normalization closures
262         foreach ($this->normalizationClosures as $closure) {
263             $value = $closure($value);
264         }
265
266         // replace value with their equivalent
267         foreach ($this->equivalentValues as $data) {
268             if ($data[0] === $value) {
269                 $value = $data[1];
270             }
271         }
272
273         // validate type
274         $this->validateType($value);
275
276         // normalize value
277         return $this->normalizeValue($value);
278     }
279
280     /**
281      * Normalizes the value before any other normalization is applied.
282      *
283      * @param $value
284      *
285      * @return $value The normalized array value
286      */
287     protected function preNormalize($value)
288     {
289         return $value;
290     }
291
292     /**
293      * Returns parent node for this node.
294      *
295      * @return NodeInterface|null
296      */
297     public function getParent()
298     {
299         return $this->parent;
300     }
301
302     /**
303      * {@inheritdoc}
304      */
305     final public function finalize($value)
306     {
307         $this->validateType($value);
308
309         $value = $this->finalizeValue($value);
310
311         // Perform validation on the final value if a closure has been set.
312         // The closure is also allowed to return another value.
313         foreach ($this->finalValidationClosures as $closure) {
314             try {
315                 $value = $closure($value);
316             } catch (Exception $e) {
317                 throw $e;
318             } catch (\Exception $e) {
319                 throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": %s', $this->getPath(), $e->getMessage()), $e->getCode(), $e);
320             }
321         }
322
323         return $value;
324     }
325
326     /**
327      * Validates the type of a Node.
328      *
329      * @param mixed $value The value to validate
330      *
331      * @throws InvalidTypeException when the value is invalid
332      */
333     abstract protected function validateType($value);
334
335     /**
336      * Normalizes the value.
337      *
338      * @param mixed $value The value to normalize
339      *
340      * @return mixed The normalized value
341      */
342     abstract protected function normalizeValue($value);
343
344     /**
345      * Merges two values together.
346      *
347      * @param mixed $leftSide
348      * @param mixed $rightSide
349      *
350      * @return mixed The merged value
351      */
352     abstract protected function mergeValues($leftSide, $rightSide);
353
354     /**
355      * Finalizes a value.
356      *
357      * @param mixed $value The value to finalize
358      *
359      * @return mixed The finalized value
360      */
361     abstract protected function finalizeValue($value);
362 }