2 namespace TYPO3\CMS\Extbase\Validation;
20 use TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException;
36 (?P<validatorName>[a-z0-9_:.\\\\]+)
39 (?P<validatorOptions>(?:\s*[a-z0-9]+\s*=\s*(?:
41 |\'(?:\\\\\'|[^\'])*\'
53 (?P<optionName>[a-z0-9]+)
57 |\'(?:\\\\\'|[^\'])*\'
110 $validator = $this->objectManager->get($validatorObjectName, $validatorOptions);
112 if (!($validator instanceof \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface)) {
113 throw new Exception\NoSuchValidatorException(
'The validator "' . $validatorObjectName .
'" does not implement TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface!', 1300694875);
134 if (!array_key_exists($targetClassName, $this->baseValidatorConjunctions)) {
135 $this->buildBaseValidatorConjunction($targetClassName, $targetClassName);
138 return $this->baseValidatorConjunctions[$targetClassName];
155 public function buildMethodArgumentsValidatorConjunctions($className, $methodName, array $methodParameters = null, array $methodValidateAnnotations = null)
158 $validatorConjunctions = array();
160 if ($methodParameters === null) {
161 $methodParameters = $this->reflectionService->getMethodParameters($className, $methodName);
163 if (empty($methodParameters)) {
164 return $validatorConjunctions;
167 foreach ($methodParameters as $parameterName => $methodParameter) {
169 $validatorConjunction = $this->
createValidator(ConjunctionValidator::class);
171 if (!array_key_exists(
'type', $methodParameter)) {
172 throw new Exception\InvalidTypeHintException(
'Missing type information, probably no @param annotation for parameter "$' . $parameterName .
'" in ' . $className .
'->' . $methodName .
'()', 1281962564);
176 if (strpbrk($methodParameter[
'type'],
'_\\') ===
false) {
179 $typeValidator = null;
182 if ($typeValidator !== null) {
183 $validatorConjunction->addValidator($typeValidator);
185 $validatorConjunctions[$parameterName] = $validatorConjunction;
188 if ($methodValidateAnnotations === null) {
190 $methodValidateAnnotations = array_map(
function ($validateAnnotation) {
192 'type' => $validateAnnotation[
'validatorName'],
193 'options' => $validateAnnotation[
'validatorOptions'],
194 'argumentName' => $validateAnnotation[
'argumentName'],
196 }, $validateAnnotations);
199 foreach ($methodValidateAnnotations as $annotationParameters) {
200 $newValidator = $this->
createValidator($annotationParameters[
'type'], $annotationParameters[
'options']);
201 if ($newValidator === null) {
202 throw new Exception\NoSuchValidatorException(
'Invalid validate annotation in ' . $className .
'->' . $methodName .
'(): Could not resolve class name for validator "' . $annotationParameters[
'type'] .
'".', 1239853109);
204 if (isset($validatorConjunctions[$annotationParameters[
'argumentName']])) {
205 $validatorConjunctions[$annotationParameters[
'argumentName']]->addValidator($newValidator);
206 }
elseif (strpos($annotationParameters[
'argumentName'],
'.') !==
false) {
207 $objectPath = explode(
'.', $annotationParameters[
'argumentName']);
208 $argumentName = array_shift($objectPath);
209 $validatorConjunctions[$argumentName]->addValidator($this->
buildSubObjectValidator($objectPath, $newValidator));
211 throw new Exception\InvalidValidationConfigurationException(
'Invalid validate annotation in ' . $className .
'->' . $methodName .
'(): Validator specified for argument name "' . $annotationParameters[
'argumentName'] .
'", but this argument does not exist.', 1253172726);
215 return $validatorConjunctions;
226 protected function buildSubObjectValidator(array $objectPath, \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface $propertyValidator)
228 $rootObjectValidator = $this->objectManager->get(\TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator::class, array());
229 $parentObjectValidator = $rootObjectValidator;
231 while (count($objectPath) > 1) {
232 $subObjectValidator = $this->objectManager->get(\TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator::class, array());
233 $subPropertyName = array_shift($objectPath);
234 $parentObjectValidator->addPropertyValidator($subPropertyName, $subObjectValidator);
235 $parentObjectValidator = $subObjectValidator;
238 $parentObjectValidator->addPropertyValidator(array_shift($objectPath), $propertyValidator);
240 return $rootObjectValidator;
266 protected function buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups = array())
269 $this->baseValidatorConjunctions[$indexKey] = $conjunctionValidator;
275 $objectValidator = $this->objectManager->get(\TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator::class, array());
276 foreach ($this->reflectionService->getClassPropertyNames($targetClassName) as $classPropertyName) {
277 $classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($targetClassName, $classPropertyName);
279 if (!isset($classPropertyTagsValues[
'var'])) {
280 throw new \InvalidArgumentException(sprintf(
'There is no @var annotation for property "%s" in class "%s".', $classPropertyName, $targetClassName), 1363778104);
284 }
catch (\TYPO3\CMS\Extbase\Utility\Exception\InvalidTypeException $exception) {
285 throw new \InvalidArgumentException(sprintf(
' @var annotation of ' . $exception->getMessage(),
'class "' . $targetClassName .
'", property "' . $classPropertyName .
'"'), 1315564744, $exception);
287 $propertyTargetClassName = $parsedType[
'type'];
291 $collectionValidator = $this->
createValidator(\TYPO3\CMS\Extbase\Validation\Validator\CollectionValidator::class, array(
'elementType' => $parsedType[
'elementType'],
'validationGroups' => $validationGroups));
292 $objectValidator->addPropertyValidator($classPropertyName, $collectionValidator);
293 }
elseif (class_exists($propertyTargetClassName) && !
TypeHandlingUtility::isCoreType($propertyTargetClassName) && $this->objectManager->isRegistered($propertyTargetClassName) && $this->objectManager->getScope($propertyTargetClassName) === \TYPO3\CMS\Extbase\Object\Container\Container::SCOPE_PROTOTYPE) {
295 if ($validatorForProperty !== null && $validatorForProperty->count() > 0) {
296 $objectValidator->addPropertyValidator($classPropertyName, $validatorForProperty);
301 $validateAnnotations = array();
303 if (isset($classPropertyTagsValues[
'validate']) && is_array($classPropertyTagsValues[
'validate'])) {
304 foreach ($classPropertyTagsValues[
'validate'] as $validateValue) {
307 foreach ($parsedAnnotations[
'validators'] as $validator) {
308 array_push($validateAnnotations, array(
309 'argumentName' => $parsedAnnotations[
'argumentName'],
310 'validatorName' => $validator[
'validatorName'],
311 'validatorOptions' => $validator[
'validatorOptions']
317 foreach ($validateAnnotations as $validateAnnotation) {
319 $newValidator = $this->
createValidator($validateAnnotation[
'validatorName'], $validateAnnotation[
'validatorOptions']);
320 if ($newValidator === null) {
321 throw new Exception\NoSuchValidatorException(
'Invalid validate annotation in ' . $targetClassName .
'::' . $classPropertyName .
': Could not resolve class name for validator "' . $validateAnnotation->type .
'".', 1241098027);
323 $objectValidator->addPropertyValidator($classPropertyName, $newValidator);
327 if (!empty($objectValidator->getPropertyValidators())) {
328 $conjunctionValidator->addValidator($objectValidator);
351 $addedValidatorClassName = null;
355 $customValidator = $this->
createValidator($possibleValidatorClassName);
356 if ($customValidator !== null) {
358 $addedValidatorClassName = get_class($customValidator);
373 if ($validateValue[0] ===
'$') {
374 $parts = explode(
' ', $validateValue, 2);
375 $validatorConfiguration = array(
'argumentName' => ltrim($parts[0],
'$'),
'validators' => array());
376 preg_match_all(self::PATTERN_MATCH_VALIDATORS, $parts[1], $matches, PREG_SET_ORDER);
378 $validatorConfiguration = array(
'validators' => array());
379 preg_match_all(self::PATTERN_MATCH_VALIDATORS, $validateValue, $matches, PREG_SET_ORDER);
381 foreach ($matches as $match) {
382 $validatorOptions = array();
383 if (isset($match[
'validatorOptions'])) {
386 $validatorConfiguration[
'validators'][] = array(
'validatorName' => $match[
'validatorName'],
'validatorOptions' => $validatorOptions);
388 return $validatorConfiguration;
400 $validatorOptions = array();
401 $parsedValidatorOptions = array();
402 preg_match_all(self::PATTERN_MATCH_VALIDATOROPTIONS, $rawValidatorOptions, $validatorOptions, PREG_SET_ORDER);
403 foreach ($validatorOptions as $validatorOption) {
404 $parsedValidatorOptions[trim($validatorOption[
'optionName'])] = trim($validatorOption[
'optionValue']);
406 array_walk($parsedValidatorOptions, array($this,
'unquoteString'));
407 return $parsedValidatorOptions;
421 switch ($quotedValue[0]) {
423 $quotedValue = str_replace(
'\\"',
'"', trim($quotedValue,
'"'));
426 $quotedValue = str_replace(
'\\\'',
'\'', trim($quotedValue,
'\''));
429 $quotedValue = str_replace(
'\\\\',
'\\', $quotedValue);
443 if (strpos($validatorName,
':') !==
false || strpbrk($validatorName,
'_\\') ===
false) {
446 list($extensionName, $extensionValidatorName) = explode(
':', $validatorName);
448 if ($validatorName !== $extensionName && $extensionValidatorName !==
'') {
450 if (strpos($extensionName,
'.') !==
false) {
451 $extensionNameParts = explode(
'.', $extensionName);
452 $extensionName = array_pop($extensionNameParts);
453 $vendorName = implode(
'\\', $extensionNameParts);
454 $possibleClassName = $vendorName .
'\\' . $extensionName .
'\\Validation\\Validator\\' . $extensionValidatorName;
456 $possibleClassName =
'Tx_' . $extensionName .
'_Validation_Validator_' . $extensionValidatorName;
460 $possibleClassName =
'TYPO3\\CMS\\Extbase\\Validation\\Validator\\' . $this->
getValidatorType($validatorName);
465 $possibleClassName = $validatorName;
466 if (!empty($possibleClassName) && $possibleClassName[0] ===
'\\') {
467 $possibleClassName = substr($possibleClassName, 1);
471 if (substr($possibleClassName, - strlen(
'Validator')) !==
'Validator') {
472 $possibleClassName .=
'Validator';
475 if (class_exists($possibleClassName)) {
476 $possibleClassNameInterfaces = class_implements($possibleClassName);
477 if (!in_array(\TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface::class, $possibleClassNameInterfaces)) {
479 throw new NoSuchValidatorException(
'Validator class ' . $validatorName .
' must implement \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface', 1365776838);
481 $resolvedValidatorName = $possibleClassName;
486 return $resolvedValidatorName;
514 $type = ucfirst($type);
529 $validateAnnotations = array();
530 $methodTagsValues = $this->reflectionService->getMethodTagsValues($className, $methodName);
531 if (isset($methodTagsValues[
'validate']) && is_array($methodTagsValues[
'validate'])) {
532 foreach ($methodTagsValues[
'validate'] as $validateValue) {
535 foreach ($parsedAnnotations[
'validators'] as $validator) {
536 array_push($validateAnnotations, array(
537 'argumentName' => $parsedAnnotations[
'argumentName'],
538 'validatorName' => $validator[
'validatorName'],
539 'validatorOptions' => $validator[
'validatorOptions']
545 return $validateAnnotations;