TYPO3 CMS  TYPO3_7-6
ObjectConverter.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  * */
29 {
34 
39 
43  protected $sourceTypes = ['array'];
44 
48  protected $targetType = 'object';
49 
53  protected $priority = 0;
54 
58  protected $objectContainer;
59 
63  protected $reflectionService;
64 
68  public function injectObjectContainer(\TYPO3\CMS\Extbase\Object\Container\Container $objectContainer)
69  {
70  $this->objectContainer = $objectContainer;
71  }
72 
76  public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
77  {
78  $this->reflectionService = $reflectionService;
79  }
80 
88  public function canConvertFrom($source, $targetType)
89  {
90  return !is_subclass_of($targetType, \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject::class);
91  }
92 
99  public function getSourceChildPropertiesToBeConverted($source)
100  {
101  if (isset($source['__type'])) {
102  unset($source['__type']);
103  }
104  return $source;
105  }
106 
116  public function getTypeOfChildProperty($targetType, $propertyName, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration)
117  {
118  $configuredTargetType = $configuration->getConfigurationFor($propertyName)->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\ObjectConverter::class, self::CONFIGURATION_TARGET_TYPE);
119  if ($configuredTargetType !== null) {
120  return $configuredTargetType;
121  }
122 
123  $specificTargetType = $this->objectContainer->getImplementationClassName($targetType);
124  if ($this->reflectionService->hasMethod($specificTargetType, \TYPO3\CMS\Extbase\Reflection\ObjectAccess::buildSetterMethodName($propertyName))) {
125  $methodParameters = $this->reflectionService->getMethodParameters($specificTargetType, \TYPO3\CMS\Extbase\Reflection\ObjectAccess::buildSetterMethodName($propertyName));
126  $methodParameter = current($methodParameters);
127  if (!isset($methodParameter['type'])) {
128  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Setter for property "' . $propertyName . '" had no type hint or documentation in target object of type "' . $specificTargetType . '".', 1303379158);
129  } else {
130  return $methodParameter['type'];
131  }
132  } else {
133  $methodParameters = $this->reflectionService->getMethodParameters($specificTargetType, '__construct');
134  if (isset($methodParameters[$propertyName]) && isset($methodParameters[$propertyName]['type'])) {
135  return $methodParameters[$propertyName]['type'];
136  } else {
137  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" had no setter or constructor argument in target object of type "' . $specificTargetType . '".', 1303379126);
138  }
139  }
140  }
141 
154  public function convertFrom($source, $targetType, array $convertedChildProperties = [], \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = null)
155  {
156  $object = $this->buildObject($convertedChildProperties, $targetType);
157  foreach ($convertedChildProperties as $propertyName => $propertyValue) {
158  $result = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue);
159  if ($result === false) {
160  $exceptionMessage = sprintf(
161  'Property "%s" having a value of type "%s" could not be set in target object of type "%s". Make sure that the property is accessible properly, for example via an appropriate setter method.',
162  $propertyName,
163  (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)),
165  );
166  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException($exceptionMessage, 1304538165);
167  }
168  }
169 
170  return $object;
171  }
172 
184  public function getTargetTypeForSource($source, $originalTargetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = null)
185  {
186  $targetType = $originalTargetType;
187 
188  if (is_array($source) && array_key_exists('__type', $source)) {
189  $targetType = $source['__type'];
190 
191  if ($configuration === null) {
192  throw new \InvalidArgumentException('A property mapping configuration must be given, not NULL.', 1326277369);
193  }
194  if ($configuration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\ObjectConverter::class, self::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED) !== true) {
195  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException('Override of target type not allowed. To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED" to TRUE.', 1317050430);
196  }
197 
198  if ($targetType !== $originalTargetType && is_a($targetType, $originalTargetType, true) === false) {
199  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidDataTypeException('The given type "' . $targetType . '" is not a subtype of "' . $originalTargetType . '".', 1317048056);
200  }
201  }
202 
203  return $targetType;
204  }
205 
216  protected function buildObject(array &$possibleConstructorArgumentValues, $objectType)
217  {
218  $specificObjectType = $this->objectContainer->getImplementationClassName($objectType);
219  if ($this->reflectionService->hasMethod($specificObjectType, '__construct')) {
220  $constructorSignature = $this->reflectionService->getMethodParameters($specificObjectType, '__construct');
221  $constructorArguments = [];
222  foreach ($constructorSignature as $constructorArgumentName => $constructorArgumentInformation) {
223  if (array_key_exists($constructorArgumentName, $possibleConstructorArgumentValues)) {
224  $constructorArguments[] = $possibleConstructorArgumentValues[$constructorArgumentName];
225  unset($possibleConstructorArgumentValues[$constructorArgumentName]);
226  } elseif ($constructorArgumentInformation['optional'] === true) {
227  $constructorArguments[] = $constructorArgumentInformation['defaultValue'];
228  } else {
229  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Missing constructor argument "' . $constructorArgumentName . '" for object of type "' . $objectType . '".', 1268734872);
230  }
231  }
232  return call_user_func_array([$this->objectManager, 'get'], array_merge([$objectType], $constructorArguments));
233  } else {
234  return $this->objectManager->get($objectType);
235  }
236  }
237 }
injectObjectContainer(\TYPO3\CMS\Extbase\Object\Container\Container $objectContainer)
getTypeOfChildProperty($targetType, $propertyName, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration)
injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
convertFrom($source, $targetType, array $convertedChildProperties=[], \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration=null)
buildObject(array &$possibleConstructorArgumentValues, $objectType)
static setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess=false)
getTargetTypeForSource($source, $originalTargetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration=null)