[CLEANUP] Rework/simplify copyright header and remove @package
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Property / PropertyMappingConfiguration.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Property;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Core\ClassLoader;
18
19 /**
20 * Concrete configuration object for the PropertyMapper.
21 *
22 * @api
23 */
24 class PropertyMappingConfiguration implements \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface {
25
26 /**
27 * Placeholder in property paths for multi-valued types
28 */
29 const PROPERTY_PATH_PLACEHOLDER = '*';
30
31 /**
32 * multi-dimensional array which stores type-converter specific configuration:
33 * 1. Dimension: Fully qualified class name of the type converter
34 * 2. Dimension: Configuration Key
35 * Value: Configuration Value
36 *
37 * @var array
38 */
39 protected $configuration;
40
41 /**
42 * Stores the configuration for specific child properties.
43 *
44 * @var array<\TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface>
45 */
46 protected $subConfigurationForProperty = array();
47
48 /**
49 * Keys which should be renamed
50 *
51 * @var array
52 */
53 protected $mapping = array();
54
55 /**
56 * @var \TYPO3\CMS\Extbase\Property\TypeConverterInterface
57 */
58 protected $typeConverter = NULL;
59
60 /**
61 * List of allowed property names to be converted
62 *
63 * @var array
64 */
65 protected $propertiesToBeMapped = array();
66
67 /**
68 * List of property names to be skipped during property mapping
69 *
70 * @var array
71 */
72 protected $propertiesToSkip = array();
73
74 /**
75 * List of disallowed property names which will be ignored while property mapping
76 *
77 * @var array
78 */
79 protected $propertiesNotToBeMapped = array();
80
81 /**
82 * If TRUE, unknown properties will be skipped during property mapping
83 *
84 * @var boolean
85 */
86 protected $skipUnknownProperties = FALSE;
87
88 /**
89 * If TRUE, unknown properties will be mapped.
90 *
91 * @var boolean
92 */
93 protected $mapUnknownProperties = FALSE;
94
95 /**
96 * The behavior is as follows:
97 *
98 * - if a property has been explicitly forbidden using allowAllPropertiesExcept(...), it is directly rejected
99 * - if a property has been allowed using allowProperties(...), it is directly allowed.
100 * - if allowAllProperties* has been called, we allow unknown properties
101 * - else, return FALSE.
102 *
103 * @param string $propertyName
104 * @return boolean TRUE if the given propertyName should be mapped, FALSE otherwise.
105 * @api
106 */
107 public function shouldMap($propertyName) {
108 if (isset($this->propertiesNotToBeMapped[$propertyName])) {
109 return FALSE;
110 }
111
112 if (isset($this->propertiesToBeMapped[$propertyName])) {
113 return TRUE;
114 }
115
116 if (isset($this->subConfigurationForProperty[self::PROPERTY_PATH_PLACEHOLDER])) {
117 return TRUE;
118 }
119
120 return $this->mapUnknownProperties;
121 }
122
123 /**
124 * Check if the given $propertyName should be skipped during mapping.
125 *
126 * @param string $propertyName
127 * @return boolean
128 * @api
129 */
130 public function shouldSkip($propertyName) {
131 return isset($this->propertiesToSkip[$propertyName]);
132 }
133
134 /**
135 * Allow all properties in property mapping, even unknown ones.
136 *
137 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
138 * @api
139 */
140 public function allowAllProperties() {
141 $this->mapUnknownProperties = TRUE;
142 return $this;
143 }
144
145 /**
146 * Allow a list of specific properties. All arguments of
147 * allowProperties are used here (varargs).
148 *
149 * Example: allowProperties('title', 'content', 'author')
150 *
151 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
152 * @api
153 */
154 public function allowProperties() {
155 foreach (func_get_args() as $propertyName) {
156 $this->propertiesToBeMapped[$propertyName] = $propertyName;
157 }
158 return $this;
159 }
160
161 /**
162 * Skip a list of specific properties. All arguments of
163 * skipProperties are used here (varargs).
164 *
165 * Example: skipProperties('unused', 'dummy')
166 *
167 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
168 * @api
169 */
170 public function skipProperties() {
171 foreach (func_get_args() as $propertyName) {
172 $this->propertiesToSkip[$propertyName] = $propertyName;
173 }
174 return $this;
175 }
176
177 /**
178 * Allow all properties during property mapping, but reject a few
179 * selected ones (blacklist).
180 *
181 * Example: allowAllPropertiesExcept('password', 'userGroup')
182 *
183 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
184 * @api
185 */
186 public function allowAllPropertiesExcept() {
187 $this->mapUnknownProperties = TRUE;
188
189 foreach (func_get_args() as $propertyName) {
190 $this->propertiesNotToBeMapped[$propertyName] = $propertyName;
191 }
192 return $this;
193 }
194
195 /**
196 * When this is enabled, properties that are disallowed will be skipped
197 * instead of triggering an error during mapping.
198 *
199 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
200 * @api
201 */
202 public function skipUnknownProperties() {
203 $this->skipUnknownProperties = TRUE;
204 return $this;
205 }
206
207 /**
208 * Whether unknown (unconfigured) properties should be skipped during
209 * mapping, instead if causing an error.
210 *
211 * @return boolean
212 * @api
213 */
214 public function shouldSkipUnknownProperties() {
215 return $this->skipUnknownProperties;
216 }
217
218 /**
219 * Returns the sub-configuration for the passed $propertyName. Must ALWAYS return a valid configuration object!
220 *
221 * @param string $propertyName
222 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface the property mapping configuration for the given $propertyName.
223 * @api
224 */
225 public function getConfigurationFor($propertyName) {
226 if (isset($this->subConfigurationForProperty[$propertyName])) {
227 return $this->subConfigurationForProperty[$propertyName];
228 } elseif (isset($this->subConfigurationForProperty[self::PROPERTY_PATH_PLACEHOLDER])) {
229 return $this->subConfigurationForProperty[self::PROPERTY_PATH_PLACEHOLDER];
230 }
231
232 return new PropertyMappingConfiguration();
233 }
234
235 /**
236 * Maps the given $sourcePropertyName to a target property name.
237 *
238 * @param string $sourcePropertyName
239 * @return string property name of target
240 * @api
241 */
242 public function getTargetPropertyName($sourcePropertyName) {
243 if (isset($this->mapping[$sourcePropertyName])) {
244 return $this->mapping[$sourcePropertyName];
245 }
246 return $sourcePropertyName;
247 }
248
249 /**
250 * @param string $typeConverterClassName
251 * @param string $key
252 * @return mixed configuration value for the specific $typeConverterClassName. Can be used by Type Converters to fetch converter-specific configuration.
253 * @api
254 */
255 public function getConfigurationValue($typeConverterClassName, $key) {
256 if (!isset($this->configuration[$typeConverterClassName][$key])) {
257 return NULL;
258 }
259
260 return $this->configuration[$typeConverterClassName][$key];
261 }
262
263 /**
264 * Define renaming from Source to Target property.
265 *
266 * @param string $sourcePropertyName
267 * @param string $targetPropertyName
268 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
269 * @api
270 */
271 public function setMapping($sourcePropertyName, $targetPropertyName) {
272 $this->mapping[$sourcePropertyName] = $targetPropertyName;
273 return $this;
274 }
275
276 /**
277 * Set all options for the given $typeConverter.
278 *
279 * @param string $typeConverter class name of type converter
280 * @param array $options
281 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
282 * @api
283 */
284 public function setTypeConverterOptions($typeConverter, array $options) {
285 if (strpos($typeConverter, '_') !== FALSE) {
286 $typeConverter = ClassLoader::getClassNameForAlias($typeConverter);
287 }
288 foreach ($this->getTypeConvertersWithParentClasses($typeConverter) as $typeConverter) {
289 $this->configuration[$typeConverter] = $options;
290 }
291 return $this;
292 }
293
294 /**
295 * Set a single option (denoted by $optionKey) for the given $typeConverter.
296 *
297 * @param string $typeConverter class name of type converter
298 * @param string $optionKey
299 * @param mixed $optionValue
300 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
301 * @api
302 */
303 public function setTypeConverterOption($typeConverter, $optionKey, $optionValue) {
304 if (strpos($typeConverter, '_') !== FALSE) {
305 $typeConverter = ClassLoader::getClassNameForAlias($typeConverter);
306 }
307 foreach ($this->getTypeConvertersWithParentClasses($typeConverter) as $typeConverter) {
308 $this->configuration[$typeConverter][$optionKey] = $optionValue;
309 }
310 return $this;
311 }
312
313 /**
314 * Get type converter classes including parents for the given type converter
315 *
316 * When setting an option on a subclassed type converter, this option must also be set on
317 * all its parent type converters.
318 *
319 * @param string $typeConverter The type converter class
320 * @return array Class names of type converters
321 */
322 protected function getTypeConvertersWithParentClasses($typeConverter) {
323 $typeConverterClasses = class_parents($typeConverter);
324 $typeConverterClasses = $typeConverterClasses === FALSE ? array() : $typeConverterClasses;
325 $typeConverterClasses[] = $typeConverter;
326 return $typeConverterClasses;
327 }
328
329 /**
330 * Returns the configuration for the specific property path, ready to be modified. Should be used
331 * inside a fluent interface like:
332 * $configuration->forProperty('foo.bar')->setTypeConverterOption(....)
333 *
334 * @param string $propertyPath
335 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration (or a subclass thereof)
336 * @api
337 */
338 public function forProperty($propertyPath) {
339 $splittedPropertyPath = explode('.', $propertyPath);
340 return $this->traverseProperties($splittedPropertyPath);
341 }
342
343 /**
344 * Traverse the property configuration. Only used by forProperty().
345 *
346 * @param array $splittedPropertyPath
347 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration (or a subclass thereof)
348 */
349 public function traverseProperties(array $splittedPropertyPath) {
350 if (count($splittedPropertyPath) === 0) {
351 return $this;
352 }
353
354 $currentProperty = array_shift($splittedPropertyPath);
355 if (!isset($this->subConfigurationForProperty[$currentProperty])) {
356 $type = get_class($this);
357 if (isset($this->subConfigurationForProperty[self::PROPERTY_PATH_PLACEHOLDER])) {
358 $this->subConfigurationForProperty[$currentProperty] = clone $this->subConfigurationForProperty[self::PROPERTY_PATH_PLACEHOLDER];
359 } else {
360 $this->subConfigurationForProperty[$currentProperty] = new $type;
361 }
362 }
363 return $this->subConfigurationForProperty[$currentProperty]->traverseProperties($splittedPropertyPath);
364 }
365
366 /**
367 * Return the type converter set for this configuration.
368 *
369 * @return \TYPO3\CMS\Extbase\Property\TypeConverterInterface
370 * @api
371 */
372 public function getTypeConverter() {
373 return $this->typeConverter;
374 }
375
376 /**
377 * Set a type converter which should be used for this specific conversion.
378 *
379 * @param \TYPO3\CMS\Extbase\Property\TypeConverterInterface $typeConverter
380 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration this
381 * @api
382 */
383 public function setTypeConverter(\TYPO3\CMS\Extbase\Property\TypeConverterInterface $typeConverter) {
384 $this->typeConverter = $typeConverter;
385 return $this;
386 }
387 }