/Classes/Property/TypeConverter/ObjectConverter.php

https://github.com/arbyte/FLOW3-X-TYPO3.FLOW3 · PHP · 176 lines · 73 code · 20 blank · 83 comment · 12 complexity · 07db818b74e09aa360ab99048dffe7d2 MD5 · raw file

  1. <?php
  2. namespace TYPO3\FLOW3\Property\TypeConverter;
  3. /* *
  4. * This script belongs to the FLOW3 framework. *
  5. * *
  6. * It is free software; you can redistribute it and/or modify it under *
  7. * the terms of the GNU Lesser General Public License, either version 3 *
  8. * of the License, or (at your option) any later version. *
  9. * *
  10. * The TYPO3 project - inspiring people to share! *
  11. * */
  12. use TYPO3\FLOW3\Annotations as FLOW3;
  13. /**
  14. * This converter transforms arrays to simple objects (POPO) by setting properties.
  15. *
  16. * @api
  17. * @FLOW3\Scope("singleton")
  18. */
  19. class ObjectConverter extends \TYPO3\FLOW3\Property\TypeConverter\AbstractTypeConverter {
  20. /**
  21. * @var integer
  22. */
  23. const CONFIGURATION_TARGET_TYPE = 3;
  24. /**
  25. * @var array
  26. */
  27. protected $sourceTypes = array('array');
  28. /**
  29. * @var strng
  30. */
  31. protected $targetType = 'object';
  32. /**
  33. * @var integer
  34. */
  35. protected $priority = 0;
  36. /**
  37. * @var \TYPO3\FLOW3\Object\ObjectManagerInterface
  38. */
  39. protected $objectManager;
  40. /**
  41. * @var \TYPO3\FLOW3\Reflection\ReflectionService
  42. */
  43. protected $reflectionService;
  44. /**
  45. * @param \TYPO3\FLOW3\Object\ObjectManagerInterface $objectManager
  46. * @return void
  47. */
  48. public function injectObjectManager(\TYPO3\FLOW3\Object\ObjectManagerInterface $objectManager) {
  49. $this->objectManager = $objectManager;
  50. }
  51. /**
  52. * @param \TYPO3\FLOW3\Reflection\ReflectionService $reflectionService
  53. * @return void
  54. */
  55. public function injectReflectionService(\TYPO3\FLOW3\Reflection\ReflectionService $reflectionService) {
  56. $this->reflectionService = $reflectionService;
  57. }
  58. /**
  59. * Only convert non-persistent types
  60. *
  61. * @param mixed $source
  62. * @param string $targetType
  63. * @return boolean
  64. */
  65. public function canConvertFrom($source, $targetType) {
  66. $isValueObject = $this->reflectionService->isClassTaggedWith($targetType, 'valueobject');
  67. $isEntity = $this->reflectionService->isClassTaggedWith($targetType, 'entity');
  68. return !($isEntity || $isValueObject);
  69. }
  70. /**
  71. * Convert all properties in the source array
  72. *
  73. * @param mixed $source
  74. * @return array
  75. */
  76. public function getSourceChildPropertiesToBeConverted($source) {
  77. return $source;
  78. }
  79. /**
  80. * The type of a property is determined by the reflection service.
  81. *
  82. * @param string $targetType
  83. * @param string $propertyName
  84. * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration
  85. * @return string
  86. */
  87. public function getTypeOfChildProperty($targetType, $propertyName, \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration) {
  88. $configuredTargetType = $configuration->getConfigurationFor($propertyName)->getConfigurationValue('TYPO3\FLOW3\Property\TypeConverter\ObjectConverter', self::CONFIGURATION_TARGET_TYPE);
  89. if ($configuredTargetType !== NULL) {
  90. return $configuredTargetType;
  91. }
  92. if ($this->reflectionService->hasMethod($targetType, \TYPO3\FLOW3\Reflection\ObjectAccess::buildSetterMethodName($propertyName))) {
  93. $methodParameters = $this->reflectionService->getMethodParameters($targetType, \TYPO3\FLOW3\Reflection\ObjectAccess::buildSetterMethodName($propertyName));
  94. $methodParameter = current($methodParameters);
  95. if (!isset($methodParameter['type'])) {
  96. throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Setter for property "' . $propertyName . '" had no type hint or documentation in target object of type "' . $targetType . '".', 1303379158);
  97. } else {
  98. return $methodParameter['type'];
  99. }
  100. } else {
  101. $methodParameters = $this->reflectionService->getMethodParameters($targetType, '__construct');
  102. if (isset($methodParameters[$propertyName]) && isset($methodParameters[$propertyName]['type'])) {
  103. return $methodParameters[$propertyName]['type'];
  104. } else {
  105. throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" had no setter or constructor argument in target object of type "' . $targetType . '".', 1303379126);
  106. }
  107. }
  108. }
  109. /**
  110. * Convert an object from $source to an object.
  111. *
  112. * @param mixed $source
  113. * @param string $targetType
  114. * @param array $convertedChildProperties
  115. * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration
  116. * @return object the target type
  117. */
  118. public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
  119. $object = $this->buildObject($convertedChildProperties, $targetType);
  120. foreach ($convertedChildProperties as $propertyName => $propertyValue) {
  121. $result = \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue);
  122. if ($result === FALSE) {
  123. throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" could not be set in target object of type "' . $targetType . '".', 1304538165);
  124. }
  125. }
  126. return $object;
  127. }
  128. /**
  129. * Builds a new instance of $objectType with the given $possibleConstructorArgumentValues.
  130. * If constructor argument values are missing from the given array the method looks for a
  131. * default value in the constructor signature.
  132. *
  133. * Furthermore, the constructor arguments are removed from $possibleConstructorArgumentValues
  134. *
  135. * @param array &$possibleConstructorArgumentValues
  136. * @param string $objectType
  137. * @return object The created instance
  138. * @throws \TYPO3\FLOW3\Property\Exception\InvalidTargetException if a required constructor argument is missing
  139. */
  140. protected function buildObject(array &$possibleConstructorArgumentValues, $objectType) {
  141. $constructorSignature = $this->reflectionService->getMethodParameters($objectType, '__construct');
  142. $constructorArguments = array();
  143. foreach ($constructorSignature as $constructorArgumentName => $constructorArgumentInformation) {
  144. if (array_key_exists($constructorArgumentName, $possibleConstructorArgumentValues)) {
  145. $constructorArguments[] = $possibleConstructorArgumentValues[$constructorArgumentName];
  146. unset($possibleConstructorArgumentValues[$constructorArgumentName]);
  147. } elseif ($constructorArgumentInformation['optional'] === TRUE) {
  148. $constructorArguments[] = $constructorArgumentInformation['defaultValue'];
  149. } else {
  150. throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Missing constructor argument "' . $constructorArgumentName . '" for object of type "' . $objectType . '".' , 1304538168);
  151. }
  152. }
  153. return call_user_func_array(array($this->objectManager, 'create'), array_merge(array($objectType), $constructorArguments));
  154. }
  155. }
  156. ?>