[BUGFIX] Correctly apply Extbase validator options and add tests 38/28938/4
authorStefan Neufeind <typo3.neufeind@speedpartner.de>
Tue, 24 Sep 2013 00:12:03 +0000 (02:12 +0200)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Fri, 4 Apr 2014 08:57:07 +0000 (10:57 +0200)
* Check supplied options
* Apply default-values of validator if needed
* Check for required options
* Provide options via constructor instead of via setOptions()
  (which is deprecated)
* Add tests for AbstractValidator and AbstractCompositeValidator

Resolves: #52208
Resolves: #57164
Releases: 6.2, 6.1
Change-Id: I589a30bea74144eed51948ecad3143ab145c958f
Reviewed-on: https://review.typo3.org/28938
Reviewed-by: Marc Bastian Heinrichs
Tested-by: Marc Bastian Heinrichs
Reviewed-by: Pascal Dürsteler
Tested-by: Pascal Dürsteler
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
typo3/sysext/extbase/Classes/Validation/Validator/AbstractValidator.php
typo3/sysext/extbase/Classes/Validation/Validator/BooleanValidator.php
typo3/sysext/extbase/Classes/Validation/ValidatorResolver.php
typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractCompositeValidatorTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractValidatorTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractCompositeValidatorClass.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractValidatorClass.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/Validation/Validator/StringLengthValidatorTest.php
typo3/sysext/extbase/Tests/Unit/Validation/ValidatorResolverTest.php

index 60f3ff5..ac67f1a 100644 (file)
@@ -27,10 +27,12 @@ namespace TYPO3\CMS\Extbase\Validation\Validator;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
+
 /**
  * Abstract validator
  */
