protected function buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups = array()) { $conjunctionValidator = new \TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator(); $this->baseValidatorConjunctions[$indexKey] = $conjunctionValidator; if (class_exists($targetClassName)) { // Model based validator /** @var \TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator $objectValidator */ $objectValidator = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Validation\\Validator\\GenericObjectValidator', array()); foreach ($this->reflectionService->getClassPropertyNames($targetClassName) as $classPropertyName) { $classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($targetClassName, $classPropertyName); if (!isset($classPropertyTagsValues['var'])) { throw new \InvalidArgumentException(sprintf('There is no @var annotation for property "%s" in class "%s".', $classPropertyName, $targetClassName), 1363778104); } // ONLY THING DIFFERENT THAN PARENT IMPLEMENTATION if (isset($classPropertyTagsValues['ignorevalidation'])) { continue; } try { $parsedType = \TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::parseType(trim(implode('', $classPropertyTagsValues['var']), ' \\')); } catch (\TYPO3\CMS\Extbase\Utility\Exception\InvalidTypeException $exception) { throw new \InvalidArgumentException(sprintf(' @var annotation of ' . $exception->getMessage(), 'class "' . $targetClassName . '", property "' . $classPropertyName . '"'), 1315564744, $exception); } $propertyTargetClassName = $parsedType['type']; if (\TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::isCollectionType($propertyTargetClassName) === TRUE) { $collectionValidator = $this->createValidator('TYPO3\\CMS\\Extbase\\Validation\\Validator\\CollectionValidator', array('elementType' => $parsedType['elementType'], 'validationGroups' => $validationGroups)); $objectValidator->addPropertyValidator($classPropertyName, $collectionValidator); } elseif (class_exists($propertyTargetClassName) && !\TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::isCoreType($propertyTargetClassName) && $this->objectManager->isRegistered($propertyTargetClassName) && $this->objectManager->getScope($propertyTargetClassName) === \TYPO3\CMS\Extbase\Object\Container\Container::SCOPE_PROTOTYPE) { $validatorForProperty = $this->getBaseValidatorConjunction($propertyTargetClassName, $validationGroups); if (count($validatorForProperty) > 0) { $objectValidator->addPropertyValidator($classPropertyName, $validatorForProperty); } } $validateAnnotations = array(); // @todo: Resolve annotations via reflectionService once its available if (isset($classPropertyTagsValues['validate']) && is_array($classPropertyTagsValues['validate'])) { foreach ($classPropertyTagsValues['validate'] as $validateValue) { $parsedAnnotations = $this->parseValidatorAnnotation($validateValue); foreach ($parsedAnnotations['validators'] as $validator) { array_push($validateAnnotations, array('argumentName' => $parsedAnnotations['argumentName'], 'validatorName' => $validator['validatorName'], 'validatorOptions' => $validator['validatorOptions'])); } } } foreach ($validateAnnotations as $validateAnnotation) { // @todo: Respect validationGroups $newValidator = $this->createValidator($validateAnnotation['validatorName'], $validateAnnotation['validatorOptions']); if ($newValidator === NULL) { throw new Exception\NoSuchValidatorException('Invalid validate annotation in ' . $targetClassName . '::' . $classPropertyName . ': Could not resolve class name for validator "' . $validateAnnotation->type . '".', 1241098027); } $objectValidator->addPropertyValidator($classPropertyName, $newValidator); } } if (count($objectValidator->getPropertyValidators()) > 0) { $conjunctionValidator->addValidator($objectValidator); } } $this->addCustomValidators($targetClassName, $conjunctionValidator); }
/** * 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\CMS\Extbase\Error\Result * @api */ public function validate($value) { $this->result = new \TYPO3\CMS\Extbase\Error\Result(); if ($this->acceptsEmptyValues === FALSE || $this->isEmpty($value) === FALSE) { if (is_object($value) && !\TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::isCollectionType(get_class($value)) && !is_array($value)) { $this->addError('The given subject was not a collection.', 1317204797); return $this->result; } elseif ($value instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage && !$value->isInitialized()) { return $this->result; } elseif (is_object($value) && $this->isValidatedAlready($value)) { return $this->result; } else { $this->isValid($value); } } return $this->result; }
/** * Updates the username and password credentials from the POST vars, if the POST parameters are available. * * @return void */ public function updateCredentials() { foreach (['version', 'user', 'tpa_id', 'expires', 'action', 'flags', 'userdata', 'signature'] as $argumentName) { $getArguments[$argumentName] = GeneralUtility::_GP($argumentName); } 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'] = TypeHandlingUtility::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->valid = true; } }
/** * Returns a plain value, i.e. objects are flattened out if possible. * Multi value objects or arrays will be converted to a comma-separated list for use in IN SQL queries. * * @param mixed $input The value that will be converted. * @param ColumnMap $columnMap Optional column map for retrieving the date storage format. * @param callable $parseStringValueCallback Optional callback method that will be called for string values. Can be used to do database quotation. * @param array $parseStringValueCallbackParameters Additional parameters that will be passed to the callabck as second parameter. * @throws \InvalidArgumentException * @throws UnexpectedTypeException * @return int|string */ public function getPlainValue($input, $columnMap = null, $parseStringValueCallback = null, array $parseStringValueCallbackParameters = []) { if ($input === null) { return 'NULL'; } if ($input instanceof Persistence\Generic\LazyLoadingProxy) { $input = $input->_loadRealInstance(); } if (is_bool($input)) { $parameter = (int) $input; } elseif ($input instanceof \DateTime) { if (!is_null($columnMap) && !is_null($columnMap->getDateTimeStorageFormat())) { $storageFormat = $columnMap->getDateTimeStorageFormat(); $timeZoneToStore = clone $input; // set to UTC to store in database $timeZoneToStore->setTimezone(new \DateTimeZone('UTC')); switch ($storageFormat) { case 'datetime': $parameter = $timeZoneToStore->format('Y-m-d H:i:s'); break; case 'date': $parameter = $timeZoneToStore->format('Y-m-d'); break; default: throw new \InvalidArgumentException('Column map DateTime format "' . $storageFormat . '" is unknown. Allowed values are datetime or date.', 1395353470); } } else { $parameter = $input->format('U'); } } elseif (TypeHandlingUtility::isValidTypeForMultiValueComparison($input)) { $plainValueArray = []; foreach ($input as $inputElement) { $plainValueArray[] = $this->getPlainValue($inputElement, $columnMap, $parseStringValueCallback, $parseStringValueCallbackParameters); } $parameter = implode(',', $plainValueArray); } elseif ($input instanceof DomainObjectInterface) { $parameter = (int) $input->getUid(); } elseif (is_object($input)) { if (TypeHandlingUtility::isCoreType($input)) { $parameter = $this->getPlainStringValue($input, $parseStringValueCallback, $parseStringValueCallbackParameters); } else { throw new UnexpectedTypeException('An object of class "' . get_class($input) . '" could not be converted to a plain value.', 1274799934); } } else { $parameter = $this->getPlainStringValue($input, $parseStringValueCallback, $parseStringValueCallbackParameters); } return $parameter; }
/** * Adds (defines) a specific property and its type. * * @param string $name Name of the property * @param string $type Type of the property * @param bool $lazy Whether the property should be lazy-loaded when reconstituting * @param string $cascade Strategy to cascade the object graph. * @return void */ public function addProperty($name, $type, $lazy = FALSE, $cascade = '') { $type = TypeHandlingUtility::parseType($type); $this->properties[$name] = array('type' => $type['type'], 'elementType' => $type['elementType'], 'lazy' => $lazy, 'cascade' => $cascade); }
/** * Constructs this controller argument * * @param string $name Name of this argument * @param string $dataType The data type of this argument * @throws \InvalidArgumentException if $name is not a string or empty * @api */ public function __construct($name, $dataType) { if (!is_string($name)) { throw new \InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688); } if (strlen($name) === 0) { throw new \InvalidArgumentException('$name must be a non-empty string, ' . strlen($name) . ' characters given.', 1232551853); } $this->name = $name; $this->dataType = TypeHandlingUtility::normalizeType($dataType); }
/** * Converts the given parameter reflection into an information array * * @param ParameterReflection $parameter The parameter to reflect * @param int $parameterPosition * @param MethodReflection|NULL $method * @return array Parameter information array */ protected function convertParameterReflectionToArray(ParameterReflection $parameter, $parameterPosition, MethodReflection $method = null) { $parameterInformation = ['position' => $parameterPosition, 'byReference' => $parameter->isPassedByReference(), 'array' => $parameter->isArray(), 'optional' => $parameter->isOptional(), 'allowsNull' => $parameter->allowsNull()]; $parameterClass = $parameter->getClass(); $parameterInformation['class'] = $parameterClass !== null ? $parameterClass->getName() : null; if ($parameter->isDefaultValueAvailable()) { $parameterInformation['defaultValue'] = $parameter->getDefaultValue(); } if ($parameterClass !== null) { $parameterInformation['type'] = $parameterClass->getName(); } elseif ($method !== null) { $methodTagsAndValues = $this->getMethodTagsValues($method->getDeclaringClass()->getName(), $method->getName()); if (isset($methodTagsAndValues['param']) && isset($methodTagsAndValues['param'][$parameterPosition])) { $explodedParameters = explode(' ', $methodTagsAndValues['param'][$parameterPosition]); if (count($explodedParameters) >= 2) { if (TypeHandlingUtility::isSimpleType($explodedParameters[0])) { // ensure that short names of simple types are resolved correctly to the long form // this is important for all kinds of type checks later on $typeInfo = TypeHandlingUtility::parseType($explodedParameters[0]); $parameterInformation['type'] = $typeInfo['type']; } else { $parameterInformation['type'] = $explodedParameters[0]; } } } } if (isset($parameterInformation['type']) && $parameterInformation['type'][0] === '\\') { $parameterInformation['type'] = substr($parameterInformation['type'], 1); } return $parameterInformation; }
/** * Determine the type converter to be used. If no converter has been found, an exception is raised. * * @param mixed $source * @param string $targetType * @param PropertyMappingConfigurationInterface $configuration * @throws Exception\TypeConverterException * @throws Exception\InvalidTargetException * @return \TYPO3\CMS\Extbase\Property\TypeConverterInterface Type Converter which should be used to convert between $source and $targetType. */ protected function findTypeConverter($source, $targetType, PropertyMappingConfigurationInterface $configuration) { if ($configuration->getTypeConverter() !== null) { return $configuration->getTypeConverter(); } $sourceType = $this->determineSourceType($source); if (!is_string($targetType)) { throw new Exception\InvalidTargetException('The target type was no string, but of type "' . gettype($targetType) . '"', 1297941727); } $targetType = $this->parseCompositeType($targetType); // This is needed to correctly convert old class names to new ones // This compatibility layer will be removed with 7.0 $targetType = \TYPO3\CMS\Core\Core\ClassLoadingInformation::getClassNameForAlias($targetType); $targetType = TypeHandlingUtility::normalizeType($targetType); $converter = null; if (TypeHandlingUtility::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 Exception\TypeConverterException('No converter found which can be used to convert from "' . $sourceType . '" to "' . $targetType . '".'); } return $converter; }
/** * Returns a plain value, i.e. objects are flattened out if possible. * * @param mixed $input * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException * @return mixed */ protected function getPlainValue($input) { if (is_array($input)) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932); } if ($input instanceof \DateTime) { return $input->format('U'); } elseif (TypeHandlingUtility::isCoreType($input)) { return (string) $input; } elseif (is_object($input)) { if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) { $realInput = $input->_loadRealInstance(); } else { $realInput = $input; } if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) { return $realInput->getUid(); } else { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934); } } elseif (is_bool($input)) { return $input === TRUE ? 1 : 0; } else { return $input; } }
/** * Return the type of a given sub-property inside the $targetType * * @param string $targetType * @param string $propertyName * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration * @return string * @api */ public function getTypeOfChildProperty($targetType, $propertyName, \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration) { $parsedTargetType = \TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::parseType($targetType); return $parsedTargetType['elementType']; }
/** * @param mixed $source * @param string $targetType * @return bool */ public function canConvertFrom($source, $targetType) { return TypeHandlingUtility::isCoreType($targetType); }
/** * Returns TRUE if the $type is a simple type. * * @param string $type * @return boolean */ public function isSimpleType($type) { return TypeHandlingUtility::isSimpleType($type); }
/** * Sets the given properties on the object. * * @param \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object The object to set properties on * @param array $row * @return void */ protected function thawProperties(\TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface $object, array $row) { $className = get_class($object); $classSchema = $this->reflectionService->getClassSchema($className); $dataMap = $this->getDataMap($className); $object->_setProperty('uid', (int) $row['uid']); $object->_setProperty('pid', (int) $row['pid']); $object->_setProperty('_localizedUid', (int) $row['uid']); $object->_setProperty('_versionedUid', (int) $row['uid']); if ($dataMap->getLanguageIdColumnName() !== NULL) { $object->_setProperty('_languageUid', (int) $row[$dataMap->getLanguageIdColumnName()]); if (isset($row['_LOCALIZED_UID'])) { $object->_setProperty('_localizedUid', (int) $row['_LOCALIZED_UID']); } } if (!empty($row['_ORIG_uid']) && !empty($GLOBALS['TCA'][$dataMap->getTableName()]['ctrl']['versioningWS'])) { $object->_setProperty('_versionedUid', (int) $row['_ORIG_uid']); } $properties = $object->_getProperties(); foreach ($properties as $propertyName => $propertyValue) { if (!$dataMap->isPersistableProperty($propertyName)) { continue; } $columnMap = $dataMap->getColumnMap($propertyName); $columnName = $columnMap->getColumnName(); $propertyData = $classSchema->getProperty($propertyName); $propertyValue = NULL; if ($row[$columnName] !== NULL) { switch ($propertyData['type']) { case 'integer': $propertyValue = (int) $row[$columnName]; break; case 'float': $propertyValue = (double) $row[$columnName]; break; case 'boolean': $propertyValue = (bool) $row[$columnName]; break; case 'string': $propertyValue = (string) $row[$columnName]; break; case 'array': // $propertyValue = $this->mapArray($row[$columnName]); // Not supported, yet! break; case 'SplObjectStorage': case 'Tx_Extbase_Persistence_ObjectStorage': case 'TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage': $propertyValue = $this->mapResultToPropertyValue($object, $propertyName, $this->fetchRelated($object, $propertyName, $row[$columnName])); break; default: if ($propertyData['type'] === 'DateTime' || in_array('DateTime', class_parents($propertyData['type']))) { $propertyValue = $this->mapDateTime($row[$columnName], $columnMap->getDateTimeStorageFormat()); } elseif (TypeHandlingUtility::isCoreType($propertyData['type'])) { $propertyValue = $this->mapCoreType($propertyData['type'], $row[$columnName]); } else { $propertyValue = $this->mapObjectToClassProperty($object, $propertyName, $row[$columnName]); } } } if ($propertyValue !== NULL) { $object->_setProperty($propertyName, $propertyValue); } } }
/** * Returns an "in" criterion used for matching objects against a query. It * matches if the property's value is contained in the multivalued operand. * * @param string $propertyName The name of the property to compare against * @param mixed $operand The value to compare with, multivalued * @throws Exception\UnexpectedTypeException * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface * @api */ public function in($propertyName, $operand) { if (!\TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::isValidTypeForMultiValueComparison($operand)) { throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('The "in" operator must be given a multivalued operand (array, ArrayAccess, Traversable).', 1264678095); } return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand); }