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