[FEATURE] Improve userFunc parameter parsing in conditions 07/20007/7
authorDmitry Dulepov <dmitry.dulepov@gmail.com>
Wed, 17 Apr 2013 07:26:01 +0000 (11:26 +0400)
committerMarkus Klein <klein.t3@mfc-linz.at>
Mon, 14 Oct 2013 10:32:15 +0000 (12:32 +0200)
userFunc TypoScript conditions can be improved to use CSV-like
syntax for parameters.

Resolves: #47301
Related: #47159
Releases: 6.2
Change-Id: Ia2a170d0b8eb160607fbd39bd9afbe6ffab679a5
Reviewed-on: https://review.typo3.org/20007
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
Reviewed-by: Markus Klein
Tested-by: Markus Klein
typo3/sysext/core/Classes/Configuration/TypoScript/ConditionMatching/AbstractConditionMatcher.php
typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherUserFuncs.php [new file with mode: 0644]

index c5bd903..32f0a4c 100644 (file)
@@ -415,9 +415,10 @@ abstract class AbstractConditionMatcher {
                                }
                                break;
                        case 'userFunc':
-                               $values = preg_split('/\\(|\\)/', $value);
-                               $funcName = trim($values[0]);
-                               $funcValues = GeneralUtility::trimExplode(',', $values[1]);
+                               $matches = array();
+                               preg_match_all('/^\s*([^\(\s]+)\s*(?:\((.*)\))?\s*$/', $value, $matches);
+                               $funcName = $matches[1][0];
+                               $funcValues = $matches[2][0] ? $this->parseUserFuncArguments($matches[2][0]) : array();
                                if (function_exists($funcName) && call_user_func_array($funcName, $funcValues)) {
                                        return TRUE;
                                }
@@ -427,6 +428,42 @@ abstract class AbstractConditionMatcher {
        }
 
        /**
+        * Parses arguments to the userFunc.
+        *
+        * @param string $arguments
+        * @return array
+        */
+       protected function parseUserFuncArguments($arguments) {
+               $result = array();
+               $arguments = trim($arguments);
+               while ($arguments) {
+                       if ($arguments{0} == ',') {
+                               $result[] = '';
+                               $arguments = substr($arguments, 1);
+                       } else {
+                               $pos = strcspn($arguments, ',\'"');
+                               if ($pos == 0) {
+                                       // We hit a quote of some kind
+                                       $quote = $arguments{0};
+                                       $segment = preg_replace('/^(.*?[^\\\])' . $quote . '.*$/', '\1', substr($arguments, 1));
+                                       $segment = str_replace('\\' . $quote, $quote, $segment);
+                                       $result[] = $segment;
+                                       $offset = strpos($arguments, ',', strlen($segment) + 2);
+                                       if ($offset === FALSE) {
+                                               $offset = strlen($arguments);
+                                       }
+                                       $arguments = substr($arguments, $offset);
+                               } else {
+                                       $result[] = trim(substr($arguments, 0, $pos));
+                                       $arguments = substr($arguments, $pos + 1);
+                               }
+                       }
+                       $arguments = trim($arguments);
+               };
+               return $result;
+       }
+
+       /**
         * Get variable common
         *
         * @param array $vars
diff --git a/typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherTest.php b/typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherTest.php
new file mode 100644 (file)
index 0000000..2080ed3
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Configuration;
+
+use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Dmitry Dulepov <dmitry.dulepov@gmail.com>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+require_once(ExtensionManagementUtility::extPath('core', 'Tests/Unit/Configuration/ConditionMatcherUserFuncs.php'));
+
+/**
+ * Test class for ConditionMatcher functions
+ *
+ * @author Dmitry Dulepov <dmitry.dulepov@gmail.com>
+ */
+class ConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /** @var ConditionMatcher */
+       protected $conditionMatcher;
+
+       public function setUp() {
+               $this->conditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Configuration\\TypoScript\\ConditionMatching\\ConditionMatcher');
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncIsCalled() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunction]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithSingleArgument() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithSingleArgument(x)]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithMultipleArguments() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithThreeArguments(1,2,3)]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncReturnsFalse() {
+               $this->assertFalse($this->conditionMatcher->match('[userFunc = user_testFunctionFalse]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithMultipleArgumentsAndQuotes() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithThreeArguments(1,2,"3,4,5,6")]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithMultipleArgumentsAndQuotesAndSpaces() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithThreeArguments ( 1 , 2, "3, 4, 5, 6" ) ]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithMultipleArgumentsAndQuotesAndSpacesStripped() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithThreeArgumentsSpaces ( 1 , 2, "3, 4, 5, 6" ) ]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithSpacesInQuotes() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithSpaces(" 3, 4, 5, 6 ")]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithMultipleArgumentsAndQuotesAndSpacesStrippedAndEscapes() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithThreeArgumentsSpaces ( 1 , 2, "3, \"4, 5\", 6" ) ]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithQuoteMissing() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testFunctionWithQuoteMissing ("value \") ]'));
+       }
+
+       /**
+        * @test
+        * @return void
+        */
+       public function testUserFuncWithQuotesInside() {
+               $this->assertTrue($this->conditionMatcher->match('[userFunc = user_testQuotes("1 \" 2") ]'));
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherUserFuncs.php b/typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherUserFuncs.php
new file mode 100644 (file)
index 0000000..8817443
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Dmitry Dulepov <dmitry.dulepov@gmail.com>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+namespace {
+       function user_testFunctionWithSingleArgument() {
+               return count(func_get_args()) === 1;
+       }
+
+       function user_testFunctionWithThreeArguments() {
+               return count(func_get_args()) === 3;
+       }
+
+       function user_testFunctionWithThreeArgumentsSpaces() {
+               $result = TRUE;
+               foreach (func_get_args() as $argument) {
+                       $result &= (trim($argument) == $argument);
+               }
+               return $result;
+       }
+
+       function user_testFunctionWithSpaces($value) {
+               return $value === ' 3, 4, 5, 6 ';
+       }
+
+       function user_testFunction() {
+               return TRUE;
+       }
+
+       function user_testFunctionFalse() {
+               return FALSE;
+       }
+
+       function user_testFunctionWithQuoteMissing($value) {
+               return $value === 'value "';
+       }
+
+       function user_testQuotes($value) {
+               return $value === '1 " 2';
+       }
+}
+
+?>
\ No newline at end of file