-abstract class AbstractValidator implements \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface {
+abstract class AbstractValidator implements ValidatorInterface {
 
        /**
         * Specifies whether this validator accepts empty values.
@@ -67,13 +69,39 @@ abstract class AbstractValidator implements \TYPO3\CMS\Extbase\Validation\Valida
        protected $result;
 
        /**
-        * Sets options for the validator
+        * Constructs the validator and sets validation options
         *
-        * @param array $validationOptions Options for the validator
+        * @param array $options Options for the validator
+        * @throws InvalidValidationOptionsException
         * @api
         */
-       public function __construct($validationOptions = array()) {
-               $this->options = $validationOptions;
+       public function __construct(array $options = array()) {
+               // check for options given but not supported
+               if (($unsupportedOptions = array_diff_key($options, $this->supportedOptions)) !== array()) {
+                       throw new InvalidValidationOptionsException('Unsupported validation option(s) found: ' . implode(', ', array_keys($unsupportedOptions)), 1379981890);
+               }
+
+               // check for required options being set
+               array_walk(
+                       $this->supportedOptions,
+                       function($supportedOptionData, $supportedOptionName, $options) {
+                               if (isset($supportedOptionData[3]) && $supportedOptionData[3] === TRUE && !array_key_exists($supportedOptionName, $options)) {
+                                       throw new InvalidValidationOptionsException('Required validation option not set: ' . $supportedOptionName, 1379981891);
+                               }
+                       },
+                       $options
+               );
+
+               // merge with default values
+               $this->options = array_merge(
+                       array_map(
+                               function ($value) {
+                                       return $value[0];
+                               },
+                               $this->supportedOptions
+                       ),
+                       $options
+               );
        }
 
        /**
index 7c7218c..ebbe305 100644 (file)
@@ -33,6 +33,19 @@ namespace TYPO3\CMS\Extbase\Validation\Validator;
 class BooleanValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator {
 
        /**
+        * @var array
+        */
+       protected $supportedOptions = array(
+               // The default is set to NULL here, because we need to be backward compatible here, because this
+               // BooleanValidator is called automatically on boolean action arguments. If we would set it to TRUE,
+               // every FALSE value for an action argument would break.
+               // TODO with next patches: deprecate this BooleanValidator and introduce a BooleanValueValidator, like
+               // in Flow, which won't be called on boolean action arguments.
+               'is' => array(NULL, 'Boolean value', 'boolean|string|integer')
+       );
+
+
+       /**
         * Returns TRUE if the given property value is a boolean matching the expectation.
         *
         * If at least one error occurred, the result is FALSE.
@@ -44,7 +57,8 @@ class BooleanValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractV
         * @return boolean TRUE if the value is within the range, otherwise FALSE
         */
        public function isValid($value) {
-               if (!isset($this->options['is'])) {
+               // see comment above, check if expectation is NULL, then nothing to do!
+               if ($this->options['is'] === NULL) {
                        return;
                }
                switch (strtolower((string)$this->options['is'])) {
index 1789e17..3ae876a 100644 (file)
@@ -105,11 +105,7 @@ class ValidatorResolver implements \TYPO3\CMS\Core\SingletonInterface {
                         */
                        $validatorObjectName = $this->resolveValidatorObjectName($validatorType);
 
-                       $validator = $this->objectManager->get($validatorObjectName);
-                       if (method_exists($validator, 'setOptions')) {
-                               // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
-                               $validator->setOptions($validatorOptions);
-                       }
+                       $validator = $this->objectManager->get($validatorObjectName, $validatorOptions);
 
                        if (!($validator instanceof \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface)) {
                                throw new Exception\NoSuchValidatorException('The validator "' . $validatorObjectName . '" does not implement TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface!', 1300694875);
diff --git a/typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractCompositeValidatorTest.php b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractCompositeValidatorTest.php
new file mode 100644 (file)
index 0000000..630701f
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Unit\Validation\Validator;
+
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the abstract base-class of composite-validators
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class AbstractCompositeValidatorTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
+
+       /**
+        * @test
+        */
+       public function validatorAcceptsSupportedOptions() {
+               $inputOptions = array(
+                       'requiredOption' => 666,
+                       'demoOption' => 42
+               );
+               $expectedOptions = $inputOptions;
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractCompositeValidatorClass', array('dummy'), array($inputOptions));
+               $this->assertSame($expectedOptions, $validator->_get('options'));
+       }
+
+       /**
+        * @test
+        */
+       public function validatorHasDefaultOptions() {
+               $inputOptions = array('requiredOption' => 666);
+               $expectedOptions = array(
+                       'requiredOption' => 666,
+                       'demoOption' => PHP_INT_MAX
+               );
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractCompositeValidatorClass', array('dummy'), array($inputOptions));
+               $this->assertSame($expectedOptions, $validator->_get('options'));
+       }
+
+       /**
+        * @test
+        */
+       public function validatorThrowsExceptionOnNotSupportedOptions() {
+               $inputOptions = array('invalidoption' => 42);
+               $this->setExpectedException('TYPO3\\CMS\\Extbase\\Validation\\Exception\\InvalidValidationOptionsException', '', 1339079804);
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractCompositeValidatorClass', array('dummy'), array($inputOptions));
+       }
+
+
+       /**
+        * @test
+        */
+       public function validatorThrowsExceptionOnMissingRequiredOptions() {
+               $inputOptions = array();
+               $this->setExpectedException('TYPO3\\CMS\\Extbase\\Validation\\Exception\\InvalidValidationOptionsException', '', 1339163922);
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractCompositeValidatorClass', array('dummy'), array($inputOptions));
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractValidatorTest.php b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/AbstractValidatorTest.php
new file mode 100644 (file)
index 0000000..d4efbe1
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Unit\Validation\Validator;
+
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the abstract base-class of validators
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class AbstractValidatorTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
+
+       /**
+        * @test
+        */
+       public function validatorAcceptsSupportedOptions() {
+               $inputOptions = array(
+                       'requiredOption' => 666,
+                       'demoOption' => 42
+               );
+               $expectedOptions = $inputOptions;
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractValidatorClass', array('dummy'), array($inputOptions));
+               $this->assertSame($expectedOptions, $validator->_get('options'));
+       }
+
+       /**
+        * @test
+        */
+       public function validatorHasDefaultOptions() {
+               $inputOptions = array('requiredOption' => 666);
+               $expectedOptions = array(
+                       'requiredOption' => 666,
+                       'demoOption' => PHP_INT_MAX
+               );
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractValidatorClass', array('dummy'), array($inputOptions));
+               $this->assertSame($expectedOptions, $validator->_get('options'));
+       }
+
+       /**
+        * @test
+        */
+       public function validatorThrowsExceptionOnNotSupportedOptions() {
+               $inputOptions = array('invalidoption' => 42);
+               $this->setExpectedException('TYPO3\\CMS\\Extbase\\Validation\\Exception\\InvalidValidationOptionsException', '', 1379981890);
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractValidatorClass', array('dummy'), array($inputOptions));
+       }
+
+
+       /**
+        * @test
+        */
+       public function validatorThrowsExceptionOnMissingRequiredOptions() {
+               $inputOptions = array();
+               $this->setExpectedException('TYPO3\\CMS\\Extbase\\Validation\\Exception\\InvalidValidationOptionsException', '', 1379981891);
+               $validator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractValidatorClass', array('dummy'), array($inputOptions));
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractCompositeValidatorClass.php b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractCompositeValidatorClass.php
new file mode 100644 (file)
index 0000000..a5e1b0d
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Unit\Validation\Validator\Fixture;
+
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the abstract base-class of vvalidators
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class AbstractCompositeValidatorClass extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractCompositeValidator {
+
+       /**
+        * @var array
+        */
+       protected $supportedOptions = array(
+               'requiredOption' => array(0, 'Some value', 'integer', TRUE),
+               'demoOption' => array(PHP_INT_MAX, 'Some value', 'integer'),
+       );
+
+       /**
+        * Check if $value is valid. If it is not valid, needs to add an error
+        * to Result.
+        *
+        * @param mixed $value
+        * @return void
+        */
+       protected function isValid($value) {
+               // dummy
+       }
+
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractValidatorClass.php b/typo3/sysext/extbase/Tests/Unit/Validation/Validator/Fixture/AbstractValidatorClass.php
new file mode 100644 (file)
index 0000000..f1b1713
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Unit\Validation\Validator\Fixture;
+
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the abstract base-class of vvalidators
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class AbstractValidatorClass extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator {
+
+       /**
+        * @var array
+        */
+       protected $supportedOptions = array(
+               'requiredOption' => array(0, 'Some value', 'integer', TRUE),
+               'demoOption' => array(PHP_INT_MAX, 'Some value', 'integer'),
+       );
+
+       /**
+        * Check if $value is valid. If it is not valid, needs to add an error
+        * to Result.
+        *
+        * @param mixed $value
+        * @return void
+        */
+       protected function isValid($value) {
+               // dummy
+       }
+
+
+}
+?>
\ No newline at end of file
index e7c2f8e..91b3a07 100644 (file)
@@ -80,7 +80,6 @@ class StringLengthValidatorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
 
        /**
         * @test
-        * @expectedException \TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException
         */
        public function stringLengthValidatorReturnsNoErrorsForAStringLongerThanThanMinLengthAndMaxLengthNotSpecified() {
                $options = array('minimum' => 5);
@@ -108,7 +107,6 @@ class StringLengthValidatorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
 
        /**
         * @test
-        * @expectedException \TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException
         */
        public function stringLengthValidatorReturnsNoErrorForAStringLengthEqualToMinLengthAndMaxLengthNotSpecified() {
                $options = array('minimum' => 10);
index 11c0d00..c616809 100644 (file)
@@ -159,13 +159,14 @@ class ValidatorResolverTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         */
        public function createValidatorResolvesAndReturnsAValidatorAndPassesTheGivenOptions() {
                $className = uniqid('Test');
-               $mockValidator = $this->getMock('TYPO3\\CMS\\Extbase\\Validation\\Validator\\ObjectValidatorInterface', array('setOptions', 'canValidate', 'isPropertyValid', 'setValidatedInstancesContainer'), array(), $className);
-               $mockValidator->expects($this->once())->method('setOptions')->with(array('foo' => 'bar'));
-               $this->mockObjectManager->expects($this->any())->method('get')->with($className)->will($this->returnValue($mockValidator));
+               $validatorOptions = array('requiredOption' => 'foo', 'demoOption' => 'bar');
+               $mockValidator = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Tests\\Unit\\Validation\\Validator\\Fixture\\AbstractValidatorClass', array('dummy'), array($validatorOptions), $className);
+               $this->mockObjectManager->expects($this->any())->method('get')->with($className, $validatorOptions)->will($this->returnValue($mockValidator));
                $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('resolveValidatorObjectName'));
                $validatorResolver->_set('objectManager', $this->mockObjectManager);
                $validatorResolver->expects($this->once())->method('resolveValidatorObjectName')->with($className)->will($this->returnValue($className));
-               $validator = $validatorResolver->createValidator($className, array('foo' => 'bar'));
+               $validator = $validatorResolver->createValidator($className, $validatorOptions);
+               $this->assertEquals($validatorOptions, $validator->_get('options'));
                $this->assertSame($mockValidator, $validator);
        }