‪TYPO3CMS  ‪main
PropertyMapper.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
24 
30 {
35 
36  public function ‪__construct(
37  protected ‪TypeConverterRegistry $typeConverterRegistry,
38  protected ‪PropertyMappingConfigurationBuilder $configurationBuilder
39  ) {
40  $this->‪resetMessages();
41  }
42 
52  public function ‪convert($source, string $targetType, ?‪PropertyMappingConfigurationInterface $configuration = null)
53  {
54  $configuration ??= $this->configurationBuilder->build();
55  $currentPropertyPath = [];
56  try {
57  $result = $this->‪doMapping($source, $targetType, $configuration, $currentPropertyPath);
58  if ($result instanceof ‪Error) {
59  return null;
60  }
61 
62  return $result;
63  } catch (‪TargetNotFoundException $e) {
64  throw $e;
65  } catch (\‪Exception $e) {
66  throw new ‪Exception('Exception while property mapping at property path "' . implode('.', $currentPropertyPath) . '": ' . $e->getMessage(), 1297759968, $e);
67  }
68  }
69 
73  public function ‪getMessages(): ‪Result
74  {
75  return ‪$this->messages;
76  }
77 
81  public function ‪resetMessages(): void
82  {
83  $this->messages = new ‪Result();
84  }
85 
105  protected function ‪doMapping($source, string $targetType, ‪PropertyMappingConfigurationInterface $configuration, array &$currentPropertyPath)
106  {
107  if (is_object($source)) {
108  $targetType = $this->‪parseCompositeType($targetType);
109  if ($source instanceof $targetType) {
110  return $source;
111  }
112  }
113 
114  $source ??= '';
115 
116  $typeConverter = $this->‪findTypeConverter($source, $targetType, $configuration);
117  $targetType = $typeConverter->getTargetTypeForSource($source, $targetType, $configuration);
118 
119  $convertedChildProperties = [];
120  foreach ($typeConverter->getSourceChildPropertiesToBeConverted($source) as $sourcePropertyName => $sourcePropertyValue) {
121  $targetPropertyName = $configuration->‪getTargetPropertyName($sourcePropertyName);
122  if ($configuration->‪shouldSkip($targetPropertyName)) {
123  continue;
124  }
125 
126  if (!$configuration->shouldMap($targetPropertyName)) {
127  if ($configuration->‪shouldSkipUnknownProperties()) {
128  continue;
129  }
130  throw new ‪InvalidPropertyMappingConfigurationException('It is not allowed to map property "' . $targetPropertyName . '". You need to use $propertyMappingConfiguration->allowProperties(\'' . $targetPropertyName . '\') to enable mapping of this property.', 1355155913);
131  }
132 
133  $targetPropertyType = $typeConverter->getTypeOfChildProperty($targetType, $targetPropertyName, $configuration);
134 
135  $subConfiguration = $configuration->getConfigurationFor($targetPropertyName);
136 
137  $currentPropertyPath[] = $targetPropertyName;
138  $targetPropertyValue = $this->doMapping($sourcePropertyValue, $targetPropertyType, $subConfiguration, $currentPropertyPath);
139  array_pop($currentPropertyPath);
140  if (!($targetPropertyValue instanceof Error)) {
141  $convertedChildProperties[$targetPropertyName] = $targetPropertyValue;
142  }
143  }
144  $result = $typeConverter->convertFrom($source, $targetType, $convertedChildProperties, $configuration);
145 
146  if ($result instanceof Error) {
147  $this->messages->forProperty(implode('.', $currentPropertyPath))->addError($result);
148  }
149 
150  return $result;
151  }
152 
166  protected function findTypeConverter($source, string $targetType, PropertyMappingConfigurationInterface $configuration): TypeConverterInterface
167  {
168  if ($configuration->getTypeConverter() !== null) {
169  return $configuration->getTypeConverter();
170  }
171 
172  $sourceType = $this->determineSourceType($source);
173 
174  $targetType = $this->parseCompositeType($targetType);
175  $targetType = TypeHandlingUtility::normalizeType($targetType);
176 
177  return $this->typeConverterRegistry->findTypeConverter($sourceType, $targetType);
178  }
179 
188  protected function determineSourceType($source): string
189  {
190  if (is_string($source)) {
191  return 'string';
192  }
193  if (is_array($source)) {
194  return 'array';
195  }
196  if (is_float($source)) {
197  return 'float';
198  }
199  if (is_int($source)) {
200  return 'integer';
201  }
202  if (is_bool($source)) {
203  return 'boolean';
204  }
205  throw new Exception\InvalidSourceException('The source is not of type string, array, float, integer or boolean, but of type "' . gettype($source) . '"', 1297773150);
206  }
207 
214  protected function parseCompositeType(string $compositeType): string
215  {
216  if (str_contains($compositeType, '<')) {
217  $compositeType = substr($compositeType, 0, (int)strpos($compositeType, '<'));
218  }
219  return $compositeType;
220  }
221 }
‪TYPO3\CMS\Extbase\Property\PropertyMapper\$messages
‪Result $messages
Definition: PropertyMapper.php:34
‪TYPO3\CMS\Extbase\Property\PropertyMapper\resetMessages
‪resetMessages()
Definition: PropertyMapper.php:81
‪TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface\getTargetPropertyName
‪string getTargetPropertyName($sourcePropertyName)
‪TYPO3\CMS\Extbase\Property
‪TYPO3\CMS\Extbase\Property\PropertyMapper\parseCompositeType
‪parseCompositeType(string $compositeType)
Definition: PropertyMapper.php:214
‪TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface
Definition: PropertyMappingConfigurationInterface.php:22
‪TYPO3\CMS\Extbase\Error\Result
Definition: Result.php:24
‪TYPO3\CMS\Extbase\Property\TypeConverterRegistry
Definition: TypeConverterRegistry.php:28
‪TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface\shouldSkip
‪bool shouldSkip($propertyName)
‪TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface\shouldSkipUnknownProperties
‪bool shouldSkipUnknownProperties()
‪TYPO3\CMS\Extbase\Error\Error
Definition: Error.php:25
‪TYPO3\CMS\Extbase\Utility\TypeHandlingUtility
Definition: TypeHandlingUtility.php:29
‪TYPO3\CMS\Extbase\Property\Exception
Definition: Exception.php:25
‪TYPO3\CMS\Extbase\Property\PropertyMapper
Definition: PropertyMapper.php:30
‪TYPO3\CMS\Extbase\Property\PropertyMapper\doMapping
‪mixed doMapping($source, string $targetType, PropertyMappingConfigurationInterface $configuration, array &$currentPropertyPath)
Definition: PropertyMapper.php:105
‪TYPO3\CMS\Extbase\Property\PropertyMapper\findTypeConverter
‪TypeConverterInterface findTypeConverter($source, string $targetType, PropertyMappingConfigurationInterface $configuration)
Definition: PropertyMapper.php:166
‪TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
Definition: InvalidPropertyMappingConfigurationException.php:25
‪TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder
Definition: PropertyMappingConfigurationBuilder.php:28
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪TYPO3\CMS\Extbase\Property\PropertyMapper\getMessages
‪getMessages()
Definition: PropertyMapper.php:73
‪TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException
Definition: TargetNotFoundException.php:25
‪TYPO3\CMS\Extbase\Property\PropertyMapper\__construct
‪__construct(protected TypeConverterRegistry $typeConverterRegistry, protected PropertyMappingConfigurationBuilder $configurationBuilder)
Definition: PropertyMapper.php:36
‪TYPO3\CMS\Extbase\Property\PropertyMapper\convert
‪mixed convert($source, string $targetType, ?PropertyMappingConfigurationInterface $configuration=null)
Definition: PropertyMapper.php:52