[!!!][TASK] Always throw exception if a userFunc does not exist 96/50996/9
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Mon, 19 Dec 2016 15:31:49 +0000 (16:31 +0100)
committerSusanne Moog <susanne.moog@typo3.org>
Sun, 18 Jun 2017 16:13:54 +0000 (18:13 +0200)
The parameter `$errorMode` is removed from the method
`GeneralUtility::callUserFunction()`. Thus, the checks agains this
variable are removed as well, causing exceptions being always thrown now.

Resolves: #74533
Releases: master
Change-Id: Ibf8b0c9de55b4d8d210dac8fc6c82b14ca7c849d
Reviewed-on: https://review.typo3.org/50996
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-74533-ThrowExceptionIfUserFunctionDoesNotExist.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php

index 27b26b2..0aa26fc 100644 (file)
@@ -3371,14 +3371,11 @@ class GeneralUtility
      * @param string $funcName Function/Method reference or Closure.
      * @param mixed $params Parameters to be pass along (typically an array) (REFERENCE!)
      * @param mixed $ref Reference to be passed along (typically "$this" - being a reference to the calling object) (REFERENCE!)
-     * @param string $_ Not used anymore since 6.0
-     * @param int $errorMode Error mode (when class/function could not be found): 0 - call debug(), 1 - do nothing, 2 - raise an exception (allows to call a user function that may return FALSE)
-     * @return mixed Content from method/function call or FALSE if the class/method/function was not found
-     * @see makeInstance()
+     * @return mixed Content from method/function call
+     * @throws \InvalidArgumentException
      */
-    public static function callUserFunction($funcName, &$params, &$ref, $_ = '', $errorMode = 0)
+    public static function callUserFunction($funcName, &$params, &$ref)
     {
-        $content = false;
         // Check if we're using a closure and invoke it directly.
         if (is_object($funcName) && is_a($funcName, 'Closure')) {
             return call_user_func_array($funcName, [&$params, &$ref]);
@@ -3387,7 +3384,7 @@ class GeneralUtility
         $parts = explode('->', $funcName);
         // Call function or method
         if (count($parts) === 2) {
-            // Class
+            // It's a class/method
             // Check if class/method exists:
             if (class_exists($parts[0])) {
                 // Create object
@@ -3397,32 +3394,18 @@ class GeneralUtility
                     $content = call_user_func_array([&$classObj, $parts[1]], [&$params, &$ref]);
                 } else {
                     $errorMsg = 'No method name \'' . $parts[1] . '\' in class ' . $parts[0];
-                    if ($errorMode == 2) {
-                        throw new \InvalidArgumentException($errorMsg, 1294585865);
-                    } elseif (!$errorMode) {
-                        debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                    }
+                    throw new \InvalidArgumentException($errorMsg, 1294585865);
                 }
             } else {
                 $errorMsg = 'No class named ' . $parts[0];
-                if ($errorMode == 2) {
-                    throw new \InvalidArgumentException($errorMsg, 1294585866);
-                } elseif (!$errorMode) {
-                    debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                }
+                throw new \InvalidArgumentException($errorMsg, 1294585866);
             }
+        } elseif (function_exists($funcName)) {
+            // It's a function
+            $content = call_user_func_array($funcName, [&$params, &$ref]);
         } else {
-            // Function
-            if (function_exists($funcName)) {
-                $content = call_user_func_array($funcName, [&$params, &$ref]);
-            } else {
-                $errorMsg = 'No function named: ' . $funcName;
-                if ($errorMode == 2) {
-                    throw new \InvalidArgumentException($errorMsg, 1294585867);
-                } elseif (!$errorMode) {
-                    debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                }
-            }
+            $errorMsg = 'No function named: ' . $funcName;
+            throw new \InvalidArgumentException($errorMsg, 1294585867);
         }
         return $content;
     }
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-74533-ThrowExceptionIfUserFunctionDoesNotExist.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-74533-ThrowExceptionIfUserFunctionDoesNotExist.rst
new file mode 100644 (file)
index 0000000..b2b8faf
--- /dev/null
@@ -0,0 +1,34 @@
+.. include:: ../../Includes.txt
+
+==================================================================
+Breaking: #74533 - Throw exception if user function does not exist
+==================================================================
+
+See :issue:`74533`
+
+Description
+===========
+
+:php:`GeneralUtility::callUserFunction()` does now always throw an exception if the passed user function does not
+exist or is not callable. The parameter `$errorMode` has been removed, exceptions are now always thrown.
+
+
+Impact
+======
+
+Calling a not existing or uncallable user function leads to an exception, breaking the page output.
+
+
+Affected Installations
+======================
+
+All TYPO3 installations are affected.
+
+
+Migration
+=========
+
+Remove or fix invalid `userFunc` calls registered in TypoScript and/or `ext_localconf.php`. Catch exceptions properly
+with try/catch.
+
+.. index:: PHP-API
index 7626e52..f48d2a4 100644 (file)
@@ -4262,20 +4262,6 @@ class GeneralUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
     /**
      * @test
      * @dataProvider callUserFunctionInvalidParameterDataprovider
-     */
-    public function callUserFunctionWillReturnFalseForInvalidParameters($functionName)
-    {
-        $inputData = ['foo' => 'bar'];
-        // omit the debug() output
-        ob_start();
-        $result = GeneralUtility::callUserFunction($functionName, $inputData, $this, 'user_', 1);
-        ob_end_clean();
-        $this->assertFalse($result);
-    }
-
-    /**
-     * @test
-     * @dataProvider callUserFunctionInvalidParameterDataprovider
      * @param string $functionName
      * @param int $expectedException
      */
@@ -4285,7 +4271,7 @@ class GeneralUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         $this->expectExceptionCode($expectedException);
 
         $inputData = ['foo' => 'bar'];
-        GeneralUtility::callUserFunction($functionName, $inputData, $this, 'user_', 2);
+        GeneralUtility::callUserFunction($functionName, $inputData, $this);
     }
 
     /**
@@ -4297,9 +4283,9 @@ class GeneralUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
     public function callUserFunctionInvalidParameterDataprovider()
     {
         return [
-            'Function is not prefixed' => ['t3lib_divTest->calledUserFunction', 1294585866],
+            'Function is not prefixed' => [self::class . '->calledUserFunction', 1294585865],
             'Class doesn\'t exists' => ['t3lib_divTest21345->user_calledUserFunction', 1294585866],
-            'No method name' => ['t3lib_divTest', 1294585867],
+            'No method name' => [self::class, 1294585867],
             'No class name' => ['->user_calledUserFunction', 1294585866],
             'No function name' => ['', 1294585867]
         ];