diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php index c7f8b60062cf3280e184d8ab9b307fbbb69bad61..8a1d390574061d8341568f131d9c0c2ca92ca896 100644 --- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php +++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php @@ -307,6 +307,7 @@ class ShortcutToolbarItem implements ToolbarItemInterface /** * Adds the correct token, if the url is an index.php script + * @todo: this needs love * * @param string $url * @return string @@ -320,16 +321,20 @@ class ShortcutToolbarItem implements ToolbarItemInterface if (isset($parameters['returnUrl'])) { $parsedReturnUrl = parse_url($parameters['returnUrl']); parse_str($parsedReturnUrl['query'], $returnUrlParameters); - if (strpos($parsedReturnUrl['path'], 'index.php') !== false && isset($returnUrlParameters['M'])) { - $module = $returnUrlParameters['M']; + if (strpos($parsedReturnUrl['path'], 'index.php') !== false && !empty($returnUrlParameters['route'])) { + $module = $returnUrlParameters['route']; $returnUrl = BackendUtility::getModuleUrl($module, $returnUrlParameters); $parameters['returnUrl'] = $returnUrl; $url = $parsedUrl['path'] . '?' . http_build_query($parameters, '', '&', PHP_QUERY_RFC3986); } } + if (isset($parameters['M']) && empty($parameters['route'])) { + $parameters['route'] = $parameters['M']; + unset($parameters['M']); + } - if (strpos($parsedUrl['path'], 'index.php') !== false && isset($parameters['M'])) { - $module = $parameters['M']; + if (strpos($parsedUrl['path'], 'index.php') !== false && isset($parameters['route'])) { + $module = $parameters['route']; $url = BackendUtility::getModuleUrl($module, $parameters); } elseif (strpos($parsedUrl['path'], 'index.php') !== false && isset($parameters['route'])) { $routePath = $parameters['route']; diff --git a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php index 952a8f5bfab9914ba2c987e655c6de3dd5714847..7b2502c12ea50f7069fc01175eb436d4e78298c9 100644 --- a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php +++ b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php @@ -1287,13 +1287,13 @@ class EditDocumentController extends AbstractModule $returnUrl = $this->retUrl; if ($this->firstEl['table'] === 'pages') { parse_str((string)parse_url($returnUrl, PHP_URL_QUERY), $queryParams); - if (isset($queryParams['M']) + if (isset($queryParams['route']) && isset($queryParams['id']) && (string)$this->firstEl['uid'] === (string)$queryParams['id'] ) { // TODO: Use the page's pid instead of 0, this requires a clean API to manipulate the page // tree from the outside to be able to mark the pid as active - $returnUrl = BackendUtility::getModuleUrl($queryParams['M'], ['id' => 0]); + $returnUrl = BackendUtility::getModuleUrl($queryParams['route'], ['id' => 0]); } } $deleteButton = $buttonBar->makeLinkButton() diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php index fdf5f593be8353b2eb80cdcf2d2ce9f9d741e83d..ddfff72aabc9b4cad917d3968727db033f55b488 100644 --- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php +++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php @@ -975,7 +975,7 @@ class PageLayoutController ->setModuleName($this->moduleName) ->setGetVariables([ 'id', - 'M', + 'route', 'edit_record', 'pointer', 'new_unique_uid', diff --git a/typo3/sysext/backend/Classes/Http/Application.php b/typo3/sysext/backend/Classes/Http/Application.php index 683a1b35f0ddfe09d9b57f4155fcc7282d165c68..fe59180c9f236e19b365cbf08667c4d92555970a 100644 --- a/typo3/sysext/backend/Classes/Http/Application.php +++ b/typo3/sysext/backend/Classes/Http/Application.php @@ -33,18 +33,12 @@ class Application implements ApplicationInterface */ protected $entryPointLevel = 1; - /** - * @var \Psr\Http\Message\ServerRequestInterface - */ - protected $request; - /** * All available request handlers that can handle backend requests (non-CLI) * @var array */ protected $availableRequestHandlers = [ \TYPO3\CMS\Backend\Http\RequestHandler::class, - \TYPO3\CMS\Backend\Http\BackendModuleRequestHandler::class, \TYPO3\CMS\Backend\Http\AjaxRequestHandler::class ]; @@ -81,12 +75,7 @@ class Application implements ApplicationInterface */ public function run(callable $execute = null) { - $this->request = \TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals(); - if (isset($this->request->getQueryParams()['M'])) { - $this->request = $this->request->withAttribute('isModuleRequest', true); - } - - $this->bootstrap->handleRequest($this->request); + $this->bootstrap->handleRequest(\TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals()); if ($execute !== null) { call_user_func($execute); diff --git a/typo3/sysext/backend/Classes/Http/BackendModuleRequestHandler.php b/typo3/sysext/backend/Classes/Http/BackendModuleRequestHandler.php deleted file mode 100644 index 38c5d073db07bca46e52094d1bb5514aa8db01d1..0000000000000000000000000000000000000000 --- a/typo3/sysext/backend/Classes/Http/BackendModuleRequestHandler.php +++ /dev/null @@ -1,222 +0,0 @@ -<?php -namespace TYPO3\CMS\Backend\Http; - -/* - * This file is part of the TYPO3 CMS project. - * - * It is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, either version 2 - * of the License, or any later version. - * - * For the full copyright and license information, please read the - * LICENSE.txt file that was distributed with this source code. - * - * The TYPO3 project - inspiring people to share! - */ - -use Psr\Http\Message\ServerRequestInterface; -use TYPO3\CMS\Backend\Utility\BackendUtility; -use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Core\Core\Bootstrap; -use TYPO3\CMS\Core\Exception; -use TYPO3\CMS\Core\FormProtection\BackendFormProtection; -use TYPO3\CMS\Core\FormProtection\FormProtectionFactory; -use TYPO3\CMS\Core\Http\Dispatcher; -use TYPO3\CMS\Core\Http\RequestHandlerInterface; -use TYPO3\CMS\Core\Http\Response; -use TYPO3\CMS\Core\Type\Bitmask\Permission; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\MathUtility; - -/** - * Handles the request for backend modules and wizards - * Juggles with $GLOBALS['TBE_MODULES'] - */ -class BackendModuleRequestHandler implements RequestHandlerInterface -{ - /** - * @var Bootstrap - */ - protected $bootstrap; - - /** - * @var array - */ - protected $moduleRegistry = []; - - /** - * @var BackendUserAuthentication - */ - protected $backendUserAuthentication; - - /** - * Instance of the current Http Request - * @var ServerRequestInterface - */ - protected $request; - - /** - * Constructor handing over the bootstrap and the original request - * - * @param Bootstrap $bootstrap - */ - public function __construct(Bootstrap $bootstrap) - { - $this->bootstrap = $bootstrap; - } - - /** - * Handles the request, evaluating the configuration and executes the module accordingly - * - * @param ServerRequestInterface $request - * @return NULL|\Psr\Http\Message\ResponseInterface - * @throws Exception - */ - public function handleRequest(ServerRequestInterface $request) - { - $this->request = $request; - $this->boot(); - - $this->moduleRegistry = $GLOBALS['TBE_MODULES']; - - if (!$this->isValidModuleRequest()) { - throw new Exception('The CSRF protection token for the requested module is missing or invalid', 1417988921); - } - - $this->backendUserAuthentication = $GLOBALS['BE_USER']; - - $moduleName = (string)$this->request->getQueryParams()['M']; - return $this->dispatchModule($moduleName); - } - - /** - * Execute TYPO3 bootstrap - */ - protected function boot() - { - $this->bootstrap->checkLockedBackendAndRedirectOrDie() - ->checkBackendIpOrDie() - ->checkSslBackendAndRedirectIfNeeded() - ->initializeBackendRouter() - ->loadExtTables() - ->initializeBackendUser() - ->initializeBackendAuthentication() - ->initializeLanguageObject() - ->initializeBackendTemplate() - ->endOutputBufferingAndCleanPreviousOutput() - ->initializeOutputCompression() - ->sendHttpHeaders(); - } - - /** - * This request handler can handle any backend request coming from index.php - * - * @param ServerRequestInterface $request - * @return bool - */ - public function canHandleRequest(ServerRequestInterface $request) - { - return $request->getAttribute('isModuleRequest', false); - } - - /** - * Checks if all parameters are met. - * - * @return bool - */ - protected function isValidModuleRequest() - { - return $this->getFormProtection() instanceof BackendFormProtection - && $this->getFormProtection()->validateToken((string)$this->request->getQueryParams()['moduleToken'], 'moduleCall', (string)$this->request->getQueryParams()['M']); - } - - /** - * Executes the modules configured via Extbase - * - * @param string $moduleName - * @return Response A PSR-7 response object - * @throws \RuntimeException - */ - protected function dispatchModule($moduleName) - { - $moduleConfiguration = $this->getModuleConfiguration($moduleName); - - $response = GeneralUtility::makeInstance(Response::class); - - // Check permissions and exit if the user has no permission for entry - $this->backendUserAuthentication->modAccess($moduleConfiguration, true); - $id = isset($this->request->getQueryParams()['id']) ? $this->request->getQueryParams()['id'] : $this->request->getParsedBody()['id']; - if ($id && MathUtility::canBeInterpretedAsInteger($id)) { - $permClause = $this->backendUserAuthentication->getPagePermsClause(Permission::PAGE_SHOW); - // Check page access - $access = is_array(BackendUtility::readPageAccess((int)$id, $permClause)); - if (!$access) { - // Check if page has been deleted - $deleteField = $GLOBALS['TCA']['pages']['ctrl']['delete']; - $pageInfo = BackendUtility::getRecord('pages', (int)$id, $deleteField, $permClause ? ' AND ' . $permClause : '', false); - if (!$pageInfo[$deleteField]) { - throw new \RuntimeException('You don\'t have access to this page', 1289917924); - } - } - } - - // Use Core Dispatching - if (isset($moduleConfiguration['routeTarget'])) { - $dispatcher = GeneralUtility::makeInstance(Dispatcher::class); - $this->request = $this->request->withAttribute('target', $moduleConfiguration['routeTarget']); - $response = $dispatcher->dispatch($this->request, $response); - } else { - // 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; - } - - /** - * Returns the module configuration which is provided during module registration - * - * @param string $moduleName - * @return array - * @throws \RuntimeException - */ - protected function getModuleConfiguration($moduleName) - { - if (!isset($this->moduleRegistry['_configuration'][$moduleName])) { - throw new \RuntimeException('Module ' . $moduleName . ' is not configured.', 1289918325); - } - return $this->moduleRegistry['_configuration'][$moduleName]; - } - - /** - * Returns the priority - how eager the handler is to actually handle the request. - * - * @return int The priority of the request handler. - */ - public function getPriority() - { - return 90; - } - - /** - * Wrapper method for static form protection utility - * - * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection - */ - protected function getFormProtection() - { - return FormProtectionFactory::get(); - } -} diff --git a/typo3/sysext/backend/Classes/Http/RequestHandler.php b/typo3/sysext/backend/Classes/Http/RequestHandler.php index 084e891a6e200257fffe5bb60250d53bdad4d2d5..a24905f77b2f4c540cce8acb870aa1a62fe1f85c 100644 --- a/typo3/sysext/backend/Classes/Http/RequestHandler.php +++ b/typo3/sysext/backend/Classes/Http/RequestHandler.php @@ -59,14 +59,22 @@ class RequestHandler implements RequestHandlerInterface */ public function handleRequest(ServerRequestInterface $request) { + // Check if a module URL is requested and deprecate this call + $moduleName = $request->getQueryParams()['M'] ?? $request->getParsedBody()['M'] ?? null; // Allow the login page to be displayed if routing is not used and on index.php - $pathToRoute = (string)$request->getQueryParams()['route'] ?: '/login'; + $pathToRoute = $request->getQueryParams()['route'] ?? $request->getParsedBody()['route'] ?? $moduleName ?? '/login'; $request = $request->withAttribute('routePath', $pathToRoute); // skip the BE user check on the login page // should be handled differently in the future by checking the Bootstrap directly $this->boot($pathToRoute === '/login'); + if ($moduleName !== null) { + trigger_error('Calling the TYPO3 Backend with "M" GET parameter will be removed in TYPO3 v10,' + . ' the calling code calls this script with "&M=' . $moduleName . '" and needs to be adapted' + . ' to use the TYPO3 API.', E_USER_DEPRECATED); + } + // Check if the router has the available route and dispatch. try { return $this->dispatch($request); diff --git a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php index 957f85c785c7a09eed65abbafa46fdb7983942af..bfd9bc6339049680269c2cd116a5260c8daa2f2c 100644 --- a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php +++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php @@ -19,9 +19,12 @@ use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Routing\Exception\InvalidRequestTokenException; use TYPO3\CMS\Backend\Routing\Route; use TYPO3\CMS\Backend\Routing\Router; +use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\FormProtection\FormProtectionFactory; use TYPO3\CMS\Core\Http\Dispatcher; use TYPO3\CMS\Core\Http\DispatcherInterface; +use TYPO3\CMS\Core\Http\Response; +use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -45,10 +48,14 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface /** @var Route $route */ $route = $router->matchRequest($request); $request = $request->withAttribute('route', $route); + $request = $request->withAttribute('target', $route->getOption('target')); if (!$this->isValidRequest($request)) { throw new InvalidRequestTokenException('Invalid request for route "' . $route->getPath() . '"', 1425389455); } + if ($route->getOption('module')) { + return $this->dispatchModule($request, $response); + } $targetIdentifier = $route->getOption('target'); $target = $this->getCallableFromTarget($targetIdentifier); return call_user_func_array($target, [$request, $response]); @@ -82,4 +89,84 @@ class RouteDispatcher extends Dispatcher implements DispatcherInterface $token = (string)(isset($request->getParsedBody()['token']) ? $request->getParsedBody()['token'] : $request->getQueryParams()['token']); return $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier')); } + + /** + * Executes the modules configured via Extbase + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface A PSR-7 response object + * @throws \RuntimeException + */ + protected function dispatchModule(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $route = $request->getAttribute('route'); + $moduleName = $route->getOption('moduleName'); + $moduleConfiguration = $this->getModuleConfiguration($moduleName); + + $backendUserAuthentication = $GLOBALS['BE_USER']; + + // Check permissions and exit if the user has no permission for entry + // @todo please do not use "true" here, what a bad coding paradigm + $backendUserAuthentication->modAccess($moduleConfiguration, true); + $id = (int)$request->getQueryParams()['id'] ?? $request->getParsedBody()['id']; + if ($id) { + $permClause = $backendUserAuthentication->getPagePermsClause(Permission::PAGE_SHOW); + // Check page access + if (!is_array(BackendUtility::readPageAccess($id, $permClause))) { + // Check if page has been deleted + $deleteField = $GLOBALS['TCA']['pages']['ctrl']['delete']; + $pageInfo = BackendUtility::getRecord('pages', $id, $deleteField, $permClause ? ' AND ' . $permClause : '', false); + if (!$pageInfo[$deleteField]) { + throw new \RuntimeException('You don\'t have access to this page', 1289917924); + } + } + } + + // 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; + } + + /** + * Returns the module configuration which is provided during module registration + * + * @param string $moduleName + * @return array + * @throws \RuntimeException + */ + protected function getModuleConfiguration($moduleName) + { + if (!isset($GLOBALS['TBE_MODULES']['_configuration'][$moduleName])) { + throw new \RuntimeException('Module ' . $moduleName . ' is not configured.', 1289918325); + } + return $GLOBALS['TBE_MODULES']['_configuration'][$moduleName]; + } } diff --git a/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php b/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php index 21d9a61b79197ba61ba51a3c402aea290dba9791..2bb2b17f33d0b8761d4dd15fa7f29f41652ea94e 100644 --- a/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php +++ b/typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php @@ -15,9 +15,7 @@ namespace TYPO3\CMS\Backend\RecordList; */ use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider; -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; -use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; @@ -215,12 +213,8 @@ abstract class AbstractRecordList protected function determineScriptUrl() { if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/backend/Classes/Routing/UriBuilder.php b/typo3/sysext/backend/Classes/Routing/UriBuilder.php index 93e5fadabb38a5672ff999e38de37f0ec0d426da..f2a9d313b8c1a57972bdbdff7f525068e4f2b913 100644 --- a/typo3/sysext/backend/Classes/Routing/UriBuilder.php +++ b/typo3/sysext/backend/Classes/Routing/UriBuilder.php @@ -54,6 +54,25 @@ class UriBuilder $this->routes = $router->getRoutes(); } + /** + * Generates a URL or path for a specific route based on the given rout. + * Currently used to link to the current script, it is encouraged to use "buildUriFromRoute" if possible. + * + * If there is no route with the given name, the generator throws the RouteNotFoundException. + * + * @param string $pathInfo The path to the route + * @param array $parameters An array of parameters + * @param string $referenceType The type of reference to be generated (one of the constants) + * @return Uri The generated Uri + * @throws RouteNotFoundException If the named route doesn't exist + */ + public function buildUriFromRoutePath($pathInfo, $parameters = [], $referenceType = self::ABSOLUTE_PATH) + { + $router = GeneralUtility::makeInstance(Router::class); + $route = $router->match($pathInfo); + return $this->buildUriFromRoute($route->getOption('_identifier'), $parameters, $referenceType); + } + /** * Generates a URL or path for a specific route based on the given parameters. * When the route is configured with "access=public" then the token generation is left out. @@ -106,8 +125,8 @@ class UriBuilder public function buildUriFromModule($moduleName, $parameters = [], $referenceType = self::ABSOLUTE_PATH) { $parameters = [ - 'M' => $moduleName, - 'moduleToken' => FormProtectionFactory::get('backend')->generateToken('moduleCall', $moduleName) + 'route' => $moduleName, + 'token' => FormProtectionFactory::get('backend')->generateToken('route', $moduleName) ] + $parameters; return $this->buildUri($parameters, $referenceType); } diff --git a/typo3/sysext/backend/Classes/Template/Components/Buttons/Action/ShortcutButton.php b/typo3/sysext/backend/Classes/Template/Components/Buttons/Action/ShortcutButton.php index 14db2a1d29424eacc974fdb18bbd514d8037ad17..b3b815041ad59c8dae8d7e6862dcd8fe11868363 100644 --- a/typo3/sysext/backend/Classes/Template/Components/Buttons/Action/ShortcutButton.php +++ b/typo3/sysext/backend/Classes/Template/Components/Buttons/Action/ShortcutButton.php @@ -239,7 +239,7 @@ class ShortcutButton implements ButtonInterface, PositionInterface // Set default GET parameters if ($emptyGetVariables) { - $this->getVariables = ['id', 'M']; + $this->getVariables = ['id', 'route']; } // Automatically determine module name in Extbase context diff --git a/typo3/sysext/backend/Classes/Template/DocumentTemplate.php b/typo3/sysext/backend/Classes/Template/DocumentTemplate.php index 02365ea0deb4128a450984be95662f500d6f4977..446bf200151d18cf2625e62ec3cad1db34b69d8e 100644 --- a/typo3/sysext/backend/Classes/Template/DocumentTemplate.php +++ b/typo3/sysext/backend/Classes/Template/DocumentTemplate.php @@ -251,7 +251,7 @@ function jumpToUrl(URL) { $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class); // Setting default scriptID, trim forward slash from route - $this->scriptID = GeneralUtility::_GET('M') !== null ? GeneralUtility::_GET('M') : ltrim(GeneralUtility::_GET('route'), '/'); + $this->scriptID = ltrim(GeneralUtility::_GET('route'), '/'); $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID); // Individual configuration per script? If so, make a recursive merge of the arrays: if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) { diff --git a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php index f8b6622b1268b3e8befda5028fb81e42a6fe4cd3..aa55258e0fa6e145e38b2bf97b76be07d9a79da8 100644 --- a/typo3/sysext/backend/Classes/Template/ModuleTemplate.php +++ b/typo3/sysext/backend/Classes/Template/ModuleTemplate.php @@ -510,8 +510,9 @@ class ModuleTemplate // since this is used for icons. $moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName; // Add the module identifier automatically if typo3/index.php is used: - if (GeneralUtility::_GET('M') !== null) { - $storeUrl = '&M=' . $moduleName . $storeUrl; + // @todo: routing + if (GeneralUtility::_GET('route') !== null) { + $storeUrl = '&route=' . $moduleName . $storeUrl; } if ((int)$motherModName === 1) { $motherModule = 'top.currentModuleLoaded'; diff --git a/typo3/sysext/backend/Classes/Tree/View/AbstractTreeView.php b/typo3/sysext/backend/Classes/Tree/View/AbstractTreeView.php index 2564e31bf185bd0cece9144e9939caa3d5f39c9c..13dab282fae1b8365f66b1052b037254462fad92 100644 --- a/typo3/sysext/backend/Classes/Tree/View/AbstractTreeView.php +++ b/typo3/sysext/backend/Classes/Tree/View/AbstractTreeView.php @@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Tree\View; * The TYPO3 project - inspiring people to share! */ -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Tree\Pagetree\Commands; use TYPO3\CMS\Backend\Utility\BackendUtility; @@ -289,12 +288,8 @@ abstract class AbstractTreeView protected function determineScriptUrl() { if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php index 103a2feb361be0fde0a3ff1d8b6b2e272ac8b626..46af96a288d908e719dc534b626d313971082c03 100644 --- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php +++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php @@ -2950,14 +2950,10 @@ class BackendUtility $script = basename(PATH_thisScript); } - if (GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Router::class); - $route = $router->match(GeneralUtility::_GP('route')); + if ($routePath = GeneralUtility::_GP('route')) { $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); - $scriptUrl = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); + $scriptUrl = (string)$uriBuilder->buildUriFromRoutePath($routePath, $mainParams); $scriptUrl .= $addParams; - } elseif ($script === 'index.php' && GeneralUtility::_GET('M')) { - $scriptUrl = self::getModuleUrl(GeneralUtility::_GET('M'), $mainParams) . $addParams; } else { $scriptUrl = $script . '?' . GeneralUtility::implodeArrayForUrl('', $mainParams) . $addParams; } @@ -3169,8 +3165,7 @@ class BackendUtility try { $uri = $uriBuilder->buildUriFromRoute($moduleName, $urlParameters); } catch (\TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException $e) { - // no route registered, use the fallback logic to check for a module - $uri = $uriBuilder->buildUriFromModule($moduleName, $urlParameters); + $uri = $uriBuilder->buildUriFromRoutePath($moduleName, $urlParameters); } return (string)$uri; } diff --git a/typo3/sysext/beuser/Classes/Controller/BackendUserActionController.php b/typo3/sysext/beuser/Classes/Controller/BackendUserActionController.php index fe9bce3f6a9a965fee41849c6428f8c2f4d0fa14..61a1a70eb9750774b1e42b6de218574d05fdad66 100644 --- a/typo3/sysext/beuser/Classes/Controller/BackendUserActionController.php +++ b/typo3/sysext/beuser/Classes/Controller/BackendUserActionController.php @@ -125,7 +125,7 @@ class BackendUserActionController extends ActionController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutName = $this->getLanguageService()->sL('LLL:EXT:beuser/Resources/Private/Language/locallang.xml:backendUsers'); if ($this->request->getControllerName() === 'BackendUser') { diff --git a/typo3/sysext/beuser/Classes/Controller/PermissionController.php b/typo3/sysext/beuser/Classes/Controller/PermissionController.php index 81155f031aca938ff34d153f4a05db7bbdeb7c81..072dd3bf481f6f4d7709c1fe2b436cce98ce9fdd 100644 --- a/typo3/sysext/beuser/Classes/Controller/PermissionController.php +++ b/typo3/sysext/beuser/Classes/Controller/PermissionController.php @@ -158,7 +158,7 @@ class PermissionController extends ActionController $extensionName = $currentRequest->getControllerExtensionName(); if (empty($getVars)) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } if ($currentRequest->getControllerActionName() === 'edit') { diff --git a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php index c0f3b752e46a1ffc5e03ef11aacfe97ffc75f012..292524f2a5501875a38b94708efe7f2db7844d67 100644 --- a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php +++ b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php @@ -858,9 +858,8 @@ class ExtensionManagementUtility } // add additional configuration + $fullModuleSignature = $main . ($sub ? '_' . $sub : ''); if (is_array($moduleConfiguration) && !empty($moduleConfiguration)) { - $fullModuleSignature = $main . ($sub ? '_' . $sub : ''); - if (!empty($moduleConfiguration['icon'])) { $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); $iconIdentifier = 'module-' . $fullModuleSignature; @@ -876,6 +875,32 @@ class ExtensionManagementUtility $GLOBALS['TBE_MODULES']['_configuration'][$fullModuleSignature] = $moduleConfiguration; } + + // Also register the module as regular route + // Build Route objects from the data + $name = $fullModuleSignature; + if (isset($moduleConfiguration['path'])) { + $path = $moduleConfiguration['path']; + } else { + $path = str_replace('_', '/', $name); + } + $path = '/' . trim($path, '/') . '/'; + + $options = [ + 'module' => true, + 'moduleName' => $fullModuleSignature, + 'access' => $moduleConfiguration['access'] ?: 'user,group' + ]; + if ($moduleConfiguration['routeTarget']) { + $options['target'] = $moduleConfiguration['routeTarget']; + } + + $router = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Router::class); + $router->addRoute( + $name, + // @todo: see if we should do a "module route" + GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Route::class, $path, $options) + ); } /** diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-82406-RoutingBackendModulesRunThroughRegularDispatcher.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-82406-RoutingBackendModulesRunThroughRegularDispatcher.rst new file mode 100644 index 0000000000000000000000000000000000000000..fd79b8e5a70883715c7ddd39b64cdce77a85017e --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-82406-RoutingBackendModulesRunThroughRegularDispatcher.rst @@ -0,0 +1,49 @@ +.. include:: ../../Includes.txt + +========================================================================== +Breaking: #82406 - Routing: Backend Modules run through regular dispatcher +========================================================================== + +See :issue:`82406` + +Description +=========== + +Calling Backend modules was previously handled via a special `BackendModuleRequestHandler` which has +been removed. + +When registering a Backend module, a route with the name of the module is automatically added to the +Backend Router. + +When generating URLs for modules, the module is not added via the GET Parameter `&M=moduleName` +anymore, but built like any other Backend Route (currently with the "route" and "token" parameters) + +All request handling functionality is now done by the regular Backend RequestHandler, +which checks if the Route to be targeted is a module, and does extra module permission checks. + + +Impact +====== + +Handling with the "&M" GET parameter in backend modules won't deliver the correct result anymore. + +Instantiating `BackendModuleRequestHandler` will result in a fatal PHP error. + + +Affected Installations +====================== + +Installations with custom extensions including backend modules which work directly with the GET +parameter "M". + + +Migration +========= + +If extensions use API methods like ``BackendUtility::getModuleUrl()`` are used, nothing needs to be +modified. + +If a backend module is using the GET parameter "M" currently, the code needs to be adjusted to the +GET "route" or use the UriBuilder directly. + +.. index:: Backend, PartiallyScanned diff --git a/typo3/sysext/cshmanual/Classes/Controller/HelpController.php b/typo3/sysext/cshmanual/Classes/Controller/HelpController.php index e623c99fde9db92c22328e9d9aab9162698b5391..06e25777560850bda48da1f7079ce46b749124bb 100644 --- a/typo3/sysext/cshmanual/Classes/Controller/HelpController.php +++ b/typo3/sysext/cshmanual/Classes/Controller/HelpController.php @@ -151,7 +151,7 @@ class HelpController extends ActionController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($moduleName) diff --git a/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php b/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php index f27a50666ee216642a7549cb27bb44ddf2ca11ae..169644191b2e291a67914611917182bf2b6b2f5a 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php +++ b/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php @@ -664,24 +664,32 @@ class UriBuilder } } else { $id = GeneralUtility::_GP('id'); - $module = GeneralUtility::_GP('M'); + $module = GeneralUtility::_GP('route'); if ($id !== null) { $arguments['id'] = $id; } if ($module !== null) { - $arguments['M'] = $module; + $arguments['route'] = $module; } } ArrayUtility::mergeRecursiveWithOverrule($arguments, $this->arguments); $arguments = $this->convertDomainObjectsToIdentityArrays($arguments); $this->lastArguments = $arguments; - $moduleName = $arguments['M']; - unset($arguments['M'], $arguments['moduleToken']); + $moduleName = $arguments['route'] ?? null; + unset($arguments['route'], $arguments['token']); $backendUriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class); - if ($this->request instanceof WebRequest && $this->createAbsoluteUri) { - $uri = (string)$backendUriBuilder->buildUriFromModule($moduleName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL); + if (!empty($moduleName)) { + if ($this->request instanceof WebRequest && $this->createAbsoluteUri) { + $uri = (string)$backendUriBuilder->buildUriFromRoutePath($moduleName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL); + } else { + $uri = (string)$backendUriBuilder->buildUriFromRoutePath($moduleName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_PATH); + } } else { - $uri = (string)$backendUriBuilder->buildUriFromModule($moduleName, $arguments); + if ($this->request instanceof WebRequest && $this->createAbsoluteUri) { + $uri = (string)$backendUriBuilder->buildUriFromModule($moduleName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL); + } else { + $uri = (string)$backendUriBuilder->buildUriFromModule($moduleName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_PATH); + } } if ($this->section !== '') { $uri .= '#' . $this->section; diff --git a/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php b/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php index a86b73b6d3cca85584fa91e9eb3e70e712850a42..063f27200e48cb37ec292fcc89722e43f52bcb35 100644 --- a/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php +++ b/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php @@ -13,6 +13,8 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Mvc\Web\Routing; * * The TYPO3 project - inspiring people to share! */ +use TYPO3\CMS\Backend\Routing\Route; +use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManager; @@ -76,6 +78,9 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->uriBuilder->_set('configurationManager', $this->mockConfigurationManager); $this->uriBuilder->_set('extensionService', $this->mockExtensionService); $this->uriBuilder->_set('environmentService', $this->createMock(EnvironmentService::class)); + $router = GeneralUtility::makeInstance(Router::class); + $router->addRoute('module_key', new Route('/test/Path', [])); + $router->addRoute('module_key2', new Route('/test/Path2', [])); // Mocking backend user is required for backend URI generation as BackendUtility::getModuleUrl() is called $backendUserMock = $this->createMock(BackendUserAuthentication::class); $backendUserMock->expects($this->any())->method('check')->will($this->returnValue(true)); @@ -207,12 +212,12 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriKeepsQueryParametersIfAddQueryStringIsSet() { - GeneralUtility::_GETset(['M' => 'moduleKey', 'id' => 'pageId', 'foo' => 'bar']); + GeneralUtility::_GETset(['route' => '/test/Path', 'id' => 'pageId', 'foo' => 'bar']); $_POST = []; $_POST['foo2'] = 'bar2'; $this->uriBuilder->setAddQueryString(true); $this->uriBuilder->setAddQueryStringMethod('GET,POST'); - $expectedResult = '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&id=pageId&foo=bar&foo2=bar2'; + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&id=pageId&foo=bar&foo2=bar2'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -222,12 +227,12 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriKeepsQueryParametersIfAddQueryStringMethodIsNotSet() { - GeneralUtility::_GETset(['M' => 'moduleKey', 'id' => 'pageId', 'foo' => 'bar']); + GeneralUtility::_GETset(['route' => '/test/Path', 'id' => 'pageId', 'foo' => 'bar']); $_POST = []; $_POST['foo2'] = 'bar2'; $this->uriBuilder->setAddQueryString(true); $this->uriBuilder->setAddQueryStringMethod(null); - $expectedResult = '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&id=pageId&foo=bar'; + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&id=pageId&foo=bar'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -240,7 +245,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase return [ 'Arguments to be excluded in the beginning' => [ [ - 'M' => 'moduleKey', + 'route' => '/test/Path', 'id' => 'pageId', 'foo' => 'bar' ], @@ -248,25 +253,25 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'foo2' => 'bar2' ], [ - 'M', + 'route', 'id' ], - '/typo3/index.php?M=&moduleToken=dummyToken&foo=bar&foo2=bar2' + '/typo3/index.php?route=&token=dummyToken&foo=bar&foo2=bar2' ], 'Arguments to be excluded in the end' => [ [ 'foo' => 'bar', 'id' => 'pageId', - 'M' => 'moduleKey' + 'route' => '/test/Path' ], [ 'foo2' => 'bar2' ], [ - 'M', + 'route', 'id' ], - '/typo3/index.php?M=&moduleToken=dummyToken&foo=bar&foo2=bar2' + '/typo3/index.php?route=&token=dummyToken&foo=bar&foo2=bar2' ], 'Arguments in nested array to be excluded' => [ [ @@ -274,7 +279,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'bar' => 'baz' ], 'id' => 'pageId', - 'M' => 'moduleKey' + 'route' => '/test/Path' ], [ 'foo2' => 'bar2' @@ -283,7 +288,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'id', 'tx_foo[bar]' ], - '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&foo2=bar2' + '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&foo2=bar2' ], 'Arguments in multidimensional array to be excluded' => [ [ @@ -293,7 +298,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase ] ], 'id' => 'pageId', - 'M' => 'moduleKey' + 'route' => '/test/Path' ], [ 'foo2' => 'bar2' @@ -302,7 +307,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase 'id', 'tx_foo[bar][baz]' ], - '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&foo2=bar2' + '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&foo2=bar2' ], ]; } @@ -331,8 +336,8 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriKeepsModuleQueryParametersIfAddQueryStringIsNotSet() { - GeneralUtility::_GETset(['M' => 'moduleKey', 'id' => 'pageId', 'foo' => 'bar']); - $expectedResult = '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&id=pageId'; + GeneralUtility::_GETset(['route' => '/test/Path', 'id' => 'pageId', 'foo' => 'bar']); + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&id=pageId'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -342,9 +347,9 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriMergesAndOverrulesQueryParametersWithArguments() { - GeneralUtility::_GETset(['M' => 'moduleKey', 'id' => 'pageId', 'foo' => 'bar']); - $this->uriBuilder->setArguments(['M' => 'overwrittenModuleKey', 'somePrefix' => ['bar' => 'baz']]); - $expectedResult = '/typo3/index.php?M=overwrittenModuleKey&moduleToken=dummyToken&id=pageId&somePrefix%5Bbar%5D=baz'; + GeneralUtility::_GETset(['route' => '/test/Path', 'id' => 'pageId', 'foo' => 'bar']); + $this->uriBuilder->setArguments(['route' => '/test/Path2', 'somePrefix' => ['bar' => 'baz']]); + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath2&token=dummyToken&id=pageId&somePrefix%5Bbar%5D=baz'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -354,11 +359,11 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriConvertsDomainObjectsAfterArgumentsHaveBeenMerged() { - GeneralUtility::_GETset(['M' => 'moduleKey']); + GeneralUtility::_GETset(['route' => '/test/Path']); $mockDomainObject = $this->getAccessibleMock(AbstractEntity::class, ['dummy']); $mockDomainObject->_set('uid', '123'); $this->uriBuilder->setArguments(['somePrefix' => ['someDomainObject' => $mockDomainObject]]); - $expectedResult = '/typo3/index.php?M=moduleKey&moduleToken=dummyToken&somePrefix%5BsomeDomainObject%5D=123'; + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken&somePrefix%5BsomeDomainObject%5D=123'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -368,9 +373,9 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase */ public function buildBackendUriRespectsSection() { - GeneralUtility::_GETset(['M' => 'moduleKey']); + GeneralUtility::_GETset(['route' => '/test/Path']); $this->uriBuilder->setSection('someSection'); - $expectedResult = '/typo3/index.php?M=moduleKey&moduleToken=dummyToken#someSection'; + $expectedResult = '/typo3/index.php?route=%2Ftest%2FPath&token=dummyToken#someSection'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -381,12 +386,12 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase public function buildBackendUriCreatesAbsoluteUrisIfSpecified() { GeneralUtility::flushInternalRuntimeCaches(); - GeneralUtility::_GETset(['M' => 'moduleKey']); + GeneralUtility::_GETset(['route' => '/test/Path']); $_SERVER['HTTP_HOST'] = 'baseuri'; $_SERVER['SCRIPT_NAME'] = '/typo3/index.php'; $this->mockRequest->expects($this->any())->method('getBaseUri')->will($this->returnValue('http://baseuri')); $this->uriBuilder->setCreateAbsoluteUri(true); - $expectedResult = 'http://baseuri/' . TYPO3_mainDir . 'index.php?M=moduleKey&moduleToken=dummyToken'; + $expectedResult = 'http://baseuri/' . TYPO3_mainDir . 'index.php?route=%2Ftest%2FPath&token=dummyToken'; $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertSame($expectedResult, $actualResult); } @@ -419,7 +424,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase ]; $this->uriBuilder->setAddQueryString(true); $this->uriBuilder->setAddQueryStringMethod('POST,GET'); - $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('/typo3/index.php?M=&moduleToken=dummyToken&key1=POST1&key2=GET2&key3[key31]=POST31&key3[key32]=GET32&key3[key33][key331]=GET331&key3[key33][key332]=POST332'); + $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('/typo3/index.php?route=&token=dummyToken&key1=POST1&key2=GET2&key3[key31]=POST31&key3[key32]=GET32&key3[key33][key331]=GET331&key3[key33][key332]=POST332'); $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } @@ -452,7 +457,7 @@ class UriBuilderTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase ]; $this->uriBuilder->setAddQueryString(true); $this->uriBuilder->setAddQueryStringMethod('GET,POST'); - $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('/typo3/index.php?M=&moduleToken=dummyToken&key1=GET1&key2=POST2&key3[key31]=GET31&key3[key32]=POST32&key3[key33][key331]=POST331&key3[key33][key332]=GET332'); + $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('/typo3/index.php?route=&token=dummyToken&key1=GET1&key2=POST2&key3[key31]=GET31&key3[key32]=POST32&key3[key33][key331]=POST331&key3[key33][key332]=GET332'); $actualResult = $this->uriBuilder->buildBackendUri(); $this->assertEquals($expectedResult, $actualResult); } diff --git a/typo3/sysext/filelist/Classes/FileList.php b/typo3/sysext/filelist/Classes/FileList.php index fe821d9879000af5e32ebbc04a79683fad822fb2..207bd6b3be774c8d70642b4d8c48aa55aec81333 100644 --- a/typo3/sysext/filelist/Classes/FileList.php +++ b/typo3/sysext/filelist/Classes/FileList.php @@ -16,7 +16,6 @@ namespace TYPO3\CMS\Filelist; use TYPO3\CMS\Backend\Clipboard\Clipboard; use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider; -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -1489,12 +1488,8 @@ class FileList protected function determineScriptUrl() { if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Buttons/ShortcutViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Buttons/ShortcutViewHelper.php index 9e838b9c21c3cf290d9f8e85928afb9943128246..12ba44799249a458adff43658f584a8967293ce7 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Buttons/ShortcutViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Buttons/ShortcutViewHelper.php @@ -34,7 +34,7 @@ use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; * </output> * * <code title="Explicitly set parameters to be stored in the shortcut"> - * <f:be.buttons.shortcut getVars="{0: 'M', 1: 'myOwnPrefix'}" setVars="{0: 'function'}" /> + * <f:be.buttons.shortcut getVars="{0: 'route', 1: 'myOwnPrefix'}" setVars="{0: 'function'}" /> * </code> * <output> * Shortcut button as known from the TYPO3 backend. @@ -99,7 +99,7 @@ class ShortcutViewHelper extends AbstractBackendViewHelper $moduleName = $currentRequest->getPluginName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $getList = implode(',', $getVars); $setList = implode(',', $setVars); diff --git a/typo3/sysext/form/Classes/Controller/FormManagerController.php b/typo3/sysext/form/Classes/Controller/FormManagerController.php index 353eb05a6b72ae0dc866d1e5d8fb61db8fbdb9f3..80b473f97689f6266540a7de5997a50bcec93ef6 100644 --- a/typo3/sysext/form/Classes/Controller/FormManagerController.php +++ b/typo3/sysext/form/Classes/Controller/FormManagerController.php @@ -427,7 +427,7 @@ class FormManagerController extends AbstractBackendController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() diff --git a/typo3/sysext/info/Classes/Controller/InfoModuleController.php b/typo3/sysext/info/Classes/Controller/InfoModuleController.php index 309fe694305d4d0668130c4d551fa089c46f0013..24426a349ed4a798510723983b6297d2dad89274 100644 --- a/typo3/sysext/info/Classes/Controller/InfoModuleController.php +++ b/typo3/sysext/info/Classes/Controller/InfoModuleController.php @@ -172,7 +172,7 @@ class InfoModuleController extends BaseScriptClass ->setModuleName($this->moduleName) ->setDisplayName($this->MOD_MENU['function'][$this->MOD_SETTINGS['function']]) ->setGetVariables([ - 'M', + 'route', 'id', 'edit_record', 'pointer', diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php index ba0746a6be33f4ec46baa580a257fce2098c3801..3f2af70a4755288a7bd95b88ec265bf3b18f7330 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php @@ -379,6 +379,11 @@ return [ 'Breaking-55298-DecoupledHistoryFunctionality.rst', ], ], + 'TYPO3\CMS\Backend\Http\BackendModuleRequestHandler' => [ + 'restFiles' => [ + 'Breaking-82406-RoutingBackendModulesRunThroughRegularDispatcher.rst', + ], + ], // Removed interfaces 'TYPO3\CMS\Backend\Form\DatabaseFileIconsHookInterface' => [ diff --git a/typo3/sysext/lowlevel/Classes/Utility/ArrayBrowser.php b/typo3/sysext/lowlevel/Classes/Utility/ArrayBrowser.php index 01700abf698c4084951500ac82574243b6e227ac..a7051053c318fbe80b1c461f943663cc0efea37f 100644 --- a/typo3/sysext/lowlevel/Classes/Utility/ArrayBrowser.php +++ b/typo3/sysext/lowlevel/Classes/Utility/ArrayBrowser.php @@ -109,7 +109,7 @@ class ArrayBrowser $output .= '<li' . ($isResult ? ' class="active"' : '') . '>'; if ($isArray && !$this->expAll) { $goto = 'a' . substr(md5($depth), 0, 6); - $output .= '<a class="list-tree-control' . ($isExpanded ? ' list-tree-control-open' : ' list-tree-control-closed') . '" id="' . $goto . '" href="' . htmlspecialchars((BackendUtility::getModuleUrl(GeneralUtility::_GP('M')) . '&node[' . $depth . ']=' . ($isExpanded ? 0 : 1) . '#' . $goto)) . '"><i class="fa"></i></a> '; + $output .= '<a class="list-tree-control' . ($isExpanded ? ' list-tree-control-open' : ' list-tree-control-closed') . '" id="' . $goto . '" href="' . htmlspecialchars((BackendUtility::getModuleUrl(GeneralUtility::_GP('route')) . '&node[' . $depth . ']=' . ($isExpanded ? 0 : 1) . '#' . $goto)) . '"><i class="fa"></i></a> '; } $output .= '<span class="list-tree-group">'; $output .= $this->wrapArrayKey($key, $depth, !$isArray ? $value : ''); @@ -149,7 +149,7 @@ class ArrayBrowser . (!MathUtility::canBeInterpretedAsInteger($theValue) ? '\'' . addslashes($theValue) . '\'' : $theValue) . '; '; $label = '<a class="list-tree-label" href="' - . htmlspecialchars((BackendUtility::getModuleUrl(GeneralUtility::_GP('M')) + . htmlspecialchars((BackendUtility::getModuleUrl(GeneralUtility::_GP('route')) . '&varname=' . urlencode($variableName))) . '#varname">' . $label . '</a>'; } diff --git a/typo3/sysext/recordlist/Classes/Browser/AbstractElementBrowser.php b/typo3/sysext/recordlist/Classes/Browser/AbstractElementBrowser.php index f1b277fd86a0fa8e555ad60ffd20824a9b2e2dc9..2e819dad6fd0e7a0f287a1c3f33b9161bd913ca1 100644 --- a/typo3/sysext/recordlist/Classes/Browser/AbstractElementBrowser.php +++ b/typo3/sysext/recordlist/Classes/Browser/AbstractElementBrowser.php @@ -14,10 +14,8 @@ namespace TYPO3\CMS\Recordlist\Browser; * The TYPO3 project - inspiring people to share! */ -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Template\DocumentTemplate; -use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Localization\LanguageService; @@ -106,12 +104,8 @@ abstract class AbstractElementBrowser protected function determineScriptUrl() { if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php b/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php index c1dbc264a8dd6a1d7b93c05d92c7cdbaa0897bb7..fe40625bb78fd8422538f54430c655ad20824f45 100644 --- a/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php +++ b/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php @@ -16,7 +16,6 @@ namespace TYPO3\CMS\Recordlist\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Template\DocumentTemplate; use TYPO3\CMS\Backend\Utility\BackendUtility; @@ -209,12 +208,8 @@ abstract class AbstractLinkBrowserController protected function determineScriptUrl(ServerRequestInterface $request) { if ($routePath = $request->getQueryParams()['route']) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = $request->getQueryParams()['M']) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php index 1b3b1dde87cfbce88e7ba875afa686ae27d16d69..672ff22b063ba291e9b78e1cf78b526119862024 100644 --- a/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList/AbstractDatabaseRecordList.php @@ -15,7 +15,6 @@ namespace TYPO3\CMS\Recordlist\RecordList; */ use TYPO3\CMS\Backend\RecordList\AbstractRecordList; -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Tree\View\PageTreeView; use TYPO3\CMS\Backend\Utility\BackendUtility; @@ -1189,12 +1188,8 @@ class AbstractDatabaseRecordList extends AbstractRecordList $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters); if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $url = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'), $urlParameters); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $url = BackendUtility::getModuleUrl($moduleName, $urlParameters); + $url = (string)$uriBuilder->buildUriFromRoutePath($routePath, $urlParameters); } else { $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . '?' . ltrim(GeneralUtility::implodeArrayForUrl('', $urlParameters), '&'); } diff --git a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php index 4da1c9e42d077249a79ae15676d04f12b9c7e6cd..bd6d78f10e3c82cba9bf15066011f41e540ba27b 100644 --- a/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php +++ b/typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php @@ -17,7 +17,6 @@ namespace TYPO3\CMS\Recordlist\RecordList; use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider; use TYPO3\CMS\Backend\Module\BaseScriptClass; use TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface; -use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Template\Components\ButtonBar; use TYPO3\CMS\Backend\Template\DocumentTemplate; @@ -869,7 +868,7 @@ class DatabaseRecordList ->setModuleName('web_list') ->setGetVariables([ 'id', - 'M', + 'route', 'imagemode', 'pointer', 'table', @@ -3580,12 +3579,8 @@ class DatabaseRecordList $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters); if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $url = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'), $urlParameters); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $url = BackendUtility::getModuleUrl($moduleName, $urlParameters); + $url = (string)$uriBuilder->buildUriFromRoutePath($routePath, $urlParameters); } else { $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . '?' . ltrim( GeneralUtility::implodeArrayForUrl('', $urlParameters), @@ -4152,12 +4147,8 @@ class DatabaseRecordList protected function determineScriptUrl() { if ($routePath = GeneralUtility::_GP('route')) { - $router = GeneralUtility::makeInstance(Router::class); - $route = $router->match($routePath); $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier')); - } elseif ($moduleName = GeneralUtility::_GP('M')) { - $this->thisScript = BackendUtility::getModuleUrl($moduleName); + $this->thisScript = (string)$uriBuilder->buildUriFromRoutePath($routePath); } else { $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME'); } diff --git a/typo3/sysext/recycler/Classes/Controller/RecyclerModuleController.php b/typo3/sysext/recycler/Classes/Controller/RecyclerModuleController.php index f6e98fc21527ef74672c2d958961595f6a99dec8..a60914e29ece2a855112d4dee6bbd2de63ffe24e 100644 --- a/typo3/sysext/recycler/Classes/Controller/RecyclerModuleController.php +++ b/typo3/sysext/recycler/Classes/Controller/RecyclerModuleController.php @@ -148,7 +148,7 @@ class RecyclerModuleController extends ActionController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($moduleName) diff --git a/typo3/sysext/reports/Classes/Controller/ReportController.php b/typo3/sysext/reports/Classes/Controller/ReportController.php index 36f1cf864cb4b359496ea728d40a1b8441342a47..6a2054231b5bfe257e4a40eb6d6abfc738bb0f5b 100644 --- a/typo3/sysext/reports/Classes/Controller/ReportController.php +++ b/typo3/sysext/reports/Classes/Controller/ReportController.php @@ -172,7 +172,7 @@ class ReportController extends ActionController $setVars = $this->request->hasArgument('setVars') ? $this->request->getArgument('setVars') : []; if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $this->request->getControllerExtensionName() . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($moduleName) diff --git a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php index 7b669e00204d669cb1027fa33429bd6e16ba3fb4..d3532ba7b1619b281fa431b94fcdf1ed1766d880 100644 --- a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php +++ b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php @@ -362,7 +362,7 @@ class TypoScriptTemplateModuleController extends BaseScriptClass // Shortcut $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($this->MCONF['name']) - ->setGetVariables(['id', 'M']); + ->setGetVariables(['id', 'route']); $buttonBar->addButton($shortcutButton); } diff --git a/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php b/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php index 8c2725e1bc6a954897e4fe3907b2df80716c913d..de87dd2f468c29d483633a7d4fe2dba6e7e9db28 100644 --- a/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php +++ b/typo3/sysext/viewpage/Classes/Controller/ViewModuleController.php @@ -103,7 +103,7 @@ class ViewModuleController extends ActionController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($moduleName) diff --git a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php index 079b4a81625e5a75149f9062f898ec88a6c8d3e3..7945dcc6d0bbb1c9bb7568e0fa6e2c5cd2fa9a23 100644 --- a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php +++ b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php @@ -87,7 +87,7 @@ class PreviewController extends AbstractController // Remove the GET parameters related to the workspaces module and the page id unset($queryParameters['tx_workspaces_web_workspacesworkspaces']); - unset($queryParameters['M']); + unset($queryParameters['route']); unset($queryParameters['id']); // Assemble a query string from the retrieved parameters diff --git a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php index 22279a17ad41ac67cd6897717bd90dffdc035783..6c21f5a0dd2aabe34dec17b0101cac42d7b285ce 100644 --- a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php +++ b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php @@ -50,7 +50,7 @@ class ReviewController extends AbstractController $extensionName = $currentRequest->getControllerExtensionName(); if (count($getVars) === 0) { $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName); - $getVars = ['id', 'M', $modulePrefix]; + $getVars = ['id', 'route', $modulePrefix]; } $shortcutButton = $buttonBar->makeShortcutButton() ->setModuleName($moduleName) diff --git a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php index f03a1c48d53945b61145e5916e8c985062985737..ba257964be14502a9cbdc469d480c35c3f40468c 100644 --- a/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php +++ b/typo3/sysext/workspaces/Classes/Service/WorkspaceService.php @@ -863,10 +863,10 @@ class WorkspaceService implements SingletonInterface $uriBuilder = $this->getObjectManager()->get(\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::class); $redirect = 'index.php?redirect_url='; // @todo this should maybe be changed so that the extbase URI Builder can deal with module names directly - $originalM = GeneralUtility::_GET('M'); - GeneralUtility::_GETset('web_WorkspacesWorkspaces', 'M'); + $originalM = GeneralUtility::_GET('route'); + GeneralUtility::_GETset('web_WorkspacesWorkspaces', 'route'); $viewScript = $uriBuilder->uriFor('index', [], 'Preview', 'workspaces', 'web_workspacesworkspaces') . '&id='; - GeneralUtility::_GETset($originalM, 'M'); + GeneralUtility::_GETset($originalM, 'route'); if ($addDomain === true) { return BackendUtility::getViewDomain($uid) . $redirect . urlencode($viewScript) . $uid; }