/** * Handle the case if $source is an array. * * @param array $source * @param string $targetType * @param array $convertedChildProperties * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return object * @throws \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException * @throws \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException */ protected function handleArrayData(array $source, $targetType, array &$convertedChildProperties, \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { $effectiveTargetType = $targetType; if (isset($source['__type'])) { if ($configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\PersistentObjectConverter', self::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED) !== TRUE) { throw new \TYPO3\FLOW3\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); } $effectiveTargetType = $source['__type']; } if (isset($source['__identity'])) { $object = $this->fetchObjectFromPersistence($source['__identity'], $effectiveTargetType); if (count($source) > 1 && ($configuration === NULL || $configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\PersistentObjectConverter', self::CONFIGURATION_MODIFICATION_ALLOWED) !== TRUE)) { throw new \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException('Modification of persistent objects not allowed. To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_MODIFICATION_ALLOWED" to TRUE.', 1297932028); } } else { if ($configuration === NULL || $configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\PersistentObjectConverter', self::CONFIGURATION_CREATION_ALLOWED) !== TRUE) { throw new \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException('Creation of objects not allowed. To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_CREATION_ALLOWED" to TRUE'); } $object = $this->buildObject($convertedChildProperties, $effectiveTargetType); } if ($effectiveTargetType !== $targetType && !$object instanceof $targetType) { throw new \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException('The given type "' . $effectiveTargetType . '" is not a subtype of "' . $targetType . '"', 1317048056); } return $object; }
/** * Helper method to collect configuration for this class. * * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @param array $configurationKeys * @return array */ protected function getConfigurationKeysAndValues(\TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration, array $configurationKeys) { $keysAndValues = array(); foreach ($configurationKeys as $configurationKey) { $keysAndValues[$configurationKey] = $configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\FloatConverter', $configurationKey); } return $keysAndValues; }
/** * 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\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return \TYPO3\FLOW3\Property\TypeConverterInterface Type Converter which should be used to convert between $source and $targetType. * @throws \TYPO3\FLOW3\Property\Exception\TypeConverterException * @throws \TYPO3\FLOW3\Property\Exception\InvalidTargetException */ protected function findTypeConverter($source, $targetType, \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration) { if ($configuration->getTypeConverter() !== NULL) { return $configuration->getTypeConverter(); } $sourceType = $this->determineSourceType($source); if (!is_string($targetType)) { throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('The target type was no string, but of type "' . gettype($targetType) . '"', 1297941727); } if (strpos($targetType, '<') !== FALSE) { $targetType = substr($targetType, 0, strpos($targetType, '<')); } $converter = NULL; if (\TYPO3\FLOW3\Utility\TypeHandling::isSimpleType($targetType)) { if (isset($this->typeConverters[$sourceType][$targetType])) { $converter = $this->findEligibleConverterWithHighestPriority($this->typeConverters[$sourceType][$targetType], $source, $targetType); } } else { $converter = $this->findFirstEligibleTypeConverterInObjectHierarchy($source, $sourceType, $targetType); } if ($converter === NULL) { throw new \TYPO3\FLOW3\Property\Exception\TypeConverterException('No converter found which can be used to convert from "' . $sourceType . '" to "' . $targetType . '".'); } return $converter; }
/** * Determines the default date format to use for the conversion. * If no format is specified in the mapping configuration DEFAULT_DATE_FORMAT is used. * * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return string * @throws \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException */ protected function getDefaultDateFormat(\TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { if ($configuration === NULL) { return self::DEFAULT_DATE_FORMAT; } $dateFormat = $configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\DateTimeConverter', self::CONFIGURATION_DATE_FORMAT); if ($dateFormat === NULL) { return self::DEFAULT_DATE_FORMAT; } elseif ($dateFormat !== NULL && !is_string($dateFormat)) { throw new \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException('CONFIGURATION_DATE_FORMAT must be of type string, "' . (is_object($dateFormat) ? get_class($dateFormat) : gettype($dateFormat)) . '" given', 1307719569); } return $dateFormat; }
/** * Converts the specified node path into a Node. * * The node path must be an absolute context node path and can be specified as a string or as an array item with the * key "__contextNodePath". The latter case is for updating existing nodes. * * This conversion method does not support / allow creation of new nodes because new nodes should be created through * the createNode() method of an existing reference node. * * Also note that the context's "current node" is not affected by this object converter, you will need to set it to * whatever node your "current" node is, if any. * * All elements in the source array which start with two underscores (like __contextNodePath) are specially treated * by this converter. * * All elements in the source array which start with a *single underscore (like _hidden) are *directly* set on the Node * object. * * All other elements, not being prefixed with underscore, are properties of the node. * * @param string|array $source Either a string or array containing the absolute context node path which identifies the node. For example "/sites/mysitecom/homepage/about@user-admin" * @param string $targetType not used * @param array $subProperties not used * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration not used * @return mixed An object or \TYPO3\FLOW3\Error\Error if the input format is not supported or could not be converted for other reasons * @throws \Exception */ public function convertFrom($source, $targetType, array $subProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { if (is_string($source)) { $source = array('__contextNodePath' => $source); } if (!is_array($source) || !isset($source['__contextNodePath'])) { return new Error('Could not convert ' . gettype($source) . ' to Node object, a valid absolute context node path as a string or array is expected.', 1302879936); } preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $source['__contextNodePath'], $matches); if (!isset($matches['NodePath'])) { return new Error('Could not convert array to Node object because the node path was invalid.', 1285162903); } $nodePath = $matches['NodePath']; if ($this->nodeRepository->getContext() === NULL) { $workspaceName = isset($matches['WorkspaceName']) ? $matches['WorkspaceName'] : 'live'; $contentContext = new ContentContext($workspaceName); $this->nodeRepository->setContext($contentContext); } else { $contentContext = $this->nodeRepository->getContext(); $workspaceName = $contentContext->getWorkspace()->getName(); } if ($workspaceName !== 'live') { $contentContext->setInvisibleContentShown(TRUE); if ($configuration->getConfigurationValue('TYPO3\\TYPO3\\Routing\\NodeObjectConverter', self::REMOVED_CONTENT_SHOWN) === TRUE) { $contentContext->setRemovedContentShown(TRUE); } } $workspace = $contentContext->getWorkspace(FALSE); if (!$workspace) { return new Error(sprintf('Could not convert %s to Node object because the workspace "%s" as specified in the context node path does not exist.', $source['__contextNodePath'], $workspaceName), 1285162905); } $currentAccessModeFromContext = $contentContext->isInaccessibleContentShown(); $contentContext->setInaccessibleContentShown(TRUE); $node = $contentContext->getNode($nodePath); $contentContext->setInaccessibleContentShown($currentAccessModeFromContext); if (!$node) { return new Error(sprintf('Could not convert array to Node object because the node "%s" does not exist.', $nodePath), 1285162908); } $contentTypeProperties = $node->getContentType()->getProperties(); foreach ($source as $nodePropertyKey => $nodePropertyValue) { if (substr($nodePropertyKey, 0, 2) === '__') { continue; } if ($nodePropertyKey[0] === '_') { $propertyName = substr($nodePropertyKey, 1); // TODO: Hack: we need to create DateTime objects for some properties of Node if (($propertyName === 'hiddenBeforeDateTime' || $propertyName === 'hiddenAfterDateTime') && is_string($nodePropertyValue)) { if ($nodePropertyValue !== '') { $nodePropertyValue = \DateTime::createFromFormat('!Y-m-d', $nodePropertyValue); } else { $nodePropertyValue = NULL; } } \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($node, $propertyName, $nodePropertyValue); } else { if (!isset($contentTypeProperties[$nodePropertyKey])) { throw new \Exception('TODO: content type XY does not have a property YY according to the schema'); } if (isset($contentTypeProperties[$nodePropertyKey]['type'])) { $targetType = $contentTypeProperties[$nodePropertyKey]['type']; if ($this->objectManager->isRegistered($targetType)) { $nodePropertyValue = $this->propertyMapper->convert(json_decode($nodePropertyValue, TRUE), $targetType); } } $node->setProperty($nodePropertyKey, $nodePropertyValue); } } return $node; }
/** * Convert an object from $source to an object. * * @param mixed $source * @param string $targetType * @param array $convertedChildProperties * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return object the target type * @throws \TYPO3\FLOW3\Property\Exception\InvalidTargetException * @throws \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException * @throws \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException */ public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { $effectiveTargetType = $targetType; if (isset($source['__type'])) { if ($configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\ObjectConverter', self::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED) !== TRUE) { throw new \TYPO3\FLOW3\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.', 1317051258); } $effectiveTargetType = $source['__type']; } $object = $this->buildObject($convertedChildProperties, $effectiveTargetType); if ($effectiveTargetType !== $targetType && !$object instanceof $targetType) { throw new \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException('The given type "' . $source['__type'] . '" is not a subtype of "' . $targetType . '"', 1317051266); } foreach ($convertedChildProperties as $propertyName => $propertyValue) { $result = \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue); if ($result === FALSE) { throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" having a value of type "' . (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)) . '" could not be set in target object of type "' . $targetType . '".', 1304538165); } } return $object; }