/**
  * 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;
 }
 /**
  * @test
  * @dataProvider collectionTypes
  */
 public function isCollectionTypeReturnsTrueForCollectionType($type, $expected)
 {
     $this->assertSame($expected, TypeHandling::isCollectionType($type), 'Failed for ' . $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;
 }
 /**
  * Builds a base validator conjunction for the given data type.
  *
  * The base validation rules are those which were declared directly in a class (typically
  * a model) through some validate annotations on properties.
  *
  * If a property holds a class for which a base validator exists, that property will be
  * checked as well, regardless of a validate annotation
  *
  * Additionally, if a custom validator was defined for the class in question, it will be added
  * to the end of the conjunction. A custom validator is found if it follows the naming convention
  * "Replace '\Model\' by '\Validator\' and append 'Validator'".
  *
  * Example: $targetClassName is TYPO3\Foo\Domain\Model\Quux, then the validator will be found if it has the
  * name TYPO3\Foo\Domain\Validator\QuuxValidator
  *
  * @param string $indexKey The key to use as index in $this->baseValidatorConjunctions; calculated from target class name and validation groups
  * @param string $targetClassName The data type to build the validation conjunction for. Needs to be the fully qualified class name.
  * @param array $validationGroups The validation groups to build the validator for
  * @return void
  * @throws \TYPO3\Flow\Validation\Exception\NoSuchValidatorException
  * @throws \InvalidArgumentException
  */
 protected function buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups)
 {
     $conjunctionValidator = new ConjunctionValidator();
     $this->baseValidatorConjunctions[$indexKey] = $conjunctionValidator;
     if (!TypeHandling::isSimpleType($targetClassName) && class_exists($targetClassName)) {
         // Model based validator
         $objectValidator = new 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);
             }
             try {
                 $parsedType = TypeHandling::parseType(trim(implode('', $classPropertyTagsValues['var']), ' \\'));
             } catch (\TYPO3\Flow\Utility\Exception\InvalidTypeException $exception) {
                 throw new \InvalidArgumentException(sprintf(' @var annotation of ' . $exception->getMessage(), 'class "' . $targetClassName . '", property "' . $classPropertyName . '"'), 1315564744, $exception);
             }
             if ($this->reflectionService->isPropertyAnnotatedWith($targetClassName, $classPropertyName, \TYPO3\Flow\Annotations\IgnoreValidation::class)) {
                 continue;
             }
             $propertyTargetClassName = $parsedType['type'];
             if (TypeHandling::isCollectionType($propertyTargetClassName) === TRUE) {
                 $collectionValidator = $this->createValidator(\TYPO3\Flow\Validation\Validator\CollectionValidator::class, array('elementType' => $parsedType['elementType'], 'validationGroups' => $validationGroups));
                 $objectValidator->addPropertyValidator($classPropertyName, $collectionValidator);
             } elseif (!TypeHandling::isSimpleType($propertyTargetClassName) && $this->objectManager->isRegistered($propertyTargetClassName) && $this->objectManager->getScope($propertyTargetClassName) === \TYPO3\Flow\Object\Configuration\Configuration::SCOPE_PROTOTYPE) {
                 $validatorForProperty = $this->getBaseValidatorConjunction($propertyTargetClassName, $validationGroups);
                 if (count($validatorForProperty) > 0) {
                     $objectValidator->addPropertyValidator($classPropertyName, $validatorForProperty);
                 }
             }
             $validateAnnotations = $this->reflectionService->getPropertyAnnotations($targetClassName, $classPropertyName, \TYPO3\Flow\Annotations\Validate::class);
             foreach ($validateAnnotations as $validateAnnotation) {
                 if (count(array_intersect($validateAnnotation->validationGroups, $validationGroups)) === 0) {
                     // In this case, the validation groups for the property do not match current validation context
                     continue;
                 }
                 $newValidator = $this->createValidator($validateAnnotation->type, $validateAnnotation->options);
                 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);
 }