From 80e78c98e901be7433d094bd632f4abce67c950b Mon Sep 17 00:00:00 2001 From: Alexander Schnitzler <git@alexanderschnitzler.de> Date: Wed, 3 Jan 2018 17:38:30 +0100 Subject: [PATCH] [BUGFIX] Fix resolving of method validators This is a regression bugfix. During the ClassSchema refactoring the resolving of method validators broke due to stripping of beginning dollar signs from tags. Releases: master Resolves: #83425 Change-Id: Ida33ade7bc61c0bb926fbf1895612eac9a94d948 Reviewed-on: https://review.typo3.org/55244 Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../Classes/Reflection/ClassSchema.php | 9 +- .../Mvc/Controller/ActionControllerTest.php | 211 ++++++++++++++++++ .../Fixture/Controller/TestController.php | 71 ++++++ .../Controller/Fixture/Domain/Model/Model.php | 25 +++ .../Domain/Validator/ModelValidator.php | 29 +++ .../Validation/Validator/CustomValidator.php | 29 +++ 6 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php create mode 100644 typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php create mode 100644 typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Model/Model.php create mode 100644 typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Domain/Validator/ModelValidator.php create mode 100644 typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Validation/Validator/CustomValidator.php diff --git a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php index e0683f267a80..3c7f681d808c 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 000000000000..ef9de7754397 --- /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 000000000000..d595fe75ac49 --- /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 000000000000..aa0fa5f889b3 --- /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 000000000000..04e046786b8f --- /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 000000000000..0b76ca0f0837 --- /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) + { + } +} -- GitLab