TYPO3 CMS  TYPO3_6-2
PropertyMapper.php
Go to the documentation of this file.
1 <?php
3 
4 /* *
5  * This script belongs to the Extbase framework *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License as published by the *
9  * Free Software Foundation, either version 3 of the License, or (at your *
10  * option) any later version. *
11  * *
12  * This script is distributed in the hope that it will be useful, but *
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14  * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15  * General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU Lesser General Public *
18  * License along with the script. *
19  * If not, see http://www.gnu.org/licenses/lgpl.html *
20  * *
21  * The TYPO3 project - inspiring people to share! *
22  * */
23 
26 
35 
40  protected $objectManager;
41 
47 
58  protected $typeConverters = array();
59 
65  protected $messages;
66 
74  public function initializeObject() {
75  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters'] as $typeConverterClassName) {
76  $typeConverter = $this->objectManager->get($typeConverterClassName);
77  foreach ($typeConverter->getSupportedSourceTypes() as $supportedSourceType) {
78  if (isset($this->typeConverters[$supportedSourceType][$typeConverter->getSupportedTargetType()][$typeConverter->getPriority()])) {
79  throw new \TYPO3\CMS\Extbase\Property\Exception\DuplicateTypeConverterException('There exist at least two converters which handle the conversion from "' . $supportedSourceType . '" to "' . $typeConverter->getSupportedTargetType() . '" with priority "' . $typeConverter->getPriority() . '": ' . get_class($this->typeConverters[$supportedSourceType][$typeConverter->getSupportedTargetType()][$typeConverter->getPriority()]) . ' and ' . get_class($typeConverter), 1297951378);
80  }
81  $this->typeConverters[$supportedSourceType][$typeConverter->getSupportedTargetType()][$typeConverter->getPriority()] = $typeConverter;
82  }
83  }
84  }
85 
96  public function convert($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
97  if ($configuration === NULL) {
98  $configuration = $this->configurationBuilder->build();
99  }
100  $currentPropertyPath = array();
101  $this->messages = new \TYPO3\CMS\Extbase\Error\Result();
102  try {
103  $result = $this->doMapping($source, $targetType, $configuration, $currentPropertyPath);
104  if ($result instanceof \TYPO3\CMS\Extbase\Error\Error) {
105  return NULL;
106  }
107 
108  return $result;
109  } catch (TargetNotFoundException $e) {
110  throw $e;
111  } catch (\Exception $e) {
112  throw new \TYPO3\CMS\Extbase\Property\Exception('Exception while property mapping at property path "' . implode('.', $currentPropertyPath) . '":' . $e->getMessage(), 1297759968, $e);
113  }
114  }
115 
122  public function getMessages() {
123  return $this->messages;
124  }
125 
136  protected function doMapping($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration, &$currentPropertyPath) {
137  if (is_object($source)) {
138  $targetType = $this->parseCompositeType($targetType);
139  if ($source instanceof $targetType) {
140  return $source;
141  }
142  }
143 
144  if ($source === NULL) {
145  $source = '';
146  }
147 
148  $typeConverter = $this->findTypeConverter($source, $targetType, $configuration);
149  $targetType = $typeConverter->getTargetTypeForSource($source, $targetType, $configuration);
150 
151  if (!is_object($typeConverter) || !$typeConverter instanceof \TYPO3\CMS\Extbase\Property\TypeConverterInterface) {
152  throw new \TYPO3\CMS\Extbase\Property\Exception\TypeConverterException('Type converter for "' . $source . '" -> "' . $targetType . '" not found.');
153  }
154 
155  $convertedChildProperties = array();
156  foreach ($typeConverter->getSourceChildPropertiesToBeConverted($source) as $sourcePropertyName => $sourcePropertyValue) {
157  $targetPropertyName = $configuration->getTargetPropertyName($sourcePropertyName);
158  if ($configuration->shouldSkip($targetPropertyName)) {
159  continue;
160  }
161 
162  if (!$configuration->shouldMap($targetPropertyName)) {
163  if ($configuration->shouldSkipUnknownProperties()) {
164  continue;
165  }
166  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException('It is not allowed to map property "' . $targetPropertyName . '". You need to use $propertyMappingConfiguration->allowProperties(\'' . $targetPropertyName . '\') to enable mapping of this property.', 1355155913);
167  }
168 
169  $targetPropertyType = $typeConverter->getTypeOfChildProperty($targetType, $targetPropertyName, $configuration);
170 
171  $subConfiguration = $configuration->getConfigurationFor($targetPropertyName);
172 
173  $currentPropertyPath[] = $targetPropertyName;
174  $targetPropertyValue = $this->doMapping($sourcePropertyValue, $targetPropertyType, $subConfiguration, $currentPropertyPath);
175  array_pop($currentPropertyPath);
176  if (!($targetPropertyValue instanceof \TYPO3\CMS\Extbase\Error\Error)) {
177  $convertedChildProperties[$targetPropertyName] = $targetPropertyValue;
178  }
179  }
180  $result = $typeConverter->convertFrom($source, $targetType, $convertedChildProperties, $configuration);
181 
182  if ($result instanceof \TYPO3\CMS\Extbase\Error\Error) {
183  $this->messages->forProperty(implode('.', $currentPropertyPath))->addError($result);
184  }
185 
186  return $result;
187  }
188 
199  protected function findTypeConverter($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration) {
200  if ($configuration->getTypeConverter() !== NULL) {
201  return $configuration->getTypeConverter();
202  }
203 
204  $sourceType = $this->determineSourceType($source);
205 
206  if (!is_string($targetType)) {
207  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('The target type was no string, but of type "' . gettype($targetType) . '"', 1297941727);
208  }
209 
210  $targetType = $this->parseCompositeType($targetType);
211  // This is needed to correctly convert old class names to new ones
212  // This compatibility layer will be removed with 7.0
213  $targetType = \TYPO3\CMS\Core\Core\ClassLoader::getClassNameForAlias($targetType);
214 
215  $targetType = TypeHandlingUtility::normalizeType($targetType);
216 
217  $converter = NULL;
218 
219  if (TypeHandlingUtility::isSimpleType($targetType)) {
220  if (isset($this->typeConverters[$sourceType][$targetType])) {
221  $converter = $this->findEligibleConverterWithHighestPriority($this->typeConverters[$sourceType][$targetType], $source, $targetType);
222  }
223  } else {
224  $converter = $this->findFirstEligibleTypeConverterInObjectHierarchy($source, $sourceType, $targetType);
225  }
226 
227  if ($converter === NULL) {
228  throw new \TYPO3\CMS\Extbase\Property\Exception\TypeConverterException('No converter found which can be used to convert from "' . $sourceType . '" to "' . $targetType . '".');
229  }
230 
231  return $converter;
232  }
233 
243  protected function findFirstEligibleTypeConverterInObjectHierarchy($source, $sourceType, $targetClass) {
244  if (!class_exists($targetClass) && !interface_exists($targetClass)) {
245  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Could not find a suitable type converter for "' . $targetClass . '" because no such class or interface exists.', 1297948764);
246  }
247 
248  if (!isset($this->typeConverters[$sourceType])) {
249  return NULL;
250  }
251 
252  $convertersForSource = $this->typeConverters[$sourceType];
253  if (isset($convertersForSource[$targetClass])) {
254  $converter = $this->findEligibleConverterWithHighestPriority($convertersForSource[$targetClass], $source, $targetClass);
255  if ($converter !== NULL) {
256  return $converter;
257  }
258  }
259 
260  foreach (class_parents($targetClass) as $parentClass) {
261  if (!isset($convertersForSource[$parentClass])) {
262  continue;
263  }
264 
265  $converter = $this->findEligibleConverterWithHighestPriority($convertersForSource[$parentClass], $source, $targetClass);
266  if ($converter !== NULL) {
267  return $converter;
268  }
269  }
270 
271  $converters = $this->getConvertersForInterfaces($convertersForSource, class_implements($targetClass));
272  $converter = $this->findEligibleConverterWithHighestPriority($converters, $source, $targetClass);
273 
274  if ($converter !== NULL) {
275  return $converter;
276  }
277  if (isset($convertersForSource['object'])) {
278  return $this->findEligibleConverterWithHighestPriority($convertersForSource['object'], $source, $targetClass);
279  } else {
280  return NULL;
281  }
282  }
283 
290  protected function findEligibleConverterWithHighestPriority($converters, $source, $targetType) {
291  if (!is_array($converters)) {
292  return NULL;
293  }
294  krsort($converters);
295  reset($converters);
296  foreach ($converters as $converter) {
297  if ($converter->canConvertFrom($source, $targetType)) {
298  return $converter;
299  }
300  }
301  return NULL;
302  }
303 
310  protected function getConvertersForInterfaces(array $convertersForSource, array $interfaceNames) {
311  $convertersForInterface = array();
312  foreach ($interfaceNames as $implementedInterface) {
313  if (isset($convertersForSource[$implementedInterface])) {
314  foreach ($convertersForSource[$implementedInterface] as $priority => $converter) {
315  if (isset($convertersForInterface[$priority])) {
316  throw new \TYPO3\CMS\Extbase\Property\Exception\DuplicateTypeConverterException('There exist at least two converters which handle the conversion to an interface with priority "' . $priority . '". ' . get_class($convertersForInterface[$priority]) . ' and ' . get_class($converter), 1297951338);
317  }
318  $convertersForInterface[$priority] = $converter;
319  }
320  }
321  }
322  return $convertersForInterface;
323  }
324 
332  protected function determineSourceType($source) {
333  if (is_string($source)) {
334  return 'string';
335  } elseif (is_array($source)) {
336  return 'array';
337  } elseif (is_float($source)) {
338  return 'float';
339  } elseif (is_integer($source)) {
340  return 'integer';
341  } elseif (is_bool($source)) {
342  return 'boolean';
343  } else {
344  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidSourceException('The source is not of type string, array, float, integer or boolean, but of type "' . gettype($source) . '"', 1297773150);
345  }
346  }
347 
355  public function parseCompositeType($compositeType) {
356  if (strpos($compositeType, '<') !== FALSE) {
357  $compositeType = substr($compositeType, 0, strpos($compositeType, '<'));
358  }
359  return $compositeType;
360  }
361 
362 }
findEligibleConverterWithHighestPriority($converters, $source, $targetType)
doMapping($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration, &$currentPropertyPath)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
findTypeConverter($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
getConvertersForInterfaces(array $convertersForSource, array $interfaceNames)
convert($source, $targetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration=NULL)