[BUGFIX] resolveValidatorObjectName support for namespaces
authorAske Ertmann <aertmann@gmail.com>
Mon, 15 Oct 2012 15:46:14 +0000 (17:46 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Sun, 4 Nov 2012 22:58:58 +0000 (23:58 +0100)
This fix makes sure that validators get resolved correctly for
namespaced extensions. This works for the following scenarios:
Fully qualified namespaced extension name, shorthand validator
names (namespaced & non-namespaaced) and built in validators.

This also changes the behavior for the built in validators,
so instead of resolving the deprecated class name it resolves
to the namespaced class name.

Fixes: #40955
Releases: 6.0

Change-Id: Iec6a1e613218cf1e5d032502231dfa3447d8fa96
Reviewed-on: http://review.typo3.org/15642
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
typo3/sysext/extbase/Classes/Validation/ValidatorResolver.php
typo3/sysext/extbase/Tests/Unit/Validation/ValidatorResolverTest.php

index 4b8350d..fc0f83c 100644 (file)
@@ -288,14 +288,15 @@ class ValidatorResolver implements \TYPO3\CMS\Core\SingletonInterface {
         * This method is meant as a helper for regular expression results.
         *
         * @param string &$quotedValue Value to unquote
+        * @return void
         */
        protected function unquoteString(&$quotedValue) {
                switch ($quotedValue[0]) {
-               case '"':
-                       $quotedValue = str_replace('\\"', '"', trim($quotedValue, '"'));
+                       case '"':
+                               $quotedValue = str_replace('\\"', '"', trim($quotedValue, '"'));
                        break;
-               case '\'':
-                       $quotedValue = str_replace('\\\'', '\'', trim($quotedValue, '\''));
+                       case '\'':
+                               $quotedValue = str_replace('\\\'', '\'', trim($quotedValue, '\''));
                        break;
                }
                $quotedValue = str_replace('\\\\', '\\', $quotedValue);
@@ -306,17 +307,24 @@ class ValidatorResolver implements \TYPO3\CMS\Core\SingletonInterface {
         * FALSE is returned
         *
         * @param string $validatorName Either the fully qualified class name of the validator or the short name of a built-in validator
-        * @return string Name of the validator object or FALSE
+        * @return string|boolean Name of the validator object or FALSE
         */
        protected function resolveValidatorObjectName($validatorName) {
-               if (strpos($validatorName, '_') !== FALSE && class_exists($validatorName)) {
+               if ((strpbrk($validatorName, '_\\') !== FALSE) && class_exists($validatorName)) {
                        return $validatorName;
                }
                list($extensionName, $extensionValidatorName) = explode(':', $validatorName);
-               if (!$extensionValidatorName) {
-                       $possibleClassName = 'Tx_Extbase_Validation_Validator_' . $this->unifyDataType($validatorName) . 'Validator';
+               if (empty($extensionValidatorName)) {
+                       $possibleClassName = 'TYPO3\\CMS\\Extbase\\Validation\\Validator\\' . $this->unifyDataType($validatorName) . 'Validator';
                } else {
-                       $possibleClassName = 'Tx_' . $extensionName . '_Validation_Validator_' . $extensionValidatorName . 'Validator';
+                       if (strpos($extensionName, '.') !== FALSE) {
+                               $extensionNameParts = explode('.', $extensionName);
+                               $extensionName = array_pop($extensionNameParts);
+                               $vendorName = implode('\\', $extensionNameParts);
+                               $possibleClassName = $vendorName . '\\' . $extensionName . '\\Validation\\Validator\\' . $extensionValidatorName . 'Validator';
+                       } else {
+                               $possibleClassName = 'Tx_' . $extensionName . '_Validation_Validator_' . $extensionValidatorName . 'Validator';
+                       }
                }
                if (class_exists($possibleClassName)) {
                        return $possibleClassName;
@@ -332,26 +340,24 @@ class ValidatorResolver implements \TYPO3\CMS\Core\SingletonInterface {
         */
        protected function unifyDataType($type) {
                switch ($type) {
-               case 'int':
-                       $type = 'Integer';
-                       break;
-               case 'bool':
-                       $type = 'Boolean';
-                       break;
-               case 'double':
-                       $type = 'Float';
-                       break;
-               case 'numeric':
-                       $type = 'Number';
-                       break;
-               case 'mixed':
-                       $type = 'Raw';
-                       break;
+                       case 'int':
+                               $type = 'Integer';
+                               break;
+                       case 'bool':
+                               $type = 'Boolean';
+                               break;
+                       case 'double':
+                               $type = 'Float';
+                               break;
+                       case 'numeric':
+                               $type = 'Number';
+                               break;
+                       case 'mixed':
+                               $type = 'Raw';
+                               break;
                }
                return ucfirst($type);
        }
 
 }
-
-
 ?>
index bfcbf4c..2a37a9e 100644 (file)
@@ -38,8 +38,8 @@ class ValidatorResolverTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $mockObjectManager = $this->getMock('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface');
                /** @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface */
                $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('dummy'));
-               $validatorResolver->_set('objectManager', $objectManager);
-               $this->assertSame(FALSE, $validatorResolver->_call('resolveValidatorObjectName', 'Foo'));
+               $validatorResolver->_set('objectManager', $mockObjectManager);
+               $this->assertFalse($validatorResolver->_call('resolveValidatorObjectName', 'Foo'));
        }
 
        /**
@@ -52,15 +52,49 @@ class ValidatorResolverTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $this->assertSame($validatorName, $validatorResolver->_call('resolveValidatorObjectName', $validatorName));
        }
 
+       /**
+        * @test
+        */
+       public function resolveValidatorObjectNameReturnsTheGivenArgumentIfANamespacedObjectOfThatNameIsRegistered() {
+               $namespace = 'Acme\\Bar';
+               $className = uniqid('FooValidator') . 'Validator';
+               $validatorName = $namespace . '\\' . $className;
+               eval('namespace ' . $namespace . '; ' . LF . 'class ' . $className . ' {}');
+               $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('dummy'));
+               $this->assertSame($validatorName, $validatorResolver->_call('resolveValidatorObjectName', $validatorName));
+       }
+
        /**
         * @test
         */
        public function resolveValidatorObjectNameCanResolveShorthandValidatornames() {
                $mockObjectManager = $this->getMock('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface');
-               eval('class Tx_Mypkg_Validation_Validator_MyValidator {}');
+               eval('class Tx_Mypkg_Validation_Validator_MyFirstValidator {}');
+               $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('dummy'));
+               $validatorResolver->_set('objectManager', $mockObjectManager);
+               $this->assertSame('Tx_Mypkg_Validation_Validator_MyFirstValidator', $validatorResolver->_call('resolveValidatorObjectName', 'Mypkg:MyFirst'));
+       }
+
+       /**
+        * @return array
+        */
+       public function namespacedShorthandValidatornames() {
+               return array(
+                       array('TYPO3\\CMS\\Mypkg\\Validation\\Validator', 'MySecondValidator', 'TYPO3.CMS.Mypkg:MySecond'),
+                       array('Acme\\Mypkg\\Validation\\Validator', 'MyThirdValidator', 'Acme.Mypkg:MyThird')
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider namespacedShorthandValidatornames
+        */
+       public function resolveValidatorObjectNameCanResolveNamespacedShorthandValidatornames($namespace, $className, $shorthandValidatorname) {
+               $mockObjectManager = $this->getMock('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface');
+               eval('namespace ' . $namespace . '; class ' . $className . ' {}');
                $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('dummy'));
                $validatorResolver->_set('objectManager', $mockObjectManager);
-               $this->assertSame('Tx_Mypkg_Validation_Validator_MyValidator', $validatorResolver->_call('resolveValidatorObjectName', 'Mypkg:My'));
+               $this->assertSame($namespace . '\\' . $className, $validatorResolver->_call('resolveValidatorObjectName', $shorthandValidatorname));
        }
 
        /**
@@ -68,10 +102,10 @@ class ValidatorResolverTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
         */
        public function resolveValidatorObjectNameCanResolveShortNamesOfBuiltInValidators() {
                $mockObjectManager = $this->getMock('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface');
-               eval('class Tx_Extbase_Validation_Validator_FooValidator {}');
+               eval('namespace TYPO3\\CMS\\Extbase\\Validation\\Validator; class FooValidator {}');
                $validatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('dummy'));
                $validatorResolver->_set('objectManager', $mockObjectManager);
-               $this->assertSame('Tx_Extbase_Validation_Validator_FooValidator', $validatorResolver->_call('resolveValidatorObjectName', 'Foo'));
+               $this->assertSame('TYPO3\\CMS\\Extbase\\Validation\\Validator\\FooValidator', $validatorResolver->_call('resolveValidatorObjectName', 'Foo'));
        }
 
        /**
@@ -273,7 +307,7 @@ class ValidatorResolverTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
         */
        public function resolveValidatorObjectNameCallsUnifyDataType() {
                $mockValidatorResolver = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Validation\\ValidatorResolver', array('unifyDataType'));
-               $mockValidatorResolver->expects($this->once())->method('unifyDataType')->with('someDataType');
+               $mockValidatorResolver->expects($this->any())->method('unifyDataType')->with('someDataType');
                $mockValidatorResolver->_call('resolveValidatorObjectName', 'someDataType');
        }