From f1475e8d1acfd2f1e3bacbf2329160645b9b3d63 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Thu, 2 Nov 2017 15:03:23 +0100 Subject: [PATCH] [TASK] Unify Backend module registration for Extbase modules This patch unifies the Backend module registration for Extbase modules like it has already been done for all other Backend modules using PSR-7 entry-points. This way backend route dispatching and module registration has been simplified. The entrypoint for Extbase Backend modules is now \TYPO3\CMS\Extbase\Core\Bootstrap->handleBackendRequest() which returns a PSR-7 response object. The following functionality has been marked as deprecated as it was solely built to handle Extbase modules when conf.php and index.php were still in style: ExtensionManagementUtility::configureModule() $GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'] Releases: master Resolves: #82902 Related: #58621 Change-Id: I7956b350d650ed52bc7b5d83db20df386d79eb65 Reviewed-on: https://review.typo3.org/54531 Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Henning Liebe <h.liebe@neusta.de> Reviewed-by: Susanne Moog <susanne.moog@typo3.org> Tested-by: Susanne Moog <susanne.moog@typo3.org> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> --- .../backend/Classes/Http/RouteDispatcher.php | 43 ++----------- .../backend/Classes/Module/ModuleLoader.php | 11 +--- .../Utility/ExtensionManagementUtility.php | 2 + ...CustomBackendModuleRegistrationMethods.rst | 40 ++++++++++++ .../sysext/extbase/Classes/Core/Bootstrap.php | 61 +++++++++++++++++++ .../extbase/Classes/Mvc/Web/Response.php | 22 +++++++ .../Classes/Utility/ExtensionUtility.php | 5 +- .../Php/MethodCallStaticMatcher.php | 7 +++ 8 files changed, 143 insertions(+), 48 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-82902-CustomBackendModuleRegistrationMethods.rst diff --git a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php index d6d456016b23..94d7fa7e5fa8 100644 --- a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php +++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php @@ -55,7 +55,7 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface } if ($route->getOption('module')) { - return $this->dispatchModule($request, $response); + $this->addAndValidateModuleConfiguration($request, $route); } $targetIdentifier = $route->getOption('target'); $target = $this->getCallableFromTarget($targetIdentifier); @@ -92,18 +92,18 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface } /** - * Executes the modules configured via Extbase + * Adds configuration for a module and checks module permissions for the + * current user. * * @param ServerRequestInterface $request - * @param ResponseInterface $response - * @return ResponseInterface A PSR-7 response object + * @param Route $route * @throws \RuntimeException */ - protected function dispatchModule(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + protected function addAndValidateModuleConfiguration(ServerRequestInterface $request, Route $route) { - $route = $request->getAttribute('route'); $moduleName = $route->getOption('moduleName'); $moduleConfiguration = $this->getModuleConfiguration($moduleName); + $route->setOption('moduleConfiguration', $moduleConfiguration); $backendUserAuthentication = $GLOBALS['BE_USER']; @@ -123,37 +123,6 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface } } } - - // Use regular Dispatching - // @todo: unify with the code above - $targetIdentifier = $route->getOption('target'); - if (!empty($targetIdentifier)) { - // @internal routeParameters are a helper construct for the install tool only. - // @todo: remove this, after sub-actions in install tool can be addressed directly - if (!empty($moduleConfiguration['routeParameters'])) { - $request = $request->withQueryParams(array_merge_recursive( - $request->getQueryParams(), - $moduleConfiguration['routeParameters'] - )); - } - return parent::dispatch($request, $response); - } - // extbase module - $configuration = [ - 'extensionName' => $moduleConfiguration['extensionName'], - 'pluginName' => $moduleName - ]; - if (isset($moduleConfiguration['vendorName'])) { - $configuration['vendorName'] = $moduleConfiguration['vendorName']; - } - - // Run Extbase - $bootstrap = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Core\Bootstrap::class); - $content = $bootstrap->run('', $configuration); - - $response->getBody()->write($content); - - return $response; } /** diff --git a/typo3/sysext/backend/Classes/Module/ModuleLoader.php b/typo3/sysext/backend/Classes/Module/ModuleLoader.php index ea1a91f830d0..e742979ca2ba 100644 --- a/typo3/sysext/backend/Classes/Module/ModuleLoader.php +++ b/typo3/sysext/backend/Classes/Module/ModuleLoader.php @@ -140,6 +140,7 @@ class ModuleLoader { // Check for own way of configuring module if (is_array($GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction'])) { + trigger_error('Registering a module using "configureModuleFunction" is deprecated and will be removed in TYPO3 v10.', E_USER_DEPRECATED); $obj = $GLOBALS['TBE_MODULES']['_configuration'][$name]['configureModuleFunction']; if (is_callable($obj)) { $MCONF = call_user_func($obj, $name); @@ -170,14 +171,8 @@ class ModuleLoader // Language processing. This will add module labels and image reference to the internal ->moduleLabels array of the LANG object. $this->addLabelsForModule($name, ($finalModuleConfiguration['labels'] ?? $setupInformation['labels'])); - // Default script setup - if ($setupInformation['configuration']['script'] === '_DISPATCH' || isset($setupInformation['configuration']['routeTarget'])) { - if ($setupInformation['configuration']['extbase']) { - $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl('Tx_' . $name); - } else { - // just go through BackendModuleRequestHandler where the routeTarget is resolved - $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl($name); - } + if (isset($setupInformation['configuration']['routeTarget'])) { + $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl($name); } else { $finalModuleConfiguration['script'] = BackendUtility::getModuleUrl('dummy'); } diff --git a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php index 773f15b010a8..49ea69eabf66 100644 --- a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php +++ b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php @@ -801,9 +801,11 @@ class ExtensionManagementUtility * * @param string $moduleSignature The module name * @return array Configuration of the module + * @deprecated since TYPO3 v9, will be removed in TYPO3 v10, addModule() works the same way nowadays. */ public static function configureModule($moduleSignature) { + trigger_error('This method will be removed in TYPO3 v10, as the same functionality is found in addModule() as well.', E_USER_DEPRECATED); $moduleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature]; // Register the icon and move it too "iconIdentifier" diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82902-CustomBackendModuleRegistrationMethods.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82902-CustomBackendModuleRegistrationMethods.rst new file mode 100644 index 000000000000..d66025f1efd7 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82902-CustomBackendModuleRegistrationMethods.rst @@ -0,0 +1,40 @@ +.. include:: ../../Includes.txt + +================================================================ +Deprecation: #82902 - Custom Backend Module registration methods +================================================================ + +See :issue:`82902` + +Description +=========== + +The internal API to register backend modules via ``ExtensionManagementUtility::configureModule()`` and +``configureModuleFunction`` has been marked as deprecated. + +It was solely introduced to allow script-based dispatching of backend modules used in TYPO3 v6.2 which +had multiple entry-points (mod1/conf.php and mod1/index.php). + +Since TYPO3 v7 Backend Routing is available, thus the old registration API is no longer needed. + +Impact +====== + +Registering a `configureModuleFunction` will trigger a deprecation warning. + +Calling ``ExtensionManagementUtility::configureModule()`` will trigger a deprecation warning. + + +Affected Installations +====================== + +Installations with legacy and/or custom Backend modules in extensions. + + +Migration +========= + +Use either ``ExtensionManagementUtility::addModule()`` or Extbase's +``ExtensionUtility::registerModule()`` to register a module, always providing a ``routeTarget``. + +.. index:: Backend, PHP-API, PartiallyScanned diff --git a/typo3/sysext/extbase/Classes/Core/Bootstrap.php b/typo3/sysext/extbase/Classes/Core/Bootstrap.php index 6b9d9427a193..7ca3ef805712 100644 --- a/typo3/sysext/extbase/Classes/Core/Bootstrap.php +++ b/typo3/sysext/extbase/Classes/Core/Bootstrap.php @@ -14,6 +14,11 @@ namespace TYPO3\CMS\Extbase\Core; * The TYPO3 project - inspiring people to share! */ +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Routing\Route; +use TYPO3\CMS\Extbase\Mvc\Web\Response; + /** * Creates a request an dispatches it to the controller which was specified * by TS Setup, flexForm and returns the content to the v4 framework. @@ -171,6 +176,62 @@ class Bootstrap implements \TYPO3\CMS\Extbase\Core\BootstrapInterface return $content; } + /** + * Entrypoint for backend modules, handling PSR-7 requests/responses + * + * @param ServerRequestInterface $request + * @return ResponseInterface + * @internal + */ + public function handleBackendRequest(ServerRequestInterface $request): ResponseInterface + { + // build the configuration from the Server request / route + /** @var Route $route */ + $route = $request->getAttribute('route'); + $moduleConfiguration = $route->getOption('moduleConfiguration'); + $configuration = [ + 'extensionName' => $moduleConfiguration['extensionName'], + 'pluginName' => $route->getOption('moduleName') + ]; + if (isset($moduleConfiguration['vendorName'])) { + $configuration['vendorName'] = $moduleConfiguration['vendorName']; + } + + $this->initialize($configuration); + + /** @var $requestHandlerResolver \TYPO3\CMS\Extbase\Mvc\RequestHandlerResolver */ + $requestHandlerResolver = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\RequestHandlerResolver::class); + $requestHandler = $requestHandlerResolver->resolveRequestHandler(); + /** @var Response $extbaseResponse */ + $extbaseResponse = $requestHandler->handleRequest(); + + // Convert to PSR-7 response and hand it back to TYPO3 Core + $response = $this->convertExtbaseResponseToPsr7Response($extbaseResponse); + $this->resetSingletons(); + $this->objectManager->get(\TYPO3\CMS\Extbase\Service\CacheService::class)->clearCachesOfRegisteredPageIds(); + return $response; + } + + /** + * Converts a Extbase response object into a PSR-7 Response + * + * @param Response $extbaseResponse + * @return ResponseInterface + */ + protected function convertExtbaseResponseToPsr7Response(Response $extbaseResponse): ResponseInterface + { + $response = new \TYPO3\CMS\Core\Http\Response( + 'php://temp', + $extbaseResponse->getStatusCode(), + $extbaseResponse->getUnpreparedHeaders() + ); + $content = $extbaseResponse->getContent(); + if ($content !== null) { + $response->getBody()->write($content); + } + return $response; + } + /** * Resets global singletons for the next plugin */ diff --git a/typo3/sysext/extbase/Classes/Mvc/Web/Response.php b/typo3/sysext/extbase/Classes/Mvc/Web/Response.php index ea744ce6b393..348e874d169a 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Web/Response.php +++ b/typo3/sysext/extbase/Classes/Mvc/Web/Response.php @@ -157,6 +157,17 @@ class Response extends \TYPO3\CMS\Extbase\Mvc\Response return $this->statusCode . ' ' . $this->statusMessage; } + /** + * Returns the status code, if not set, uses the OK status code 200 + * + * @return int + * @internal only use for backend module handling + */ + public function getStatusCode() + { + return $this->statusCode ?: 200; + } + /** * Sets the specified HTTP header * @@ -200,6 +211,17 @@ class Response extends \TYPO3\CMS\Extbase\Mvc\Response return $preparedHeaders; } + /** + * Returns the HTTP headers grouped by name without the status header + * + * @return array all headers set for this request + * @internal only used within TYPO3 Core to convert to PSR-7 response headers + */ + public function getUnpreparedHeaders(): array + { + return $this->headers; + } + /** * Sends the HTTP headers. * diff --git a/typo3/sysext/extbase/Classes/Utility/ExtensionUtility.php b/typo3/sysext/extbase/Classes/Utility/ExtensionUtility.php index f3f3e59b9dd6..5ecadfd807a4 100644 --- a/typo3/sysext/extbase/Classes/Utility/ExtensionUtility.php +++ b/typo3/sysext/extbase/Classes/Utility/ExtensionUtility.php @@ -193,8 +193,7 @@ tt_content.' . $pluginSignature . ' { $moduleConfiguration['vendorName'] = $vendorName; } $moduleConfiguration['extensionName'] = $extensionName; - $moduleConfiguration['configureModuleFunction'] = [\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::class, 'configureModule']; - $GLOBALS['TBE_MODULES']['_configuration'][$moduleSignature] = $moduleConfiguration; + $moduleConfiguration['routeTarget'] = \TYPO3\CMS\Extbase\Core\Bootstrap::class . '::handleBackendRequest'; if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature])) { $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$moduleSignature] = []; } @@ -203,7 +202,7 @@ tt_content.' . $pluginSignature . ' { 'actions' => \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $actions) ]; } - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addModule($mainModuleName, $subModuleName, $position); + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addModule($mainModuleName, $subModuleName, $position, null, $moduleConfiguration); } /** diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php index 6788f44a156d..ac5210ae926f 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php @@ -491,4 +491,11 @@ return [ 'Deprecation-82899-ExtensionManagementUtilityMethods.rst', ], ], + 'TYPO3\CMS\Core\Utility\ExtensionManagementUtility::configureModule' => [ + 'numberOfMandatoryArguments' => 0, + 'maximumNumberOfArguments' => 0, + 'restFiles' => [ + 'Deprecation-82902-CustomBackendModuleRegistrationMethods.rst', + ], + ], ]; -- GitLab