TYPO3 CMS  TYPO3_8-7
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 = 10;
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  }
130  return $methodParameter['type'];
131  }
132  $methodParameters = $this->reflectionService->getMethodParameters($specificTargetType, '__construct');
133  if (isset($methodParameters[$propertyName]) && isset($methodParameters[$propertyName]['type'])) {
134  return $methodParameters[$propertyName]['type'];
135  }
136  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" had no setter or constructor argument in target object of type "' . $specificTargetType . '".', 1303379126);
137  }
138 
151  public function convertFrom($source, $targetType, array $convertedChildProperties = [], \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = null)
152  {
153  $object = $this->buildObject($convertedChildProperties, $targetType);
154  foreach ($convertedChildProperties as $propertyName => $propertyValue) {
155  $result = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue);
156  if ($result === false) {
157  $exceptionMessage = sprintf(
158  '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.',
159  $propertyName,
160  (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)),
162  );
163  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException($exceptionMessage, 1304538165);
164  }
165  }
166 
167  return $object;
168  }
169 
181  public function getTargetTypeForSource($source, $originalTargetType, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = null)
182  {
183  $targetType = $originalTargetType;
184 
185  if (is_array($source) && array_key_exists('__type', $source)) {
186  $targetType = $source['__type'];
187 
188  if ($configuration === null) {
189  throw new \InvalidArgumentException('A property mapping configuration must be given, not NULL.', 1326277369);
190  }
191  if ($configuration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\ObjectConverter::class, self::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED) !== true) {
192  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);
193  }
194 
195  if ($targetType !== $originalTargetType && is_a($targetType, $originalTargetType, true) === false) {
196  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidDataTypeException('The given type "' . $targetType . '" is not a subtype of "' . $originalTargetType . '".', 1317048056);
197  }
198  }
199 
200  return $targetType;
201  }
202 
213  protected function buildObject(array &$possibleConstructorArgumentValues, $objectType)
214  {
215  $specificObjectType = $this->objectContainer->getImplementationClassName($objectType);
216  if ($this->reflectionService->hasMethod($specificObjectType, '__construct')) {
217  $constructorSignature = $this->reflectionService->getMethodParameters($specificObjectType, '__construct');
218  $constructorArguments = [];
219  foreach ($constructorSignature as $constructorArgumentName => $constructorArgumentInformation) {
220  if (array_key_exists($constructorArgumentName, $possibleConstructorArgumentValues)) {
221  $constructorArguments[] = $possibleConstructorArgumentValues[$constructorArgumentName];
222  unset($possibleConstructorArgumentValues[$constructorArgumentName]);
223  } elseif ($constructorArgumentInformation['optional'] === true) {
224  $constructorArguments[] = $constructorArgumentInformation['defaultValue'];
225  } else {
226  throw new \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException('Missing constructor argument "' . $constructorArgumentName . '" for object of type "' . $objectType . '".', 1268734872);
227  }
228  }
229  return call_user_func_array([$this->objectManager, 'get'], array_merge([$objectType], $constructorArguments));
230  }
231  return $this->objectManager->get($objectType);
232  }
233 }
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)