diff --git a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php index e0683f267a80626fe01a00e588f69f433af79976..3c7f681d808cf2ddad9f794ac64f7dab2af2b035 100644 --- a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php +++ b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php @@ -323,8 +323,13 @@ class ClassSchema if ($tag === 'validate') { $this->methods[$methodName]['annotations']['validators'] = $values; } - $this->methods[$methodName]['tags'][$tag] = array_map(function ($value) { - return ltrim($value, '$'); + $this->methods[$methodName]['tags'][$tag] = array_map(function ($value) use ($tag) { + // not stripping the dollar sign for @validate annotations is just + // a quick fix for a regression introduced in 9.0.0. + // This exception to the rules will vanish once the resolving of + // validators will take place inside this class and not in the + // controller during runtime. + return $tag === 'validate' ? $value : ltrim($value, '$'); }, $values); } diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ef9de775439714c780b23c2274572fcded7cb69f --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php @@ -0,0 +1,211 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Mvc\Controller\Arguments; +use TYPO3\CMS\Extbase\Mvc\Web\Request; +use TYPO3\CMS\Extbase\Mvc\Web\Response; +use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator; +use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator; +use TYPO3\CMS\Extbase\Validation\Validator\StringValidator; + +/** + * Test case + */ +class ActionControllerTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase +{ + /** + * @var \TYPO3\CMS\Extbase\Mvc\Web\Request + */ + protected $request; + + /** + * @var \TYPO3\CMS\Extbase\Mvc\Web\Response + */ + protected $response; + + /** + * @var \TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Controller\TestController + */ + protected $controller; + + protected function setUp() + { + parent::setUp(); + + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + + $this->request = $objectManager->get(Request::class); + $this->request->setControllerVendorName('TYPO3\\CMS'); + $this->request->setPluginName('Pi1'); + $this->request->setControllerExtensionName('Extbase\\Tests\\Functional\\Mvc\\Controller\\Fixture'); + $this->request->setControllerName('Test'); + $this->request->setMethod('GET'); + $this->request->setFormat('html'); + + $this->response = $objectManager->get(Response::class); + + $this->controller = $objectManager->get(Fixture\Controller\TestController::class); + } + + /** + * @test + */ + public function modelValidatorsAreProperlyResolved() + { + // Setup + $this->request->setControllerActionName('foo'); + $this->request->setArgument('fooParam', []); + + // Test run + $this->controller->processRequest($this->request, $this->response); + + // Open arguments property + $reflectionClass = new \ReflectionClass($this->controller); + $argumentsProperty = $reflectionClass->getProperty('arguments'); + $argumentsProperty->setAccessible(true); + + // Assertions + + /** @var Arguments $arguments */ + $arguments = $argumentsProperty->getValue($this->controller); + $argument = $arguments->getArgument('fooParam'); + + /** @var ConjunctionValidator $validator */ + $conjunctionValidator = $argument->getValidator(); + static::assertInstanceOf(ConjunctionValidator::class, $conjunctionValidator); + + /** @var \SplObjectStorage $validators */ + $validators = $conjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $validators); + + $validators->rewind(); + + /** @var ConjunctionValidator $subConjunctionValidator */ + $subConjunctionValidator = $validators->current(); + static::assertInstanceOf(ConjunctionValidator::class, $subConjunctionValidator); + + /** @var \SplObjectStorage $subValidators */ + $subValidators = $subConjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $subValidators); + + $subValidators->rewind(); + static::assertInstanceOf(Fixture\Domain\Validator\ModelValidator::class, $subValidators->current()); + } + + /** + * @test + */ + public function customValidatorsAreProperlyResolved() + { + // Setup + $this->request->setControllerActionName('bar'); + $this->request->setArgument('barParam', ''); + + // Test run + $this->controller->processRequest($this->request, $this->response); + + // Open arguments property + $reflectionClass = new \ReflectionClass($this->controller); + $argumentsProperty = $reflectionClass->getProperty('arguments'); + $argumentsProperty->setAccessible(true); + + // Assertions + + /** @var Arguments $arguments */ + $arguments = $argumentsProperty->getValue($this->controller); + $argument = $arguments->getArgument('barParam'); + + /** @var ConjunctionValidator $validator */ + $conjunctionValidator = $argument->getValidator(); + static::assertInstanceOf(ConjunctionValidator::class, $conjunctionValidator); + + /** @var \SplObjectStorage $validators */ + $validators = $conjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $validators); + + $validators->rewind(); + static::assertInstanceOf(StringValidator::class, $validators->current()); + + $validators->next(); + static::assertInstanceOf(Fixture\Validation\Validator\CustomValidator::class, $validators->current()); + + $validators->next(); + + /** @var ConjunctionValidator $subConjunctionValidator */ + $subConjunctionValidator = $validators->current(); + static::assertInstanceOf(ConjunctionValidator::class, $subConjunctionValidator); + + // todo: It doesn't make sense that there is another conjunction + // todo: valididator with a StringValidator attached. We need to + // todo: find out what causes that and how to fix this. + + /** @var \SplObjectStorage $subValidators */ + $subValidators = $subConjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $subValidators); + + $subValidators->rewind(); + static::assertInstanceOf(StringValidator::class, $subValidators->current()); + } + + /** + * @test + */ + public function extbaseValidatorsAreProperlyResolved() + { + // Setup + $this->request->setControllerActionName('baz'); + $this->request->setArgument('bazParam', [ 'notEmpty' ]); + + // Test run + $this->controller->processRequest($this->request, $this->response); + + // Open arguments property + $reflectionClass = new \ReflectionClass($this->controller); + $argumentsProperty = $reflectionClass->getProperty('arguments'); + $argumentsProperty->setAccessible(true); + + // Assertions + + /** @var Arguments $arguments */ + $arguments = $argumentsProperty->getValue($this->controller); + $argument = $arguments->getArgument('bazParam'); + + /** @var ConjunctionValidator $validator */ + $conjunctionValidator = $argument->getValidator(); + static::assertInstanceOf(ConjunctionValidator::class, $conjunctionValidator); + + /** @var \SplObjectStorage $validators */ + $validators = $conjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $validators); + + $validators->rewind(); + static::assertInstanceOf(NotEmptyValidator::class, $validators->current()); + + $validators->next(); + + /** @var ConjunctionValidator $subConjunctionValidator */ + $subConjunctionValidator = $validators->current(); + static::assertInstanceOf(ConjunctionValidator::class, $subConjunctionValidator); + + /** @var \SplObjectStorage $subValidators */ + $subValidators = $subConjunctionValidator->getValidators(); + static::assertInstanceOf(\SplObjectStorage::class, $subValidators); + static::assertEmpty($subValidators); + } +} diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php new file mode 100644 index 0000000000000000000000000000000000000000..d595fe75ac49487daf0124ead9080456c994461b --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php @@ -0,0 +1,71 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Controller; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; +use TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration; +use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter; +use TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Domain\Model\Model; + +/** + * Fixture controller + */ +class TestController extends ActionController +{ + public function initializeFooAction() + { + /** @var MvcPropertyMappingConfiguration $propertMappingConfiguration */ + $propertMappingConfiguration = $this->arguments['fooParam']->getPropertyMappingConfiguration(); + $propertMappingConfiguration->allowAllProperties(); + $propertMappingConfiguration->setTypeConverterOption( + PersistentObjectConverter::class, + PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, + true + ); + } + + /** + * @param \TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Domain\Model\Model $fooParam + * @return string + */ + public function fooAction(Model $fooParam) + { + // return string so we don't need to mock a view + return ''; + } + + /** + * @param string $barParam + * @validate $barParam TYPO3.CMS.Extbase.Tests.Functional.Mvc.Controller.Fixture:CustomValidator + * @return string + */ + public function barAction(string $barParam) + { + // return string so we don't need to mock a view + return ''; + } + + /** + * @param array $bazParam + * @validate $bazParam NotEmpty + * @return string + */ + public function bazAction(array $bazParam) + { + // return string so we don't need to mock a view + return ''; + } +} diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Model/Model.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Model/Model.php new file mode 100644 index 0000000000000000000000000000000000000000..aa0fa5f889b302d7a151bb62129ed571619ac23f --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Model/Model.php @@ -0,0 +1,25 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Domain\Model; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; + +/** + * Fixture model + */ +class Model extends AbstractEntity +{ +} diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Validator/ModelValidator.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Validator/ModelValidator.php new file mode 100644 index 0000000000000000000000000000000000000000..04e046786b8f70014537852040c8e7a2ff07edc0 --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Validator/ModelValidator.php @@ -0,0 +1,29 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Domain\Validator; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * Fixture model validator + */ +class ModelValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator +{ + /** + * @param mixed $value + */ + protected function isValid($value) + { + } +} diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Validation/Validator/CustomValidator.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Validation/Validator/CustomValidator.php new file mode 100644 index 0000000000000000000000000000000000000000..0b76ca0f0837caf9d67c2b7971babf29c9c89c4d --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Validation/Validator/CustomValidator.php @@ -0,0 +1,29 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller\Fixture\Validation\Validator; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * Fixture custom validator + */ +class CustomValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator +{ + /** + * @param mixed $value + */ + protected function isValid($value) + { + } +}