/** * Expand shortened class names in "var" and "param" annotations, taking use statements into account. * * @param ClassReflection $class * @param string $type the type inside var/param annotation * @return string the possibly expanded type */ protected function expandType(ClassReflection $class, $type) { // expand "SomeType<SomeElementType>" to "\SomeTypeNamespace\SomeType<\ElementTypeNamespace\ElementType>" if (strpos($type, '<') !== false) { $typeParts = explode('<', $type); $type = $typeParts[0]; $elementType = rtrim($typeParts[1], '>'); return $this->expandType($class, $type) . '<' . $this->expandType($class, $elementType) . '>'; } // skip simple types and types with fully qualified namespaces if ($type === 'mixed' || $type[0] === '\\' || TypeHandling::isSimpleType($type)) { return TypeHandling::normalizeType($type); } // we try to find the class relative to the current namespace... $possibleFullyQualifiedClassName = sprintf('%s\\%s', $class->getNamespaceName(), $type); if (class_exists($possibleFullyQualifiedClassName) || interface_exists($possibleFullyQualifiedClassName)) { return $possibleFullyQualifiedClassName; } // and then we try to find "use" statements for the class. $className = $class->getName(); if (!isset($this->useStatementsForClassCache[$className])) { $this->useStatementsForClassCache[$className] = $this->getDoctrinePhpParser()->parseClass($class); } $useStatementsForClass = $this->useStatementsForClassCache[$className]; // ... and try to expand them $typeParts = explode('\\', $type, 2); $lowercasedFirstTypePart = strtolower($typeParts[0]); if (isset($useStatementsForClass[$lowercasedFirstTypePart])) { $typeParts[0] = $useStatementsForClass[$lowercasedFirstTypePart]; return implode('\\', $typeParts); } return $type; }
/** * @test * @dataProvider normalizeTypes */ public function normalizeTypesReturnsNormalizedType($type, $normalized) { $this->assertEquals(TypeHandling::normalizeType($type), $normalized); }
/** * Sets the data type of this argument that is also used for property mapping. * @param string $dataType * @return \TYPO3\Flow\Mvc\Controller\Argument $this */ public function setDataType($dataType) { $this->dataType = \TYPO3\Flow\Utility\TypeHandling::normalizeType($dataType); return $this; }
/** * @param string $operand * @param string $value * @return boolean TRUE if $value is of type $operand; FALSE otherwise */ protected function handleSimpleTypeOperand($operand, $value) { $operand = \TYPO3\Flow\Utility\TypeHandling::normalizeType($operand); if ($operand === 'object') { return is_object($value); } elseif ($operand === 'string') { return is_string($value); } elseif ($operand === 'integer') { return is_integer($value); } elseif ($operand === 'boolean') { return is_bool($value); } elseif ($operand === 'float') { return is_float($value); } elseif ($operand === 'array') { return is_array($value); } return false; }
/** * Determine the type converter to be used. If no converter has been found, an exception is raised. * * @param mixed $source * @param string $targetType * @param \TYPO3\Flow\Property\PropertyMappingConfigurationInterface $configuration * @return \TYPO3\Flow\Property\TypeConverterInterface Type Converter which should be used to convert between $source and $targetType. * @throws \TYPO3\Flow\Property\Exception\TypeConverterException * @throws \TYPO3\Flow\Property\Exception\InvalidTargetException */ protected function findTypeConverter($source, $targetType, \TYPO3\Flow\Property\PropertyMappingConfigurationInterface $configuration) { if ($configuration->getTypeConverter() !== null) { return $configuration->getTypeConverter(); } if (!is_string($targetType)) { throw new \TYPO3\Flow\Property\Exception\InvalidTargetException('The target type was no string, but of type "' . gettype($targetType) . '"', 1297941727); } $normalizedTargetType = TypeHandling::normalizeType($targetType); $truncatedTargetType = TypeHandling::truncateElementType($normalizedTargetType); $converter = null; $sourceTypes = $this->determineSourceTypes($source); foreach ($sourceTypes as $sourceType) { if (TypeHandling::isSimpleType($truncatedTargetType)) { if (isset($this->typeConverters[$sourceType][$truncatedTargetType])) { $converter = $this->findEligibleConverterWithHighestPriority($this->typeConverters[$sourceType][$truncatedTargetType], $source, $normalizedTargetType); } } else { $converter = $this->findFirstEligibleTypeConverterInObjectHierarchy($source, $sourceType, $normalizedTargetType); } if ($converter !== null) { return $converter; } } throw new \TYPO3\Flow\Property\Exception\TypeConverterException('No converter found which can be used to convert from "' . implode('" or "', $sourceTypes) . '" to "' . $normalizedTargetType . '".'); }
/** * Sets the data type of this argument that is also used for property mapping. * @param string $dataType * @return Argument $this * @deprecated Will be removed for next major Flow version. Set the DataType via constructor. */ public function setDataType($dataType) { $this->dataType = TypeHandling::normalizeType($dataType); return $this; }
/** * @param mixed $propertyValue * @param string $dataType * @return mixed * @throws PropertyException */ protected function convertValue($propertyValue, $dataType) { $rawType = TypeHandling::truncateElementType($dataType); // This hardcoded handling is to circumvent rewriting PropertyMappers that convert objects. Usually they expect the source to be an object already and break if not. if (!TypeHandling::isSimpleType($rawType) && !is_object($propertyValue) && !is_array($propertyValue)) { return null; } if ($rawType === 'array') { $conversionTargetType = 'array<string>'; } elseif (TypeHandling::isSimpleType($rawType)) { $conversionTargetType = TypeHandling::normalizeType($rawType); } else { $conversionTargetType = 'array'; } $propertyMappingConfiguration = $this->createConfiguration($dataType); $convertedValue = $this->propertyMapper->convert($propertyValue, $conversionTargetType, $propertyMappingConfiguration); if ($convertedValue instanceof \TYPO3\Flow\Error\Error) { throw new PropertyException($convertedValue->getMessage(), $convertedValue->getCode()); } return $convertedValue; }