/** * Convert raw property values to the correct type according to a node type configuration * * @param NodeType $nodeType * @param string $propertyName * @param string $rawValue * @param Context $context * @return mixed */ public function convert(NodeType $nodeType, $propertyName, $rawValue, Context $context) { $propertyType = $nodeType->getPropertyType($propertyName); switch ($propertyType) { case 'string': return $rawValue; case 'reference': return $this->convertReference($rawValue, $context); case 'references': return $this->convertReferences($rawValue, $context); case 'DateTime': return $this->convertDateTime($rawValue); case 'integer': return $this->convertInteger($rawValue); case 'boolean': return $this->convertBoolean($rawValue); case 'array': return $this->convertArray($rawValue); default: $innerType = $propertyType; if ($propertyType !== null) { try { $parsedType = \TYPO3\Flow\Utility\TypeHandling::parseType($propertyType); $innerType = $parsedType['elementType'] ?: $parsedType['type']; } catch (\TYPO3\Flow\Utility\Exception\InvalidTypeException $exception) { } } if (is_string($rawValue) && $this->objectManager->isRegistered($innerType) && $rawValue !== '') { return $this->propertyMapper->convert(json_decode($rawValue, true), $propertyType, $configuration); } } }
/** * Change the property on the given node. * * @param NodeData $node * @return void */ public function execute(NodeData $node) { foreach ($node->getNodeType()->getProperties() as $propertyName => $propertyConfiguration) { if (isset($propertyConfiguration['type']) && in_array(trim($propertyConfiguration['type']), $this->getHandledObjectTypes())) { if (!isset($nodeProperties)) { $nodeRecordQuery = $this->entityManager->getConnection()->prepare('SELECT properties FROM typo3_typo3cr_domain_model_nodedata WHERE persistence_object_identifier=?'); $nodeRecordQuery->execute([$this->persistenceManager->getIdentifierByObject($node)]); $nodeRecord = $nodeRecordQuery->fetch(\PDO::FETCH_ASSOC); $nodeProperties = unserialize($nodeRecord['properties']); } if (!isset($nodeProperties[$propertyName]) || !is_object($nodeProperties[$propertyName])) { continue; } /** @var Asset $assetObject */ $assetObject = $nodeProperties[$propertyName]; $nodeProperties[$propertyName] = null; $stream = $assetObject->getResource()->getStream(); if ($stream === false) { continue; } fclose($stream); $objectType = TypeHandling::getTypeForValue($assetObject); $objectIdentifier = ObjectAccess::getProperty($assetObject, 'Persistence_Object_Identifier', true); $nodeProperties[$propertyName] = array('__flow_object_type' => $objectType, '__identifier' => $objectIdentifier); } } if (isset($nodeProperties)) { $nodeUpdateQuery = $this->entityManager->getConnection()->prepare('UPDATE typo3_typo3cr_domain_model_nodedata SET properties=? WHERE persistence_object_identifier=?'); $nodeUpdateQuery->execute([serialize($nodeProperties), $this->persistenceManager->getIdentifierByObject($node)]); } }
public function render() { $value = $this->renderChildren(); $type = str_replace('\\', '_', TypeHandling::getTypeForValue($value)); $type = $type == "NULL" ? "Null" : $type; return $type; }
/** * @param Mapping $mapping * @param string $className * @param string $propertyName * * @throws \Flowpack\ElasticSearch\Exception * @return void */ protected function augmentMappingByProperty(Mapping $mapping, $className, $propertyName) { list($propertyType) = $this->reflectionService->getPropertyTagValues($className, $propertyName, 'var'); if (($transformAnnotation = $this->reflectionService->getPropertyAnnotation($className, $propertyName, 'Flowpack\\ElasticSearch\\Annotations\\Transform')) !== NULL) { $mappingType = $this->transformerFactory->create($transformAnnotation->type)->getTargetMappingType(); } elseif (\TYPO3\Flow\Utility\TypeHandling::isSimpleType($propertyType)) { $mappingType = $propertyType; } elseif ($propertyType === '\\DateTime') { $mappingType = 'date'; } else { throw new \Flowpack\ElasticSearch\Exception('Mapping is only supported for simple types and DateTime objects; "' . $propertyType . '" given but without a Transform directive.'); } $mapping->setPropertyByPath($propertyName, array('type' => $mappingType)); $annotation = $this->reflectionService->getPropertyAnnotation($className, $propertyName, 'Flowpack\\ElasticSearch\\Annotations\\Mapping'); if ($annotation instanceof MappingAnnotation) { $mapping->setPropertyByPath($propertyName, $this->processMappingAnnotation($annotation, $mapping->getPropertyByPath($propertyName))); if ($annotation->getFields()) { foreach ($annotation->getFields() as $multiFieldAnnotation) { $multiFieldIndexName = trim($multiFieldAnnotation->index_name); if ($multiFieldIndexName === '') { throw new \Flowpack\ElasticSearch\Exception('Multi field require an unique index name "' . $className . '::' . $propertyName . '".'); } if (isset($multiFields[$multiFieldIndexName])) { throw new \Flowpack\ElasticSearch\Exception('Duplicate index name in the same multi field is not allowed "' . $className . '::' . $propertyName . '".'); } $multiFieldAnnotation->type = $mappingType; $multiFields[$multiFieldIndexName] = $this->processMappingAnnotation($multiFieldAnnotation); } $mapping->setPropertyByPath(array($propertyName, 'fields'), $multiFields); } } }
/** * Updates the username and password credentials from the POST vars, if the POST parameters * are available. Sets the authentication status to REAUTHENTICATION_NEEDED, if credentials have been sent. * * @param \TYPO3\Flow\Mvc\ActionRequest $actionRequest The current action request instance * @return void */ public function updateCredentials(\TYPO3\Flow\Mvc\ActionRequest $actionRequest) { $getArguments = $actionRequest->getArguments(); if (!empty($getArguments['user']) && !empty($getArguments['signature']) && !empty($getArguments['expires']) && !empty($getArguments['version']) && !empty($getArguments['tpa_id']) && !empty($getArguments['action']) && !empty($getArguments['flags']) && !empty($getArguments['userdata'])) { $this->credentials['username'] = $getArguments['user']; $this->credentials['signature'] = \TYPO3\Flow\Utility\TypeHandling::hex2bin($getArguments['signature']); $this->credentials['expires'] = $getArguments['expires']; $this->credentials['version'] = $getArguments['version']; $this->credentials['tpaId'] = $getArguments['tpa_id']; $this->credentials['action'] = $getArguments['action']; $this->credentials['flags'] = $getArguments['flags']; $this->credentials['userdata'] = $getArguments['userdata']; $this->setAuthenticationStatus(self::AUTHENTICATION_NEEDED); } }
/** * Convert an object from \TYPO3\Media\Domain\Model\ImageInterface to a json representation * * @param ImageInterface $source * @param string $targetType must be 'string' * @param array $convertedChildProperties * @param PropertyMappingConfigurationInterface $configuration * @return string|Error The converted Image, a Validation Error or NULL */ public function convertFrom($source, $targetType, array $convertedChildProperties = array(), PropertyMappingConfigurationInterface $configuration = null) { $data = array('__identity' => $this->persistenceManager->getIdentifierByObject($source), '__type' => TypeHandling::getTypeForValue($source)); if ($source instanceof ImageVariant) { $data['originalAsset'] = ['__identity' => $this->persistenceManager->getIdentifierByObject($source->getOriginalAsset())]; $adjustments = array(); foreach ($source->getAdjustments() as $adjustment) { $index = TypeHandling::getTypeForValue($adjustment); $adjustments[$index] = array(); foreach (ObjectAccess::getGettableProperties($adjustment) as $propertyName => $propertyValue) { $adjustments[$index][$propertyName] = $propertyValue; } } $data['adjustments'] = $adjustments; } return $data; }
/** * Checks if the given value is valid according to the validator, and returns * the Error Messages object which occurred. * * @param mixed $value The value that should be validated * @return \TYPO3\Flow\Error\Result * @api */ public function validate($value) { $this->result = new \TYPO3\Flow\Error\Result(); if ($this->acceptsEmptyValues === false || $this->isEmpty($value) === false) { if ($value instanceof \Doctrine\ORM\PersistentCollection && !$value->isInitialized()) { return $this->result; } elseif (is_object($value) && !\TYPO3\Flow\Utility\TypeHandling::isCollectionType(get_class($value)) && !is_array($value)) { $this->addError('The given subject was not a collection.', 1317204797); return $this->result; } elseif (is_object($value) && $this->isValidatedAlready($value)) { return $this->result; } else { $this->isValid($value); } } return $this->result; }
/** * Convert raw property values to the correct type according to a node type configuration * * @param NodeType $nodeType * @param string $propertyName * @param string $rawValue * @param Context $context * @return mixed */ public function convert(NodeType $nodeType, $propertyName, $rawValue, Context $context) { $propertyType = $nodeType->getPropertyType($propertyName); switch ($propertyType) { case 'string': return $rawValue; case 'reference': return $this->convertReference($rawValue, $context); case 'references': return $this->convertReferences($rawValue, $context); case 'DateTime': return $this->convertDateTime($rawValue); case 'integer': return $this->convertInteger($rawValue); case 'boolean': return $this->convertBoolean($rawValue); case 'array': return $this->convertArray($rawValue); default: $innerType = $propertyType; if ($propertyType !== null) { try { $parsedType = \TYPO3\Flow\Utility\TypeHandling::parseType($propertyType); $innerType = $parsedType['elementType'] ?: $parsedType['type']; } catch (\TYPO3\Flow\Utility\Exception\InvalidTypeException $exception) { } } if ((is_string($rawValue) || is_array($rawValue)) && $this->objectManager->isRegistered($innerType) && $rawValue !== '') { $propertyMappingConfiguration = new MvcPropertyMappingConfiguration(); $propertyMappingConfiguration->allowOverrideTargetType(); $propertyMappingConfiguration->allowAllProperties(); $propertyMappingConfiguration->skipUnknownProperties(); $propertyMappingConfiguration->setTypeConverterOption('TYPO3\\Flow\\Property\\TypeConverter\\PersistentObjectConverter', \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED, true); $propertyMappingConfiguration->setTypeConverterOption('TYPO3\\Flow\\Property\\TypeConverter\\PersistentObjectConverter', \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, true); return $this->propertyMapper->convert($rawValue, $propertyType, $propertyMappingConfiguration); } else { return $rawValue; } } }
/** * An onFlush event listener used to validate entities upon persistence. * * @param \Doctrine\ORM\Event\OnFlushEventArgs $eventArgs * @return void */ public function onFlush(\Doctrine\ORM\Event\OnFlushEventArgs $eventArgs) { $unitOfWork = $this->entityManager->getUnitOfWork(); $entityInsertions = $unitOfWork->getScheduledEntityInsertions(); $validatedInstancesContainer = new \SplObjectStorage(); $knownValueObjects = array(); foreach ($entityInsertions as $entity) { $className = TypeHandling::getTypeForValue($entity); if ($this->reflectionService->getClassSchema($className)->getModelType() === ClassSchema::MODELTYPE_VALUEOBJECT) { $identifier = $this->getIdentifierByObject($entity); if (isset($knownValueObjects[$className][$identifier]) || $unitOfWork->getEntityPersister($className)->exists($entity)) { unset($entityInsertions[spl_object_hash($entity)]); continue; } $knownValueObjects[$className][$identifier] = true; } $this->validateObject($entity, $validatedInstancesContainer); } \TYPO3\Flow\Reflection\ObjectAccess::setProperty($unitOfWork, 'entityInsertions', $entityInsertions, true); foreach ($unitOfWork->getScheduledEntityUpdates() as $entity) { $this->validateObject($entity, $validatedInstancesContainer); } }
/** * Delete an asset * * @param \TYPO3\Media\Domain\Model\Asset $asset * @return void */ public function deleteAction(\TYPO3\Media\Domain\Model\Asset $asset) { $relationMap = []; $relationMap[TypeHandling::getTypeForValue($asset)] = array($this->persistenceManager->getIdentifierByObject($asset)); if ($asset instanceof \TYPO3\Media\Domain\Model\Image) { foreach ($asset->getVariants() as $variant) { $type = TypeHandling::getTypeForValue($variant); if (!isset($relationMap[$type])) { $relationMap[$type] = []; } $relationMap[$type][] = $this->persistenceManager->getIdentifierByObject($variant); } } $relatedNodes = $this->nodeDataRepository->findNodesByRelatedEntities($relationMap); if (count($relatedNodes) > 0) { $this->addFlashMessage('Asset could not be deleted, because there are still Nodes using it.', '', Message::SEVERITY_WARNING, array(), 1412422767); $this->redirect('index'); } // FIXME: Resources are not deleted, because we cannot be sure that the resource isn't used anywhere else. $this->assetRepository->remove($asset); $this->addFlashMessage(sprintf('Asset "%s" has been deleted.', $asset->getLabel()), null, null, array(), 1412375050); $this->redirect('index'); }
/** * Checks if the given value is a unique entity depending on it's identity properties or * custom configured identity properties. * * @param mixed $value The value that should be validated * @return void * @throws \TYPO3\Flow\Validation\Exception\InvalidValidationOptionsException * @api */ protected function isValid($value) { if (!is_object($value)) { throw new InvalidValidationOptionsException('The value supplied for the UniqueEntityValidator must be an object.', 1358454270); } $classSchema = $this->reflectionService->getClassSchema(TypeHandling::getTypeForValue($value)); if ($classSchema === null || $classSchema->getModelType() !== \TYPO3\Flow\Reflection\ClassSchema::MODELTYPE_ENTITY) { throw new InvalidValidationOptionsException('The object supplied for the UniqueEntityValidator must be an entity.', 1358454284); } if ($this->options['identityProperties'] !== null) { $identityProperties = $this->options['identityProperties']; foreach ($identityProperties as $propertyName) { if ($classSchema->hasProperty($propertyName) === false) { throw new InvalidValidationOptionsException(sprintf('The custom identity property name "%s" supplied for the UniqueEntityValidator does not exists in "%s".', $propertyName, $classSchema->getClassName()), 1358960500); } } } else { $identityProperties = array_keys($classSchema->getIdentityProperties()); } if (count($identityProperties) === 0) { throw new InvalidValidationOptionsException('The object supplied for the UniqueEntityValidator must have at least one identity property.', 1358459831); } $identifierProperties = $this->reflectionService->getPropertyNamesByAnnotation($classSchema->getClassName(), 'Doctrine\\ORM\\Mapping\\Id'); if (count($identifierProperties) > 1) { throw new InvalidValidationOptionsException('The object supplied for the UniqueEntityValidator must only have one identifier property @ORM\\Id.', 1358501745); } $identifierPropertyName = count($identifierProperties) > 0 ? array_shift($identifierProperties) : 'Persistence_Object_Identifier'; $query = $this->persistenceManager->createQueryForType($classSchema->getClassName()); $constraints = array($query->logicalNot($query->equals($identifierPropertyName, $this->persistenceManager->getIdentifierByObject($value)))); foreach ($identityProperties as $propertyName) { $constraints[] = $query->equals($propertyName, ObjectAccess::getProperty($value, $propertyName)); } if ($query->matching($query->logicalAnd($constraints))->count() > 0) { $this->addError('Another entity with the same unique identifiers already exists', 1355785874); } }
/** * Convert an object from $source to an entity or a value object. * * @param mixed $source * @param string $targetType * @param array $convertedChildProperties * @param PropertyMappingConfigurationInterface $configuration * @return object|TargetNotFoundError the converted entity/value object or an instance of TargetNotFoundError if the object could not be resolved * @throws \InvalidArgumentException|InvalidTargetException */ public function convertFrom($source, $targetType, array $convertedChildProperties = array(), PropertyMappingConfigurationInterface $configuration = null) { if (is_array($source)) { if ($this->reflectionService->isClassAnnotatedWith($targetType, \TYPO3\Flow\Annotations\ValueObject::class)) { // Unset identity for value objects to use constructor mapping, since the identity is determined from // property values after construction unset($source['__identity']); } $object = $this->handleArrayData($source, $targetType, $convertedChildProperties, $configuration); if ($object instanceof TargetNotFoundError) { return $object; } } elseif (is_string($source)) { if ($source === '') { return null; } $object = $this->fetchObjectFromPersistence($source, $targetType); if ($object === null) { return new TargetNotFoundError(sprintf('Object of type "%s" with identity "%s" not found.', $targetType, $source), 1412283033); } } else { throw new \InvalidArgumentException('Only strings and arrays are accepted.', 1305630314); } $objectConstructorArguments = $this->getConstructorArgumentsForClass(TypeHandling::getTypeForValue($object)); foreach ($convertedChildProperties as $propertyName => $propertyValue) { // We need to check for "immutable" constructor arguments that have no setter and remove them. if (isset($objectConstructorArguments[$propertyName]) && !ObjectAccess::isPropertySettable($object, $propertyName)) { $currentPropertyValue = ObjectAccess::getProperty($object, $propertyName); if ($currentPropertyValue === $propertyValue) { continue; } else { $exceptionMessage = sprintf('Property "%s" having a value of type "%s" could not be set in target object of type "%s". The property has no setter and is not equal to the value in the object, in that case it would have been skipped.', $propertyName, is_object($propertyValue) ? TypeHandling::getTypeForValue($propertyValue) : gettype($propertyValue), $targetType); throw new InvalidTargetException($exceptionMessage, 1421498771); } } $result = ObjectAccess::setProperty($object, $propertyName, $propertyValue); if ($result === false) { $exceptionMessage = sprintf('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.', $propertyName, is_object($propertyValue) ? TypeHandling::getTypeForValue($propertyValue) : gettype($propertyValue), $targetType); throw new InvalidTargetException($exceptionMessage, 1297935345); } } return $object; }
/** * @test * @dataProvider convertCallsCanConvertFromWithTheFullNormalizedTargetTypeDataProvider */ public function convertCallsCanConvertFromWithTheFullNormalizedTargetType($source, $fullTargetType) { $mockTypeConverter = $this->getMockTypeConverter(); $mockTypeConverter->expects($this->atLeastOnce())->method('canConvertFrom')->with($source, $fullTargetType); $truncatedTargetType = TypeHandling::truncateElementType($fullTargetType); $mockTypeConverters = array(gettype($source) => array($truncatedTargetType => array(1 => $mockTypeConverter))); $propertyMapper = $this->getAccessibleMock('TYPO3\\Flow\\Property\\PropertyMapper', array('dummy')); $propertyMapper->_set('typeConverters', $mockTypeConverters); $mockConfiguration = $this->getMockBuilder('TYPO3\\Flow\\Property\\PropertyMappingConfiguration')->disableOriginalConstructor()->getMock(); $propertyMapper->convert($source, $fullTargetType, $mockConfiguration); // dummy assertion to avoid PHPUnit warning $this->assertTrue(TRUE); }
/** * @param ClassSchema $classSchema * @param string $propertyName * @return boolean * @throws InvalidPropertyTypeException * @throws \InvalidArgumentException */ protected function evaluateClassPropertyAnnotationsForSchema(ClassSchema $classSchema, $propertyName) { $skipArtificialIdentity = false; $className = $classSchema->getClassName(); if ($this->isPropertyAnnotatedWith($className, $propertyName, Flow\Transient::class)) { return false; } if ($this->isPropertyAnnotatedWith($className, $propertyName, Flow\Inject::class)) { return false; } if (!$this->isPropertyTaggedWith($className, $propertyName, 'var')) { return false; } $varTagValues = $this->getPropertyTagValues($className, $propertyName, 'var'); if (count($varTagValues) > 1) { throw new InvalidPropertyTypeException('More than one @var annotation given for "' . $className . '::$' . $propertyName . '"', 1367334366); } $declaredType = strtok(trim(current($varTagValues), " \n\t"), " \n\t"); try { TypeHandling::parseType($declaredType); } catch (InvalidTypeException $exception) { throw new \InvalidArgumentException(sprintf($exception->getMessage(), 'class "' . $className . '" for property "' . $propertyName . '"'), 1315564475); } if ($this->isPropertyAnnotatedWith($className, $propertyName, ORM\Id::class)) { $skipArtificialIdentity = true; } $classSchema->addProperty($propertyName, $declaredType, $this->isPropertyAnnotatedWith($className, $propertyName, Flow\Lazy::class), $this->isPropertyAnnotatedWith($className, $propertyName, Flow\Transient::class)); if ($this->isPropertyAnnotatedWith($className, $propertyName, Flow\Identity::class)) { $classSchema->markAsIdentityProperty($propertyName); } return $skipArtificialIdentity; }
/** * Returns a greater than or equal criterion used for matching objects against a query * * @param string $propertyName The name of the property to compare against * @param mixed $operand The value to compare with * @return \TYPO3\Flow\Persistence\Generic\Qom\Comparison * @throws \TYPO3\Flow\Persistence\Exception\InvalidQueryException if used on a multi-valued property or with a non-literal/non-DateTime operand * @api */ public function greaterThanOrEqual($propertyName, $operand) { if ($this->classSchema->isMultiValuedProperty($propertyName)) { throw new \TYPO3\Flow\Persistence\Exception\InvalidQueryException('Property "' . $propertyName . '" must not be multi-valued', 1276774883); } if (!$operand instanceof \DateTime && !\TYPO3\Flow\Utility\TypeHandling::isLiteral(gettype($operand))) { throw new \TYPO3\Flow\Persistence\Exception\InvalidQueryException('Operand must be a literal or DateTime, was ' . gettype($operand), 1276774884); } return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, '_entity'), \TYPO3\Flow\Persistence\QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand); }
/** * Tries to find a suitable type converter for the given source and target type. * * @param string $source The actual source value * @param string $sourceType Type of the source to convert from * @param string $targetType Name of the target type to find a type converter for * @return mixed Either the matching object converter or NULL * @throws \TYPO3\Flow\Property\Exception\InvalidTargetException */ protected function findFirstEligibleTypeConverterInObjectHierarchy($source, $sourceType, $targetType) { $targetClass = TypeHandling::truncateElementType($targetType); if (!class_exists($targetClass) && !interface_exists($targetClass)) { throw new \TYPO3\Flow\Property\Exception\InvalidTargetException(sprintf('Could not find a suitable type converter for "%s" because no such the class/interface "%s" does not exist.', $targetType, $targetClass), 1297948764); } if (!isset($this->typeConverters[$sourceType])) { return null; } $convertersForSource = $this->typeConverters[$sourceType]; if (isset($convertersForSource[$targetClass])) { $converter = $this->findEligibleConverterWithHighestPriority($convertersForSource[$targetClass], $source, $targetType); if ($converter !== null) { return $converter; } } foreach (class_parents($targetClass) as $parentClass) { if (!isset($convertersForSource[$parentClass])) { continue; } $converter = $this->findEligibleConverterWithHighestPriority($convertersForSource[$parentClass], $source, $targetType); if ($converter !== null) { return $converter; } } $converters = $this->getConvertersForInterfaces($convertersForSource, class_implements($targetClass)); $converter = $this->findEligibleConverterWithHighestPriority($converters, $source, $targetType); if ($converter !== null) { return $converter; } if (isset($convertersForSource['object'])) { return $this->findEligibleConverterWithHighestPriority($convertersForSource['object'], $source, $targetType); } else { return null; } }
/** * Iterates through the given $properties setting them on the specified $node using the appropriate TypeConverters. * * @param object $nodeLike * @param NodeType $nodeType * @param array $properties * @param TYPO3CRContext $context * @param PropertyMappingConfigurationInterface $configuration * @return void * @throws TypeConverterException */ protected function setNodeProperties($nodeLike, NodeType $nodeType, array $properties, TYPO3CRContext $context, PropertyMappingConfigurationInterface $configuration = null) { $nodeTypeProperties = $nodeType->getProperties(); unset($properties['_lastPublicationDateTime']); foreach ($properties as $nodePropertyName => $nodePropertyValue) { if (substr($nodePropertyName, 0, 2) === '__') { continue; } $nodePropertyType = isset($nodeTypeProperties[$nodePropertyName]['type']) ? $nodeTypeProperties[$nodePropertyName]['type'] : null; switch ($nodePropertyType) { case 'reference': $nodePropertyValue = $context->getNodeByIdentifier($nodePropertyValue); break; case 'references': $nodeIdentifiers = json_decode($nodePropertyValue); $nodePropertyValue = array(); if (is_array($nodeIdentifiers)) { foreach ($nodeIdentifiers as $nodeIdentifier) { $referencedNode = $context->getNodeByIdentifier($nodeIdentifier); if ($referencedNode !== null) { $nodePropertyValue[] = $referencedNode; } } } elseif ($nodeIdentifiers !== null) { throw new TypeConverterException(sprintf('node type "%s" expects an array of identifiers for its property "%s"', $nodeType->getName(), $nodePropertyName), 1383587419); } break; case 'DateTime': if ($nodePropertyValue !== '' && ($nodePropertyValue = \DateTime::createFromFormat(\DateTime::W3C, $nodePropertyValue)) !== false) { $nodePropertyValue->setTimezone(new \DateTimeZone(date_default_timezone_get())); } else { $nodePropertyValue = null; } break; case 'integer': $nodePropertyValue = intval($nodePropertyValue); break; case 'boolean': if (is_string($nodePropertyValue)) { $nodePropertyValue = $nodePropertyValue === 'true' ? true : false; } break; case 'array': $nodePropertyValue = json_decode($nodePropertyValue, true); break; } if (substr($nodePropertyName, 0, 1) === '_') { $nodePropertyName = substr($nodePropertyName, 1); ObjectAccess::setProperty($nodeLike, $nodePropertyName, $nodePropertyValue); continue; } if (!isset($nodeTypeProperties[$nodePropertyName])) { if ($configuration !== null && $configuration->shouldSkipUnknownProperties()) { continue; } else { throw new TypeConverterException(sprintf('Node type "%s" does not have a property "%s" according to the schema', $nodeType->getName(), $nodePropertyName), 1359552744); } } $innerType = $nodePropertyType; if ($nodePropertyType !== null) { try { $parsedType = TypeHandling::parseType($nodePropertyType); $innerType = $parsedType['elementType'] ?: $parsedType['type']; } catch (InvalidTypeException $exception) { } } if (is_string($nodePropertyValue) && $this->objectManager->isRegistered($innerType) && $nodePropertyValue !== '') { $nodePropertyValue = $this->propertyMapper->convert(json_decode($nodePropertyValue, true), $nodePropertyType, $configuration); } $nodeLike->setProperty($nodePropertyName, $nodePropertyValue); } }
/** * @test * @dataProvider collectionTypes */ public function isCollectionTypeReturnsTrueForCollectionType($type, $expected) { $this->assertSame($expected, TypeHandling::isCollectionType($type), 'Failed for ' . $type); }
/** * 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; }
/** * @return void */ protected function initializeConverters() { $this->resourceInformation = array(); foreach ($this->reflectionService->getAllImplementationClassNamesForInterface(ResourceInformationInterface::class) as $resourceInformationClassName) { $this->resourceInformation[] = $this->objectManager->get($resourceInformationClassName); } usort($this->resourceInformation, function (ResourceInformationInterface $first, ResourceInformationInterface $second) { if ($first->getPriority() == $second->getPriority()) { return strcmp(TypeHandling::getTypeForValue($first), TypeHandling::getTypeForValue($second)); } else { return $first->getPriority() < $second->getPriority(); } }); }
/** * @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; }
/** * @return string */ public function getType() { return TypeHandling::getTypeForValue($this->getPayload()); }
/** * Return the type of a given sub-property inside the $targetType * * @param string $targetType * @param string $propertyName * @param PropertyMappingConfigurationInterface $configuration * @return string */ public function getTypeOfChildProperty($targetType, $propertyName, PropertyMappingConfigurationInterface $configuration) { $parsedTargetType = TypeHandling::parseType($targetType); return $parsedTargetType['elementType']; }
/** * Traverses the $array and replaces known persisted objects with a tuple of * type and identifier. * * @param array $array * @return void * @throws \RuntimeException */ protected function encodeObjectReferences(array &$array) { foreach ($array as &$value) { if (is_array($value)) { $this->encodeObjectReferences($value); } if (!is_object($value) || is_object($value) && $value instanceof DependencyProxy) { continue; } $propertyClassName = TypeHandling::getTypeForValue($value); if ($value instanceof \DateTimeInterface) { $value = array('date' => $value->format('Y-m-d H:i:s.u'), 'timezone' => $value->format('e'), 'dateFormat' => 'Y-m-d H:i:s.u'); } elseif ($value instanceof \SplObjectStorage) { throw new \RuntimeException('SplObjectStorage in array properties is not supported', 1375196580); } elseif ($value instanceof \Doctrine\Common\Collections\Collection) { throw new \RuntimeException('Collection in array properties is not supported', 1375196581); } elseif ($value instanceof \ArrayObject) { throw new \RuntimeException('ArrayObject in array properties is not supported', 1375196582); } elseif ($this->persistenceManager->isNewObject($value) === false && ($this->reflectionService->isClassAnnotatedWith($propertyClassName, \TYPO3\Flow\Annotations\Entity::class) || $this->reflectionService->isClassAnnotatedWith($propertyClassName, \TYPO3\Flow\Annotations\ValueObject::class) || $this->reflectionService->isClassAnnotatedWith($propertyClassName, 'Doctrine\\ORM\\Mapping\\Entity'))) { $value = array('__flow_object_type' => $propertyClassName, '__identifier' => $this->persistenceManager->getIdentifierByObject($value)); } } }
/** * Tells if the value of the specified property can be retrieved by this Object Accessor. * * @param object $object Object containing the property * @param string $propertyName Name of the property to check * @return boolean * @throws \InvalidArgumentException */ public static function isPropertyGettable($object, $propertyName) { if (!is_object($object)) { throw new \InvalidArgumentException('$object must be an object, ' . gettype($object) . ' given.', 1259828921); } if ($object instanceof \ArrayAccess && isset($object[$propertyName]) === true) { return true; } elseif ($object instanceof \stdClass && array_search($propertyName, array_keys(get_object_vars($object))) !== false) { return true; } $uppercasePropertyName = ucfirst($propertyName); if (is_callable(array($object, 'get' . $uppercasePropertyName))) { return true; } if (is_callable(array($object, 'is' . $uppercasePropertyName))) { return true; } if (is_callable(array($object, 'has' . $uppercasePropertyName))) { return true; } $className = TypeHandling::getTypeForValue($object); return array_search($propertyName, array_keys(get_class_vars($className))) !== false; }
/** * @param \TYPO3\Media\Domain\Model\Asset $asset * @return array */ protected function getRelatedNodes(\TYPO3\Media\Domain\Model\Asset $asset) { $relationMap = []; $relationMap[TypeHandling::getTypeForValue($asset)] = [$this->persistenceManager->getIdentifierByObject($asset)]; if ($asset instanceof \TYPO3\Media\Domain\Model\Image) { foreach ($asset->getVariants() as $variant) { $type = TypeHandling::getTypeForValue($variant); if (!isset($relationMap[$type])) { $relationMap[$type] = []; } $relationMap[$type][] = $this->persistenceManager->getIdentifierByObject($variant); } } return $this->nodeDataRepository->findNodesByRelatedEntities($relationMap); }
/** * Finds a package by a given object of that package; if no such package * could be found, NULL is returned. This basically works with comparing the package class' namespace * against the fully qualified class name of the given $object. * In order to not being satisfied with a shorter package's namespace, the packages to check are sorted * by the length of their namespace descending. * * @param object $object The object to find the possessing package of * @return PackageInterface The package the given object belongs to or NULL if it could not be found * @deprecated */ public function getPackageOfObject($object) { return $this->getPackageByClassName(TypeHandling::getTypeForValue($object)); }
private function buildNodeProperty(NodeInterface $node, $propertyName, $dataType) { if (substr($propertyName, 0, 1) === '_') { $propertyValue = ObjectAccess::getProperty($node, substr($propertyName, 1)); } else { $propertyValue = $node->getProperty($propertyName); } // Enforce an integer value for integer properties as otherwise javascript will give NaN and VIE converts it to an array containing 16 times 'NaN' if ($dataType === 'integer') { $propertyValue = (int) $propertyValue; } // Serialize boolean values to String if ($dataType === 'boolean') { return $propertyValue ? 'true' : 'false'; } // Serialize array values to String if ($dataType === 'array') { return $propertyValue; } // Serialize date values to String if ($dataType === 'DateTime') { if (!$propertyValue instanceof \DateTimeInterface) { return ''; } $value = clone $propertyValue; return $value->setTimezone(new \DateTimeZone('UTC'))->format(\DateTime::W3C); } // Serialize node references to node identifiers if ($dataType === 'references') { $nodeIdentifiers = array(); if (is_array($propertyValue)) { /** @var $subNode NodeInterface */ foreach ($propertyValue as $subNode) { $nodeIdentifiers[] = $subNode->getIdentifier(); } } return $nodeIdentifiers; } // Serialize node reference to node identifier if ($dataType === 'reference') { if ($propertyValue instanceof NodeInterface) { return $propertyValue->getIdentifier(); } else { return ''; } } if ($propertyValue instanceof \TYPO3\Media\Domain\Model\ImageInterface) { $propertyMappingConfiguration = new \TYPO3\Flow\Property\PropertyMappingConfiguration(); return $this->entityToIdentityConverter->convertFrom($propertyValue, 'array', array(), $propertyMappingConfiguration); } // Serialize an Asset to JSON (the NodeConverter expects JSON for object type properties) if ($dataType === ltrim('TYPO3\\Media\\Domain\\Model\\Asset', '\\') && $propertyValue !== null) { if ($propertyValue instanceof \TYPO3\Media\Domain\Model\Asset) { return $this->persistenceManager->getIdentifierByObject($propertyValue); } } // Serialize an array of Assets to JSON if (is_array($propertyValue)) { $parsedType = \TYPO3\Flow\Utility\TypeHandling::parseType($dataType); if ($parsedType['elementType'] === ltrim('TYPO3\\Media\\Domain\\Model\\Asset', '\\')) { $convertedValues = array(); foreach ($propertyValue as $singlePropertyValue) { if ($singlePropertyValue instanceof \TYPO3\Media\Domain\Model\Asset) { $convertedValues[] = $this->persistenceManager->getIdentifierByObject($singlePropertyValue); } } return $convertedValues; } } return $propertyValue === null ? '' : $propertyValue; }
/** * Convert a value to the internal object data format * * @param string $identifier The object's identifier * @param object $object The object with the property to flatten * @param string $propertyName The name of the property * @param array $propertyMetaData The property metadata * @param array $propertyData Reference to the property data array * @return void * @api */ protected function flattenValue($identifier, $object, $propertyName, array $propertyMetaData, array &$propertyData) { $propertyValue = \TYPO3\Flow\Reflection\ObjectAccess::getProperty($object, $propertyName, true); if ($propertyValue instanceof \TYPO3\Flow\Persistence\Aspect\PersistenceMagicInterface) { $propertyData[$propertyName] = array('type' => get_class($propertyValue), 'multivalue' => false, 'value' => $this->processObject($propertyValue, $identifier)); } else { switch ($propertyMetaData['type']) { case 'DateTime': $propertyData[$propertyName] = array('multivalue' => false, 'value' => $this->processDateTime($propertyValue)); break; case 'Doctrine\\Common\\Collections\\Collection': case 'Doctrine\\Common\\Collections\\ArrayCollection': $propertyValue = $propertyValue === null ? array() : $propertyValue->toArray(); case 'array': $propertyData[$propertyName] = array('multivalue' => true, 'value' => $this->processArray($propertyValue, $identifier, $this->persistenceSession->getCleanStateOfProperty($object, $propertyName))); break; case 'SplObjectStorage': $propertyData[$propertyName] = array('multivalue' => true, 'value' => $this->processSplObjectStorage($propertyValue, $identifier, $this->persistenceSession->getCleanStateOfProperty($object, $propertyName))); break; default: if ($propertyValue === null && !\TYPO3\Flow\Utility\TypeHandling::isSimpleType($propertyMetaData['type'])) { $this->removeDeletedReference($object, $propertyName, $propertyMetaData); } $propertyData[$propertyName] = array('multivalue' => false, 'value' => $propertyValue); break; } $propertyData[$propertyName]['type'] = $propertyMetaData['type']; } }
/** * @param string $className * @return array */ public function findModelProperties($className) { $modelDefinition = array(); foreach ($this->reflectionService->getClassPropertyNames($className) as $propertyName) { if (is_array($this->ignoredProperties) && in_array($propertyName, $this->ignoredProperties)) { continue; } $propertyType = $this->reflectionService->getPropertyTagValues($className, $propertyName, 'var'); $type = \TYPO3\Flow\Utility\TypeHandling::parseType($propertyType[0]); // if (class_exists($type['type']) && !isset($classNames[$type['type']])) { // $this->readClass($type['type'], $classNames); // } // if (class_exists($type['elementType']) && !isset($classNames[$type['elementType']])) { // if ($this->reflectionService->isClassAbstract($type['elementType'])) { // $implementations = $this->reflectionService->getAllSubClassNamesForClass($type['elementType']); // foreach ($implementations as $implementationClassName) { // if (isset($classNames[$implementationClassName])) { // continue; // } // $this->readClass($implementationClassName, $classNames); // } // } else { // $this->readClass($type['elementType'], $classNames); // } // } // TODO: Add lookup for relations and add them to the modelImplementations $modelDefinition[$propertyName] = array('type' => \TYPO3\Flow\Utility\TypeHandling::isCollectionType($type['type']) ? $type['elementType'] : $type['type']); } return $modelDefinition; }