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); }
/** * 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; }
/** * @param mixed $source * @param string $targetType * @return bool */ public function canConvertFrom($source, $targetType) { return TypeHandlingUtility::isCoreType($targetType); }
/** * 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; } }
/** * 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); } } }