‪TYPO3CMS  10.4
ValidatorResolver.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
29 
35 {
39  protected ‪$objectManager;
40 
44  protected ‪$reflectionService;
45 
49  protected ‪$baseValidatorConjunctions = [];
50 
55  {
56  $this->objectManager = ‪$objectManager;
57  }
58 
63  {
64  $this->reflectionService = ‪$reflectionService;
65  }
66 
76  public function ‪createValidator($validatorType, array $validatorOptions = [])
77  {
78  // todo: ValidatorResolver should not take care of creating validator instances.
79  // todo: Instead, a factory should be used.
80  try {
84  $validatorObjectName = ‪ValidatorClassNameResolver::resolve($validatorType);
85 
86  ‪$validator = $this->objectManager->get($validatorObjectName, $validatorOptions);
87 
88  // Move this check into ClassSchema
89  if (!(‪$validator instanceof ‪ValidatorInterface)) {
90  throw new ‪NoSuchValidatorException('The validator "' . $validatorObjectName . '" does not implement TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface!', 1300694875);
91  }
92 
93  return ‪$validator;
94  } catch (‪NoSuchValidatorException $e) {
95  GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__)->debug($e->getMessage());
96  return null;
97  }
98  }
99 
109  public function ‪getBaseValidatorConjunction($targetClassName)
110  {
111  if (!array_key_exists($targetClassName, $this->baseValidatorConjunctions)) {
112  $this->‪buildBaseValidatorConjunction($targetClassName, $targetClassName);
113  }
114 
115  return $this->baseValidatorConjunctions[$targetClassName];
116  }
117 
140  protected function ‪buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups = [])
141  {
142  $conjunctionValidator = new ‪ConjunctionValidator();
143  $this->baseValidatorConjunctions[$indexKey] = $conjunctionValidator;
144 
145  // note: the simpleType check reduces lookups to the class loader
146  if (!‪TypeHandlingUtility::isSimpleType($targetClassName) && class_exists($targetClassName)) {
147  $classSchema = $this->reflectionService->getClassSchema($targetClassName);
148 
149  // Model based validator
151  $objectValidator = $this->objectManager->get(GenericObjectValidator::class, []);
152  foreach ($classSchema->getProperties() as $property) {
153  if ($property->getType() === null) {
154  // todo: The type is only necessary here for further analyzations whether it's a simple type or
155  // todo: a collection. If this is evaluated in the ClassSchema, this whole code part is not needed
156  // todo: any longer and can be removed.
157  throw new \InvalidArgumentException(sprintf('There is no @var annotation for property "%s" in class "%s".', $property->getName(), $targetClassName), 1363778104);
158  }
159 
160  $propertyTargetClassName = $property->getType();
161  // note: the outer simpleType check reduces lookups to the class loader
162 
163  // todo: whether the property holds a simple type or not and whether it holds a collection is known in
164  // todo: in the ClassSchema. The information could be made available and not evaluated here again.
165  if (!‪TypeHandlingUtility::isSimpleType($propertyTargetClassName)) {
166  if (‪TypeHandlingUtility::isCollectionType($propertyTargetClassName)) {
167  $collectionValidator = $this->‪createValidator(
168  CollectionValidator::class,
169  [
170  'elementType' => $property->getElementType(),
171  'validationGroups' => $validationGroups
172  ]
173  );
174  $objectValidator->addPropertyValidator($property->getName(), $collectionValidator);
175  } elseif (class_exists($propertyTargetClassName) && !‪TypeHandlingUtility::isCoreType($propertyTargetClassName) && !in_array(SingletonInterface::class, class_implements($propertyTargetClassName, true), true)) {
176  /*
177  * class_exists($propertyTargetClassName) checks, if the type of the property is an object
178  * instead of a simple type. Like DateTime or another model.
179  *
180  * !TypeHandlingUtility::isCoreType($propertyTargetClassName) checks if the type of the property
181  * is not a core type, which are Enums and File objects for example.
182  * todo: check why these types should not be validated
183  *
184  * !in_array(SingletonInterface::class, class_implements($propertyTargetClassName, true), true)
185  * checks if the class is an instance of a Singleton
186  * todo: check why Singletons shouldn't be validated.
187  */
188 
189  /*
190  * (Alexander Schnitzler) By looking at this code I assume that this is the path for 1:1
191  * relations in models. Still, the question remains why it excludes core types and singletons.
192  * It makes sense on a theoretical level but I don't see a technical issue allowing these as
193  * well.
194  */
195  $validatorForProperty = $this->‪getBaseValidatorConjunction($propertyTargetClassName);
196  if ($validatorForProperty !== null && $validatorForProperty->count() > 0) {
197  $objectValidator->addPropertyValidator($property->getName(), $validatorForProperty);
198  }
199  }
200  }
201 
202  foreach ($property->getValidators() as $validatorDefinition) {
203  // @todo: Respect validationGroups
204 
205  // @todo: At this point we already have the class name of the validator, thus there is not need
206  // @todo: calling \TYPO3\CMS\Extbase\Validation\ValidatorResolver::resolveValidatorObjectName inside
207  // @todo: \TYPO3\CMS\Extbase\Validation\ValidatorResolver::createValidator once again. However, to
208  // @todo: keep things simple for now, we still use the method createValidator here. In the future,
209  // @todo: createValidator must only accept FQCN's.
210  $newValidator = $this->‪createValidator($validatorDefinition['className'], $validatorDefinition['options']);
211  if ($newValidator === null) {
212  throw new ‪NoSuchValidatorException('Invalid validate annotation in ' . $targetClassName . '::' . $property->getName() . ': Could not resolve class name for validator "' . $validatorDefinition['className'] . '".', 1241098027);
213  }
214  $objectValidator->addPropertyValidator($property->getName(), $newValidator);
215  }
216  }
217 
218  if (!empty($objectValidator->getPropertyValidators())) {
219  $conjunctionValidator->addValidator($objectValidator);
220  }
221  }
222  }
223 }
‪TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator
Definition: ConjunctionValidator.php:24
‪TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException
Definition: NoSuchValidatorException.php:26
‪TYPO3\CMS\Extbase\Validation\Validator\CollectionValidator
Definition: CollectionValidator.php:27
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\injectObjectManager
‪injectObjectManager(ObjectManagerInterface $objectManager)
Definition: ValidatorResolver.php:51
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\$baseValidatorConjunctions
‪array $baseValidatorConjunctions
Definition: ValidatorResolver.php:46
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver
Definition: ValidatorResolver.php:35
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\createValidator
‪TYPO3 CMS Extbase Validation Validator ValidatorInterface createValidator($validatorType, array $validatorOptions=[])
Definition: ValidatorResolver.php:73
‪TYPO3\CMS\Extbase\Validation\ValidatorClassNameResolver\resolve
‪static string resolve(string $validatorIdentifier)
Definition: ValidatorClassNameResolver.php:46
‪TYPO3\CMS\Extbase\Utility\TypeHandlingUtility\isSimpleType
‪static bool isSimpleType(string $type)
Definition: TypeHandlingUtility.php:113
‪TYPO3\CMS\Extbase\Object\ObjectManagerInterface
Definition: ObjectManagerInterface.php:26
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\injectReflectionService
‪injectReflectionService(ReflectionService $reflectionService)
Definition: ValidatorResolver.php:59
‪TYPO3\CMS\Extbase\Reflection\ReflectionService
Definition: ReflectionService.php:31
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\buildBaseValidatorConjunction
‪buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups=[])
Definition: ValidatorResolver.php:137
‪TYPO3\CMS\Extbase\Utility\TypeHandlingUtility\isCollectionType
‪static bool isCollectionType(string $type)
Definition: TypeHandlingUtility.php:135
‪TYPO3\CMS\Extbase\Utility\TypeHandlingUtility
Definition: TypeHandlingUtility.php:29
‪$validator
‪if(isset($args['d'])) $validator
Definition: validateRstFiles.php:218
‪TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator
Definition: GenericObjectValidator.php:25
‪TYPO3\CMS\Extbase\Utility\TypeHandlingUtility\isCoreType
‪static bool isCoreType($type)
Definition: TypeHandlingUtility.php:124
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\$objectManager
‪TYPO3 CMS Extbase Object ObjectManagerInterface $objectManager
Definition: ValidatorResolver.php:38
‪TYPO3\CMS\Extbase\Validation
Definition: Error.php:16
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\getBaseValidatorConjunction
‪ConjunctionValidator getBaseValidatorConjunction($targetClassName)
Definition: ValidatorResolver.php:106
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:23
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:30
‪TYPO3\CMS\Extbase\Validation\ValidatorResolver\$reflectionService
‪TYPO3 CMS Extbase Reflection ReflectionService $reflectionService
Definition: ValidatorResolver.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface
Definition: ValidatorInterface.php:22