[TASK] Decouple adminPanel from frontend 58/56558/18
authorSusanne Moog <susanne.moog@typo3.org>
Thu, 5 Apr 2018 11:09:41 +0000 (13:09 +0200)
committerBenni Mack <benni@typo3.org>
Fri, 6 Apr 2018 18:36:33 +0000 (20:36 +0200)
The admin panel has been extracted into an own extension. To enable
users to de-activate the admin panel completely, the hard coupling
between the extension and other parts of the core had to be resolved.

With this change, the initialization of both adminPanel and feedit
were moved into PSR-15 middlewares. Additionally all parameters
related to the adminPanel were removed from the FrontendBackend-
UserAuthentication.

As feedit is tigthly coupled with the adminPanel some changes had
to be made to its initialization, too.

The flow of the adminPanel initialization and rendering were
streamlined to allow modules to make use of the request object.

Due to these changes in the control flow of the application the
two existing tests were removed and new tests will be rewritten
once the API is declared as stable.

Releases: master
Resolves: #84641
Change-Id: I72beefde0d792d3f4295c45aa27204c817d2de7a
Reviewed-on: https://review.typo3.org/56558
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
31 files changed:
typo3/sysext/adminpanel/Classes/Controller/MainController.php [new file with mode: 0644]
typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php [new file with mode: 0644]
typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php [new file with mode: 0644]
typo3/sysext/adminpanel/Classes/Modules/AbstractModule.php
typo3/sysext/adminpanel/Classes/Modules/AdminPanelModuleInterface.php
typo3/sysext/adminpanel/Classes/Modules/CacheModule.php
typo3/sysext/adminpanel/Classes/Modules/EditModule.php
typo3/sysext/adminpanel/Classes/Modules/PreviewModule.php
typo3/sysext/adminpanel/Classes/Modules/TsDebugModule.php
typo3/sysext/adminpanel/Classes/Repositories/FrontendGroupsRepository.php
typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php [new file with mode: 0644]
typo3/sysext/adminpanel/Classes/View/AdminPanelView.php
typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php [new file with mode: 0644]
typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php [deleted file]
typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php [deleted file]
typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php [deleted file]
typo3/sysext/adminpanel/composer.json
typo3/sysext/adminpanel/ext_localconf.php
typo3/sysext/backend/Classes/FrontendBackendUserAuthentication.php
typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst [new file with mode: 0644]
typo3/sysext/feedit/Classes/FrontendEditPanel.php
typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php [new file with mode: 0644]
typo3/sysext/feedit/Configuration/RequestMiddlewares.php [new file with mode: 0644]
typo3/sysext/feedit/composer.json
typo3/sysext/frontend/Classes/Http/RequestHandler.php
typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
typo3/sysext/frontend/composer.json
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
typo3/sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
typo3/sysext/workspaces/Classes/Authentication/PreviewUserAuthentication.php

diff --git a/typo3/sysext/adminpanel/Classes/Controller/MainController.php b/typo3/sysext/adminpanel/Classes/Controller/MainController.php
new file mode 100644 (file)
index 0000000..1ffdb97
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Controller;
+
+/*
+ * 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 TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
+use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Main controller for the admin panel
+ *
+ * @internal
+ */
+class MainController implements SingletonInterface
+{
+    /**
+     * @var array<AdminPanelModuleInterface>
+     */
+    protected $modules = [];
+
+    /**
+     * Initializes settings for the admin panel.
+     *
+     * @param \TYPO3\CMS\Core\Http\ServerRequest $request
+     */
+    public function initialize(ServerRequest $request): void
+    {
+        $this->validateSortAndInitializeModules();
+        $this->saveConfiguration();
+
+        foreach ($this->modules as $module) {
+            if ($module->isEnabled()) {
+                $module->initializeModule($request);
+            }
+        }
+    }
+
+    /**
+     * Renders the panel - Is currently called via RenderHook in postProcessOutput
+     *
+     * @todo Still uses the legacy AdminpanelView and should be rewritten to fluid
+     *
+     * @return string
+     */
+    public function render(): string
+    {
+        // handling via legacy functions
+        $adminPanelView = GeneralUtility::makeInstance(AdminPanelView::class);
+        $adminPanelView->setModules($this->modules);
+        return $adminPanelView->display();
+    }
+
+    /**
+     * Save admin panel configuration to backend user UC
+     */
+    protected function saveConfiguration(): void
+    {
+        $input = GeneralUtility::_GP('TSFE_ADMIN_PANEL');
+        $beUser = $this->getBackendUser();
+        if (is_array($input)) {
+            // Setting
+            $beUser->uc['TSFE_adminConfig'] = array_merge(
+                !is_array($beUser->uc['TSFE_adminConfig']) ? [] : $beUser->uc['TSFE_adminConfig'],
+                $input
+            );
+            unset($beUser->uc['TSFE_adminConfig']['action']);
+
+            foreach ($this->modules as $module) {
+                if ($module->isEnabled() && $module->isOpen()) {
+                    $module->onSubmit($input);
+                }
+            }
+            // Saving
+            $beUser->writeUC();
+            // Flush fluid template cache
+            $cacheManager = new CacheManager();
+            $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
+            $cacheManager->getCache('fluid_template')->flush();
+        }
+    }
+
+    /**
+     * Validates, sorts and initiates the registered modules
+     *
+     * @throws \RuntimeException
+     */
+    protected function validateSortAndInitializeModules(): void
+    {
+        $modules = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
+        if (empty($modules)) {
+            return;
+        }
+        foreach ($modules as $identifier => $configuration) {
+            if (empty($configuration) || !is_array($configuration)) {
+                throw new \RuntimeException(
+                    'Missing configuration for module "' . $identifier . '".',
+                    1519490105
+                );
+            }
+            if (!is_string($configuration['module']) ||
+                empty($configuration['module']) ||
+                !class_exists($configuration['module']) ||
+                !is_subclass_of(
+                    $configuration['module'],
+                    AdminPanelModuleInterface::class
+                )
+            ) {
+                throw new \RuntimeException(
+                    'The module "' .
+                    $identifier .
+                    '" defines an invalid module class. Ensure the class exists and implements the "' .
+                    AdminPanelModuleInterface::class .
+                    '".',
+                    1519490112
+                );
+            }
+        }
+
+        $orderedModules = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
+            $modules
+        );
+
+        foreach ($orderedModules as $module) {
+            $this->modules[] = GeneralUtility::makeInstance($module['module']);
+        }
+    }
+
+    /**
+     * Returns LanguageService
+     *
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * Returns the current BE user.
+     *
+     * @return FrontendBackendUserAuthentication
+     */
+    protected function getBackendUser(): FrontendBackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php b/typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php
new file mode 100644 (file)
index 0000000..c0a5506
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Hooks;
+
+/*
+ * 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 TYPO3\CMS\Adminpanel\Controller\MainController;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Hook used to postProcess output - renders the admin panel
+ */
+class RenderHook
+{
+
+    /**
+     * PostProcess output hook to render the admin panel
+     * We use a hook this late in the project to make sure all data is collected and can be displayed
+     *
+     * As the main content is already rendered, we use a string replace on the content to append the adminPanel
+     * to the HTML body.
+     *
+     * @param array $params
+     * @param TypoScriptFrontendController $pObj
+     */
+    public function renderAdminPanel(array $params, TypoScriptFrontendController $pObj)
+    {
+        if ($pObj->isBackendUserLoggedIn() &&
+            $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication &&
+            (
+                !$GLOBALS['BE_USER']->extAdminConfig['hide'] && $pObj->config['config']['admPanel']
+            )
+        ) {
+            $mainController = GeneralUtility::makeInstance(MainController::class);
+            $pObj->content = str_ireplace(
+                '</body>',
+                $mainController->render() . '</body>',
+                $pObj->content
+            );
+        }
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php
new file mode 100644 (file)
index 0000000..b0dba87
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Middleware;
+
+/*
+ * 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\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Adminpanel\Controller\MainController;
+use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * PSR-15 Middleware to initialize the admin panel
+ */
+class AdminPanelInitiator implements MiddlewareInterface
+{
+
+    /**
+     * Initialize the adminPanel if
+     * - backend user is logged in
+     * - at least one adminpanel functionality is enabled
+     *
+     * @param ServerRequestInterface $request
+     * @param RequestHandlerInterface $handler
+     * @return ResponseInterface
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if ($GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
+
+            // Initialize admin panel since simulation settings are required here
+            $beUser = $GLOBALS['BE_USER'];
+            // set legacy config
+            $beUser->extAdminConfig = $beUser->getTSConfigProp('admPanel');
+            $adminPanelConfiguration = $beUser->extAdminConfig;
+            if (isset($adminPanelConfiguration['enable.'])) {
+                foreach ($adminPanelConfiguration['enable.'] as $value) {
+                    if ($value) {
+                        $adminPanelController = GeneralUtility::makeInstance(
+                            MainController::class
+                        );
+                        $adminPanelController->initialize($request);
+                        // legacy handling
+                        $beUser->adminPanel = GeneralUtility::makeInstance(AdminPanelView::class);
+                        $beUser->extAdmEnabled = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return $handler->handle($request);
+    }
+}
index 07f3c61..756ed7c 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 
 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Localization\LanguageService;
 
 /**
@@ -32,6 +33,16 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     protected $extResources = 'EXT:adminpanel/Resources/Private';
 
     /**
+     * @var array
+     */
+    protected $mainConfiguration;
+
+    public function __construct()
+    {
+        $this->mainConfiguration = $this->getBackendUser()->getTSConfigProp('admPanel');
+    }
+
+    /**
      * @inheritdoc
      */
     public function getAdditionalJavaScriptCode(): string
@@ -42,7 +53,7 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
     }
 
@@ -59,8 +70,8 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $identifier = $this->getIdentifier();
         $result = $this->isEnabledViaTsConfig();
-        if ($this->getBackendUser()->extAdminConfig['override.'][$identifier] ?? false) {
-            $result = (bool)$this->getBackendUser()->extAdminConfig['override.'][$identifier];
+        if ($this->mainConfiguration['override.'][$identifier] ?? false) {
+            $result = (bool)$this->mainConfiguration['override.'][$identifier];
         }
         return $result;
     }
@@ -116,7 +127,7 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $labelStr = $this->getLanguageService()->getLL($key);
         if ($convertWithHtmlspecialchars) {
-            $labelStr = htmlspecialchars($labelStr);
+            $labelStr = htmlspecialchars($labelStr, ENT_QUOTES | ENT_HTML5);
         }
         return $labelStr;
     }
@@ -143,8 +154,8 @@ abstract class AbstractModule implements AdminPanelModuleInterface
         $beUser = $this->getBackendUser();
         $identifier = $this->getIdentifier();
 
-        if ($option && isset($beUser->extAdminConfig['override.'][$identifier . '.'][$option])) {
-            $returnValue = $beUser->extAdminConfig['override.'][$identifier . '.'][$option];
+        if ($option && isset($this->mainConfiguration['override.'][$identifier . '.'][$option])) {
+            $returnValue = $this->mainConfiguration['override.'][$identifier . '.'][$option];
         } else {
             $returnValue = $beUser->uc['TSFE_adminConfig'][$identifier . '_' . $option] ?? '';
         }
@@ -171,9 +182,9 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $result = false;
         $identifier = $this->getIdentifier();
-        if (!empty($this->getBackendUser()->extAdminConfig['enable.']['all'])) {
+        if (!empty($this->mainConfiguration['enable.']['all'])) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.'][$identifier])) {
+        } elseif (!empty($this->mainConfiguration['enable.'][$identifier])) {
             $result = true;
         }
         return $result;
index 12a4ab9..f56445f 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -16,6 +16,8 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
+
 /**
  * Interface for admin panel modules registered via EXTCONF
  *
@@ -23,6 +25,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 interface AdminPanelModuleInterface
 {
+
     /**
      * Additional JavaScript code for this module
      * (you should only use vanilla JS here, as you cannot
@@ -56,8 +59,10 @@ interface AdminPanelModuleInterface
 
     /**
      * Initialize the module - runs early in a TYPO3 request
+     *
+     * @param \TYPO3\CMS\Core\Http\ServerRequest $request
      */
-    public function initializeModule(): void;
+    public function initializeModule(ServerRequest $request): void;
 
     /**
      * Module is enabled
index 5a5fc63..78c8606 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -65,7 +66,7 @@ class CacheModule extends AbstractModule
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         if ($this->getConfigurationOption('noCache')) {
             $this->getTypoScriptFrontendController()->set_no_cache('Admin Panel: No Caching', true);
index cb52bb4..a6cbbdf 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -16,7 +16,9 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -39,6 +41,7 @@ class EditModule extends AbstractModule
         $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
         $view->setPartialRootPaths([$this->extResources . '/Partials']);
 
+        $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
         $view->assignMultiple([
             'feEdit' => ExtensionManagementUtility::isLoaded('feedit'),
             'display' => [
@@ -46,7 +49,7 @@ class EditModule extends AbstractModule
                 'fieldIcons' => $this->getConfigurationOption('displayFieldIcons'),
                 'displayIcons' => $this->getConfigurationOption('displayIcons'),
             ],
-            'toolbar' => $this->getBackendUser()->adminPanel->ext_makeToolBar(),
+            'toolbar' => $editToolbarService->createToolbar(),
             'script' => [
                 'pageUid' => (int)$this->getTypoScriptFrontendController()->page['uid'],
                 'pageModule' => $this->getPageModule(),
@@ -98,9 +101,11 @@ class EditModule extends AbstractModule
      * Initialize the edit module
      * Includes the frontend edit initialization
      *
+     * @param ServerRequest $request
+     *
      * @todo move into fe_edit (including the module)
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         $extFeEditLoaded = ExtensionManagementUtility::isLoaded('feedit');
         $typoScriptFrontend = $this->getTypoScriptFrontendController();
index b22850a..262b5c8 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 
 use TYPO3\CMS\Adminpanel\Repositories\FrontendGroupsRepository;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -93,7 +94,10 @@ class PreviewModule extends AbstractModule
         return $this->getLanguageService()->sL($locallangFileAndPath);
     }
 
-    public function initializeModule(): void
+    /**
+     * @param ServerRequest $request
+     */
+    public function initializeModule(ServerRequest $request): void
     {
         $this->initializeFrontendPreview();
         if (GeneralUtility::_GP('ADMCMD_simUser')) {
index 6b33237..c888021 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Adminpanel\Modules;
 
 /*
@@ -15,6 +16,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -74,7 +76,7 @@ class TsDebugModule extends AbstractModule
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         $typoScriptFrontend = $this->getTypoScriptFrontendController();
         $typoScriptFrontend->forceTemplateParsing = (bool)$this->getConfigurationOption('forceTemplateParsing');
@@ -111,7 +113,6 @@ class TsDebugModule extends AbstractModule
     /**
      * Renders the TypoScript log as string
      *
-     * @param $output
      * @return string
      */
     private function renderTypoScriptLog(): string
index 35881d2..6f18401 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Repositories;
 
@@ -110,7 +110,7 @@ class FrontendGroupsRepository
     /**
      * Returns the current BE user.
      *
-     * @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
+     * @return FrontendBackendUserAuthentication
      */
     protected function getBackendUser(): FrontendBackendUserAuthentication
     {
diff --git a/typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php b/typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php
new file mode 100644 (file)
index 0000000..7ccb119
--- /dev/null
@@ -0,0 +1,273 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Service;
+
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+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\FrontendRestrictionContainer;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Class for the Edit Toolbar
+ *
+ * @internal
+ */
+class EditToolbarService
+{
+
+    /**
+     * Creates the tool bar links for the "edit" section of the Admin Panel.
+     *
+     * @return string A string containing images wrapped in <a>-tags linking them to proper functions.
+     */
+    public function createToolbar(): string
+    {
+        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+        $tsfe = $this->getTypoScriptFrontendController();
+        //  If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
+        $tsConfig = BackendUtility::getModTSconfig($tsfe->page['uid'], 'mod');
+        $moduleName = $tsConfig['properties']['newContentElementWizard.']['override'] ?? 'new_content_element';
+        /** @var UriBuilder $uriBuilder */
+        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+        $perms = $this->getBackendUser()->calcPerms($tsfe->page);
+        $langAllowed = $this->getBackendUser()->checkLanguageAccess($tsfe->sys_language_uid);
+        $id = $tsfe->id;
+        $returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
+        $classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
+        $output = [];
+        $output[] = '<div class="typo3-adminPanel-form-group">';
+        $output[] = '  <div class="typo3-adminPanel-btn-group" role="group">';
+
+        // History
+        /** @var UriBuilder $uriBuilder */
+        $link = (string)$uriBuilder->buildUriFromRoute(
+            'record_history',
+            [
+                'element' => 'pages:' . $id,
+                'returnUrl' => $returnUrl,
+            ]
+        );
+        $title = $this->extGetLL('edit_recordHistory');
+        $output[] = '<a class="' .
+                    $classes .
+                    '" href="' .
+                    htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                    '#latest" title="' .
+                    $title .
+                    '">';
+        $output[] = '  ' . $iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render();
+        $output[] = '</a>';
+
+        // New Content
+        if ($perms & Permission::CONTENT_EDIT && $langAllowed) {
+            $linkParameters = [
+                'id' => $id,
+                'returnUrl' => $returnUrl,
+            ];
+            if (!empty($tsfe->sys_language_uid)) {
+                $linkParameters['sys_language_uid'] = $tsfe->sys_language_uid;
+            }
+            $link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
+            $icon = $iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_newContentElement');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Move Page
+        if ($perms & Permission::PAGE_EDIT) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'move_element',
+                [
+                    'table' => 'pages',
+                    'uid' => $id,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_move_page');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // New Page
+        if ($perms & Permission::PAGE_NEW) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'db_new',
+                [
+                    'id' => $id,
+                    'pagesOnly' => 1,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_newPage');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Edit Page
+        if ($perms & Permission::PAGE_EDIT) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'record_edit',
+                [
+                    'edit[pages][' . $id . ']' => 'edit',
+                    'noView' => 1,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_editPageProperties');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Edit Page Overlay
+        if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) {
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getQueryBuilderForTable('pages');
+            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
+            $row = $queryBuilder
+                ->select('uid', 'pid', 't3ver_state')
+                ->from('pages')
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
+                        $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
+                    ),
+                    $queryBuilder->expr()->eq(
+                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
+                        $queryBuilder->createNamedParameter($tsfe->sys_language_uid, \PDO::PARAM_INT)
+                    )
+                )
+                ->setMaxResults(1)
+                ->execute()
+                ->fetch();
+            $tsfe->sys_page->versionOL('pages', $row);
+            if (is_array($row)) {
+                $link = (string)$uriBuilder->buildUriFromRoute(
+                    'record_edit',
+                    [
+                        'edit[pages][' . $row['uid'] . ']' => 'edit',
+                        'noView' => 1,
+                        'returnUrl' => $returnUrl,
+                    ]
+                );
+                $icon = $iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)
+                    ->render();
+                $title = $this->extGetLL('edit_editPageOverlay');
+                $output[] = '<a class="' .
+                            $classes .
+                            '" href="' .
+                            htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                            '" title="' .
+                            $title .
+                            '">';
+                $output[] = '  ' . $icon;
+                $output[] = '</a>';
+            }
+        }
+
+        // Open list view
+        if ($this->getBackendUser()->check('modules', 'web_list')) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'web_list',
+                [
+                    'id' => $id,
+                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_db_list');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        $output[] = '  </div>';
+        $output[] = '</div>';
+        return implode('', $output);
+    }
+
+    /**
+     * Translate given key
+     *
+     * @param string $key Key for a label in the $LOCAL_LANG array of "sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
+     * @param bool $convertWithHtmlspecialchars If TRUE the language-label will be sent through htmlspecialchars
+     * @return string The value for the $key
+     */
+    protected function extGetLL($key, $convertWithHtmlspecialchars = true): ?string
+    {
+        $labelStr = $this->getLanguageService()->getLL($key);
+        if ($convertWithHtmlspecialchars) {
+            $labelStr = htmlspecialchars($labelStr, ENT_QUOTES | ENT_HTML5);
+        }
+        return $labelStr;
+    }
+
+    /**
+     * @return FrontendBackendUserAuthentication
+     */
+    protected function getBackendUser(): FrontendBackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
index 1cc0a16..cddd787 100644 (file)
@@ -16,19 +16,16 @@ namespace TYPO3\CMS\Adminpanel\View;
  */
 
 use TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Cache\CacheManager;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
-use TYPO3\CMS\Core\Service\DependencyOrderingService;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 
 /**
  * View class for the admin panel in frontend editing.
+ *
+ * @internal
  */
 class AdminPanelView
 {
@@ -64,27 +61,27 @@ class AdminPanelView
     protected $modules = [];
 
     /**
+     * @var array
+     */
+    protected $configuration;
+
+    /**
      * Constructor
      */
     public function __construct()
     {
-        $this->initialize();
+        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
     }
 
     /**
-     * Initializes settings for the admin panel.
+     * Setter for injecting new-style modules
+     *
+     * @see \TYPO3\CMS\Adminpanel\Controller\MainController::render()
+     * @param array $modules
      */
-    public function initialize()
+    public function setModules(array $modules): void
     {
-        $this->validateSortAndInitializeModules();
-        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-        $this->saveConfiguration();
-
-        foreach ($this->modules as $module) {
-            if ($module->isEnabled()) {
-                $module->initializeModule();
-            }
-        }
+        $this->modules = $modules;
     }
 
     /**
@@ -106,7 +103,7 @@ class AdminPanelView
     /**
      * Render a single module with header panel
      *
-     * @param \TYPO3\CMS\Frontend\AdminPanel\AdminPanelModuleInterface $module
+     * @param \TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface $module
      * @return string
      */
     protected function getModule(AdminPanelModuleInterface $module): string
@@ -316,80 +313,6 @@ class AdminPanelView
         return $this->getBackendUser()->uc['TSFE_adminConfig']['display_top'] ?? false;
     }
 
-    /**
-     * Save admin panel configuration to backend user UC
-     */
-    protected function saveConfiguration()
-    {
-        $input = GeneralUtility::_GP('TSFE_ADMIN_PANEL');
-        $beUser = $this->getBackendUser();
-        if (is_array($input)) {
-            // Setting
-            $beUser->uc['TSFE_adminConfig'] = array_merge(
-                !is_array($beUser->uc['TSFE_adminConfig']) ? [] : $beUser->uc['TSFE_adminConfig'],
-                $input
-            );
-            unset($beUser->uc['TSFE_adminConfig']['action']);
-
-            foreach ($this->modules as $module) {
-                if ($module->isEnabled() && $module->isOpen()) {
-                    $module->onSubmit($input);
-                }
-            }
-            // Saving
-            $beUser->writeUC();
-            // Flush fluid template cache
-            $cacheManager = new CacheManager();
-            $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
-            $cacheManager->getCache('fluid_template')->flush();
-        }
-    }
-
-    /**
-     * Validates, sorts and initiates the registered modules
-     *
-     * @throws \RuntimeException
-     */
-    protected function validateSortAndInitializeModules(): void
-    {
-        $modules = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
-        if (empty($modules)) {
-            return;
-        }
-        foreach ($modules as $identifier => $configuration) {
-            if (empty($configuration) || !is_array($configuration)) {
-                throw new \RuntimeException(
-                    'Missing configuration for module "' . $identifier . '".',
-                    1519490105
-                );
-            }
-            if (!is_string($configuration['module']) ||
-                empty($configuration['module']) ||
-                !class_exists($configuration['module']) ||
-                !is_subclass_of(
-                    $configuration['module'],
-                    AdminPanelModuleInterface::class
-                )) {
-                throw new \RuntimeException(
-                    'The module "' .
-                    $identifier .
-                    '" defines an invalid module class. Ensure the class exists and implements the "' .
-                    AdminPanelModuleInterface::class .
-                    '".',
-                    1519490112
-                );
-            }
-        }
-
-        $orderedModules = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
-            $modules
-        );
-
-        foreach ($orderedModules as $module) {
-            $this->modules[] = GeneralUtility::makeInstance($module['module']);
-        }
-    }
-
     /*****************************************************
      * Admin Panel Layout Helper functions
      ****************************************************/
@@ -397,7 +320,7 @@ class AdminPanelView
     /**
      * Wraps a string in a link which will open/close a certain part of the Admin Panel
      *
-     * @param \TYPO3\CMS\Frontend\AdminPanel\AdminPanelModuleInterface $module
+     * @param AdminPanelModuleInterface $module
      * @return string
      */
     protected function getSectionOpenerLink(AdminPanelModuleInterface $module): string
@@ -426,164 +349,14 @@ class AdminPanelView
     /**
      * Creates the tool bar links for the "edit" section of the Admin Panel.
      *
+     * @deprecated
      * @return string A string containing images wrapped in <a>-tags linking them to proper functions.
      */
     public function ext_makeToolBar()
     {
-        $tsfe = $this->getTypoScriptFrontendController();
-        //  If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
-        $tsConfig = BackendUtility::getModTSconfig($tsfe->page['uid'], 'mod');
-        $moduleName = $tsConfig['properties']['newContentElementWizard.']['override'] ?? 'new_content_element';
-        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
-        $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
-        $perms = $this->getBackendUser()->calcPerms($tsfe->page);
-        $langAllowed = $this->getBackendUser()->checkLanguageAccess($tsfe->sys_language_uid);
-        $id = $tsfe->id;
-        $returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
-        $classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
-        $output = [];
-        $output[] = '<div class="typo3-adminPanel-form-group">';
-        $output[] = '  <div class="typo3-adminPanel-btn-group" role="group">';
-
-        // History
-        $link = (string)$uriBuilder->buildUriFromRoute(
-            'record_history',
-            [
-                'element' => 'pages:' . $id,
-                'returnUrl' => $returnUrl
-            ]
-        );
-        $title = $this->extGetLL('edit_recordHistory');
-        $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '#latest" title="' . $title . '">';
-        $output[] = '  ' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render();
-        $output[] = '</a>';
-
-        // New Content
-        if ($perms & Permission::CONTENT_EDIT && $langAllowed) {
-            $linkParameters = [
-                'id' => $id,
-                'returnUrl' => $returnUrl,
-            ];
-            if (!empty($tsfe->sys_language_uid)) {
-                $linkParameters['sys_language_uid'] = $tsfe->sys_language_uid;
-            }
-            $link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
-            $icon = $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_newContentElement');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Move Page
-        if ($perms & Permission::PAGE_EDIT) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'move_element',
-                [
-                    'table' => 'pages',
-                    'uid' => $id,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_move_page');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // New Page
-        if ($perms & Permission::PAGE_NEW) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'db_new',
-                [
-                    'id' => $id,
-                    'pagesOnly' => 1,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_newPage');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Edit Page
-        if ($perms & Permission::PAGE_EDIT) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'record_edit',
-                [
-                    'edit[pages][' . $id . ']' => 'edit',
-                    'noView' => 1,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_editPageProperties');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Edit Page Overlay
-        if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) {
-            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-                ->getQueryBuilderForTable('pages');
-            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
-            $row = $queryBuilder
-                ->select('uid', 'pid', 't3ver_state')
-                ->from('pages')
-                ->where(
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
-                        $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
-                    ),
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
-                        $queryBuilder->createNamedParameter($tsfe->sys_language_uid, \PDO::PARAM_INT)
-                    )
-                )
-                ->setMaxResults(1)
-                ->execute()
-                ->fetch();
-            $tsfe->sys_page->versionOL('pages', $row);
-            if (is_array($row)) {
-                $link = (string)$uriBuilder->buildUriFromRoute(
-                    'record_edit',
-                    [
-                        'edit[pages][' . $row['uid'] . ']' => 'edit',
-                        'noView' => 1,
-                        'returnUrl' => $returnUrl
-                    ]
-                );
-                $icon = $this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)->render();
-                $title = $this->extGetLL('edit_editPageOverlay');
-                $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-                $output[] = '  ' . $icon;
-                $output[] = '</a>';
-            }
-        }
-
-        // Open list view
-        if ($this->getBackendUser()->check('modules', 'web_list')) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'web_list',
-                [
-                    'id' => $id,
-                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_db_list');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        $output[] = '  </div>';
-        $output[] = '</div>';
-        return implode('', $output);
+        trigger_error('', E_USER_DEPRECATED);
+        $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
+        return $editToolbarService->createToolbar();
     }
 
     /**
@@ -662,9 +435,9 @@ class AdminPanelView
         // Returns TRUE if the module checked is "preview" and the forcePreview flag is set.
         if ($key === 'preview' && $this->ext_forcePreview) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.']['all'])) {
+        } elseif (!empty($this->configuration['enable.']['all'])) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.'][$key])) {
+        } elseif (!empty($this->configuration['enable.'][$key])) {
             $result = true;
         }
         return $result;
@@ -707,20 +480,20 @@ class AdminPanelView
         // deprecated
         if (
             $sectionName === 'edit' && (
-                $val === 'displayIcons' && $beUser->extAdminConfig['module.']['edit.']['forceDisplayIcons'] ||
-                $val === 'displayFieldIcons' && $beUser->extAdminConfig['module.']['edit.']['forceDisplayFieldIcons'] ||
-                $val === 'editNoPopup' && $beUser->extAdminConfig['module.']['edit.']['forceNoPopup']
+                $val === 'displayIcons' && $this->configuration['module.']['edit.']['forceDisplayIcons'] ||
+                $val === 'displayFieldIcons' && $this->configuration['module.']['edit.']['forceDisplayFieldIcons'] ||
+                $val === 'editNoPopup' && $this->configuration['module.']['edit.']['forceNoPopup']
             )
         ) {
             return true;
         }
 
         // Override all settings with user TSconfig
-        if ($val && isset($beUser->extAdminConfig['override.'][$sectionName . '.'][$val])) {
-            return $beUser->extAdminConfig['override.'][$sectionName . '.'][$val];
+        if ($val && isset($this->configuration['override.'][$sectionName . '.'][$val])) {
+            return $this->configuration['override.'][$sectionName . '.'][$val];
         }
-        if (!$val && isset($beUser->extAdminConfig['override.'][$sectionName])) {
-            return $beUser->extAdminConfig['override.'][$sectionName];
+        if (!$val && isset($this->configuration['override.'][$sectionName])) {
+            return $this->configuration['override.'][$sectionName];
         }
 
         $returnValue = $val ? $beUser->uc['TSFE_adminConfig'][$sectionName . '_' . $val] : 1;
diff --git a/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php b/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
new file mode 100644 (file)
index 0000000..ffa8eb1
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * An array consisting of implementations of middlewares for a middleware stack to be registered
+ *  'stackname' => [
+ *      'middleware-identifier' => [
+ *         'target' => classname or callable
+ *         'before/after' => array of dependencies
+ *      ]
+ *   ]
+ */
+return [
+    'frontend' => [
+        'typo3/cms-adminpanel/initiator' => [
+            'target' => \TYPO3\CMS\Adminpanel\Middleware\AdminPanelInitiator::class,
+            'after' => [
+                'typo3/cms-frontend/tsfe',
+                'typo3/cms-frontend/authentication',
+                'typo3/cms-frontend/backend-user-authentication',
+            ]
+        ],
+    ]
+];
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php b/typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php
deleted file mode 100644 (file)
index bfd416b..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View;
-
-/*
- * 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 TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures\AdminPanelDisabledModuleFixture;
-use TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures\AdminPanelEnabledShownOnSubmitInitializeModuleFixture;
-use TYPO3\CMS\Adminpanel\View\AdminPanelView;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Imaging\IconFactory;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
-
-/**
- * Test case
- */
-class AdminPanelViewTest extends UnitTestCase
-{
-    public function setUp()
-    {
-        parent::setUp();
-        $iconFactoryProphecy = $this->prophesize(IconFactory::class);
-        GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
-        $beUserProphecy = $this->prophesize(BackendUserAuthentication::class);
-        $GLOBALS['BE_USER'] = $beUserProphecy->reveal();
-    }
-
-    /**
-     * @test
-     */
-    public function initializeCallsOnSubmitIfInputVarsAreSet()
-    {
-        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
-            'fixtureOnSubmit' => [
-                'module' => AdminPanelEnabledShownOnSubmitInitializeModuleFixture::class,
-            ],
-        ];
-
-        $postVars = ['preview_showFluidDebug' => '1'];
-        $_GET['TSFE_ADMIN_PANEL'] = $postVars;
-
-        $this->expectExceptionCode('1519997815');
-
-        new AdminPanelView();
-    }
-
-    /**
-     * @test
-     */
-    public function initializeCallsInitializeModulesForEnabledModules()
-    {
-        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
-            'enabledModule' => [
-                'module' => AdminPanelEnabledShownOnSubmitInitializeModuleFixture::class,
-            ],
-            'disabledModule' => [
-                'module' => AdminPanelDisabledModuleFixture::class,
-                'before' => ['enabledModule'],
-            ],
-        ];
-
-        $this->expectExceptionCode(1519999273);
-        new AdminPanelView();
-    }
-}
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php b/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php
deleted file mode 100644 (file)
index d9cc674..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-declare(strict_types=1);
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures;
-
-/*
- * 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 TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-
-class AdminPanelDisabledModuleFixture implements AdminPanelModuleInterface
-{
-
-    /**
-     * Additional JavaScript code for this module
-     * (you should only use vanilla JS here, as you cannot
-     * rely on the web site providing a specific framework)
-     *
-     * @return string
-     */
-    public function getAdditionalJavaScriptCode(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module content as rendered HTML
-     *
-     * @return string
-     */
-    public function getContent(): string
-    {
-        return '';
-    }
-
-    /**
-     * Identifier for this module,
-     * for example "preview" or "cache"
-     *
-     * @return string
-     */
-    public function getIdentifier(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module label
-     *
-     * @return string
-     */
-    public function getLabel(): string
-    {
-        return '';
-    }
-
-    /**
-     * Initialize the module - runs early in a TYPO3 request
-     */
-    public function initializeModule(): void
-    {
-        throw new \RuntimeException('I should not be initialized.', 1519999375);
-    }
-
-    /**
-     * Module is enabled
-     * -> should be initialized
-     * A module may be enabled but not shown
-     * -> only the initializeModule() method
-     * will be called
-     *
-     * @return bool
-     */
-    public function isEnabled(): bool
-    {
-        return false;
-    }
-
-    /**
-     * Module is open
-     * -> module is enabled
-     * -> module panel is shown and open
-     *
-     * @return bool
-     */
-    public function isOpen(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is shown
-     * -> module is enabled
-     * -> module panel should be displayed
-     *
-     * @return bool
-     */
-    public function isShown(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Executed on saving / submit of the configuration form
-     * Can be used to react to changed settings
-     * (for example: clearing a specific cache)
-     *
-     * @param array $input
-     */
-    public function onSubmit(array $input): void
-    {
-    }
-
-    /**
-     * Does this module need a form submit?
-     *
-     * @return bool
-     */
-    public function showFormSubmitButton(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Returns a string array with javascript files that will be rendered after the module
-     *
-     * @return array
-     */
-    public function getJavaScriptFiles(): array
-    {
-        return [];
-    }
-}
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php b/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php
deleted file mode 100644 (file)
index 0835228..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-declare(strict_types=1);
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures;
-
-/*
- * 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 TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-
-class AdminPanelEnabledShownOnSubmitInitializeModuleFixture implements AdminPanelModuleInterface
-{
-
-    /**
-     * Additional JavaScript code for this module
-     * (you should only use vanilla JS here, as you cannot
-     * rely on the web site providing a specific framework)
-     *
-     * @return string
-     */
-    public function getAdditionalJavaScriptCode(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module content as rendered HTML
-     *
-     * @return string
-     */
-    public function getContent(): string
-    {
-        return '';
-    }
-
-    /**
-     * Identifier for this module,
-     * for example "preview" or "cache"
-     *
-     * @return string
-     */
-    public function getIdentifier(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module label
-     *
-     * @return string
-     */
-    public function getLabel(): string
-    {
-        return '';
-    }
-
-    /**
-     * Initialize the module - runs early in a TYPO3 request
-     */
-    public function initializeModule(): void
-    {
-        throw new \RuntimeException('initialized.', 1519999273);
-    }
-
-    /**
-     * Module is enabled
-     * -> should be initialized
-     * A module may be enabled but not shown
-     * -> only the initializeModule() method
-     * will be called
-     *
-     * @return bool
-     */
-    public function isEnabled(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is open
-     * -> module is enabled
-     * -> module panel is shown and open
-     *
-     * @return bool
-     */
-    public function isOpen(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is shown
-     * -> module is enabled
-     * -> module panel should be displayed
-     *
-     * @return bool
-     */
-    public function isShown(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Executed on saving / submit of the configuration form
-     * Can be used to react to changed settings
-     * (for example: clearing a specific cache)
-     *
-     * @param array $input
-     */
-    public function onSubmit(array $input): void
-    {
-        throw new \RuntimeException('Catch me if you can!', 1519997815);
-    }
-
-    /**
-     * Does this module need a form submit?
-     *
-     * @return bool
-     */
-    public function showFormSubmitButton(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Returns a string array with javascript files that will be rendered after the module
-     *
-     * @return array
-     */
-    public function getJavaScriptFiles(): array
-    {
-        return [];
-    }
-}
index 15c401c..5fe9880 100644 (file)
                "sort-packages": true
        },
        "require": {
+               "typo3/cms-backend": "9.2.*@dev",
                "typo3/cms-core": "9.2.*@dev",
-               "typo3/cms-frontend": "9.2.*@dev"
+               "typo3/cms-fluid": "9.2.*@dev",
+               "typo3/cms-frontend": "9.2.*@dev",
+               "psr/http-message": "~1.0",
+               "psr/http-server-handler": "^1.0",
+               "psr/http-server-middleware": "^1.0"
        },
        "conflict": {
                "typo3/cms": "*"
index 0094d2f..ba181f0 100644 (file)
@@ -1,4 +1,7 @@
 <?php
+defined('TYPO3_MODE') or die();
+
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'][] = \TYPO3\CMS\Adminpanel\Hooks\RenderHook::class . '->renderAdminPanel';
 
 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
     'preview' => [
index cd08742..6c24767 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Backend;
  */
 
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Database\Query\QueryHelper;
@@ -29,6 +30,19 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class FrontendBackendUserAuthentication extends BackendUserAuthentication
 {
+    use PublicPropertyDeprecationTrait;
+
+    /**
+     * Properties which have been moved to protected status from public
+     *
+     * @var array
+     */
+    protected $deprecatedPublicProperties = [
+        'extAdmEnabled' => 'Using $extAdmEnabled of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+        'adminPanel' => 'Using $adminPanel of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+        'extAdminConfig' => 'Using $extAdminConfig of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+    ];
+
     /**
      * Form field with login name.
      *
@@ -69,11 +83,13 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
      * General flag which is set if the adminpanel is enabled at all.
      *
      * @var bool
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $extAdmEnabled = false;
 
     /**
      * @var \TYPO3\CMS\Adminpanel\View\AdminPanelView Instance of admin panel
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $adminPanel = null;
 
@@ -84,58 +100,39 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
 
     /**
      * @var array
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $extAdminConfig = [];
 
     /**
      * Initializes the admin panel.
+     *
+     * @deprecated since TYPO3v9 - rewritten as middleware
      */
     public function initializeAdminPanel()
     {
-        $this->extAdminConfig = $this->getTSConfigProp('admPanel');
-        if (isset($this->extAdminConfig['enable.'])) {
-            foreach ($this->extAdminConfig['enable.'] as $value) {
-                if ($value) {
-                    $this->adminPanel = GeneralUtility::makeInstance(\TYPO3\CMS\Adminpanel\View\AdminPanelView::class);
-                    $this->extAdmEnabled = true;
-                    break;
-                }
-            }
-        }
+        trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
     }
 
     /**
      * Initializes frontend editing.
+     *
+     * @deprecated since TYPO3v9 - rewritten as middleware
      */
     public function initializeFrontendEdit()
     {
-        if (isset($this->extAdminConfig['enable.']) && $this->isFrontendEditingActive()) {
-            foreach ($this->extAdminConfig['enable.'] as $value) {
-                if ($value) {
-                    if ($GLOBALS['TSFE'] instanceof \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController) {
-                        // Grab the Page TSConfig property that determines which controller to use.
-                        $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig();
-                        $controllerKey = $pageTSConfig['TSFE.']['frontendEditingController'] ?? 'default';
-                    } else {
-                        $controllerKey = 'default';
-                    }
-                    $controllerClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController'][$controllerKey];
-                    if ($controllerClass) {
-                        $this->frontendEdit = GeneralUtility::makeInstance($controllerClass);
-                    }
-                    break;
-                }
-            }
-        }
+        trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
     }
 
     /**
      * Determines whether frontend editing is currently active.
      *
+     * @deprecated since TYPO3 v9 - see ext "feedit" for API
      * @return bool Whether frontend editing is active
      */
     public function isFrontendEditingActive()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use underlying TSFE directly.', E_USER_DEPRECATED);
         return $this->extAdmEnabled && (
             $this->adminPanel->isAdminModuleEnabled('edit') ||
             (int)$GLOBALS['TSFE']->displayEditIcons === 1 ||
@@ -146,20 +143,24 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
     /**
      * Delegates to the appropriate view and renders the admin panel content.
      *
+     * @deprecated since TYPO3v9 - see ext "adminpanel" for new API
      * @return string.
      */
     public function displayAdminPanel()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use MainController of adminpanel extension.', E_USER_DEPRECATED);
         return $this->adminPanel->display();
     }
 
     /**
      * Determines whether the admin panel is enabled and visible.
      *
+     * @deprecated since TYPO3v9 - see ext "adminpanel" for new API
      * @return bool true if the admin panel is enabled and visible
      */
     public function isAdminPanelVisible()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use new adminpanel API instead.', E_USER_DEPRECATED);
         return $this->extAdmEnabled && !$this->extAdminConfig['hide'] && $GLOBALS['TSFE']->config['config']['admPanel'];
     }
 
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst
new file mode 100644 (file)
index 0000000..051f5ed
--- /dev/null
@@ -0,0 +1,53 @@
+.. include:: ../../Includes.txt
+
+===============================================================================================================
+Deprecation: #84641 - Deprecated AdminPanel related methods and properties in FrontendBackendUserAuthentication
+===============================================================================================================
+
+See :issue:`84641`
+
+Description
+===========
+
+The admin panel has been extracted into an own extension. To enable users to de-activate the admin panel completely, the hard coupling between the extension and other parts of the core had to be resolved. The admin panel now takes care of its own initialization and provides API methods related to its functionality.
+The following API methods and properties located in `FrontendBackendUserAuthentication` have been deprecated:
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$adminPanel`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdminConfig`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdmEnabled`
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeAdminPanel()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeFrontendEdit()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isFrontendEditingActive()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::displayAdminPanel()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isAdminPanelVisible()`
+
+
+Impact
+======
+
+Using any of the methods will trigger a deprecation warning.
+
+
+Affected Installations
+======================
+
+Any installation directly calling one of the mentioned methods or properties.
+
+
+Migration
+=========
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$adminPanel` - use `MainController` of adminpanel instead
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdminConfig` - load directly from TSConfig if needed
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdmEnabled` - check directly against TSConfig if necessary
+
+Both initialization methods `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeAdminPanel` and
+`\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeFrontendEdit` were rewritten as PSR-15 middlewares,
+remove any calls as they are not necessary anymore.
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isFrontendEditingActive` and `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isAdminPanelVisible` - check against TSFE directly
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::displayAdminPanel` - use `MainController::render()` instead
+
+.. index:: Frontend, PHP-API, PartiallyScanned
index 54addc2..0133177 100644 (file)
@@ -13,7 +13,7 @@ namespace TYPO3\CMS\Feedit;
  *
  * The TYPO3 project - inspiring people to share!
  */
-use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -97,8 +97,9 @@ class FrontendEditPanel
         $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
 
         $panel = '';
-        if (isset($allow['toolbar']) && $this->backendUser->adminPanel instanceof AdminPanelView) {
-            $panel .= $this->backendUser->adminPanel->ext_makeToolBar();
+        if (isset($allow['toolbar'])) {
+            $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
+            $panel .= $editToolbarService->createToolbar();
         }
         if (isset($allow['edit'])) {
             $icon = '<span title="' . $this->backendUser->extGetLL('p_editRecord') . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render('inline') . '</span>';
diff --git a/typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php b/typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php
new file mode 100644 (file)
index 0000000..96c7ede
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Feedit\Middleware;
+
+/*
+ * 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\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * PSR-15 middleware initializing frontend editing
+ */
+class FrontendEditInitiator implements MiddlewareInterface
+{
+
+    /**
+     * Process an incoming server request and return a response, optionally delegating
+     * response creation to a handler.
+     *
+     * @param ServerRequestInterface $request
+     * @param RequestHandlerInterface $handler
+     * @return ResponseInterface
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if ($GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
+            $config = $GLOBALS['BE_USER']->getTSConfigProp('admPanel');
+            $active = (int)$GLOBALS['TSFE']->displayEditIcons === 1 || (int)$GLOBALS['TSFE']->displayFieldEditIcons === 1;
+            if ($active && isset($config['enable.'])) {
+                foreach ($config['enable.'] as $value) {
+                    if ($value) {
+                        if ($GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
+                            // Grab the Page TSConfig property that determines which controller to use.
+                            $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig();
+                            $controllerKey = $pageTSConfig['TSFE.']['frontendEditingController'] ?? 'default';
+                        } else {
+                            $controllerKey = 'default';
+                        }
+                        $controllerClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController'][$controllerKey];
+                        if ($controllerClass) {
+                            $GLOBALS['BE_USER']->frontendEdit = GeneralUtility::makeInstance($controllerClass);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        return $handler->handle($request);
+    }
+}
diff --git a/typo3/sysext/feedit/Configuration/RequestMiddlewares.php b/typo3/sysext/feedit/Configuration/RequestMiddlewares.php
new file mode 100644 (file)
index 0000000..71ca4ac
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+/**
+ * An array consisting of implementations of middlewares for a middleware stack to be registered
+ *  'stackname' => [
+ *      'middleware-identifier' => [
+ *         'target' => classname or callable
+ *         'before/after' => array of dependencies
+ *      ]
+ *   ]
+ */
+return [
+    'frontend' => [
+        'typo3/cms-frontendedit/initiator' => [
+            'target' => \TYPO3\CMS\Feedit\Middleware\FrontendEditInitiator::class,
+            'after' => [
+                'typo3/cms-adminpanel/initiator',
+                'typo3/cms-frontend/page-resolver',
+            ]
+        ],
+    ]
+];
index 45608ec..0579243 100644 (file)
                "sort-packages": true
        },
        "require": {
-               "typo3/cms-core": "9.2.*@dev"
+               "typo3/cms-adminpanel": "9.2.*@dev",
+               "typo3/cms-backend": "9.2.*@dev",
+               "typo3/cms-core": "9.2.*@dev",
+               "typo3/cms-frontend": "9.2.*@dev",
+               "psr/http-message": "~1.0",
+               "psr/http-server-handler": "^1.0",
+               "psr/http-server-middleware": "^1.0"
        },
        "conflict": {
                "typo3/cms": "*"
index c7755da..e00620e 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Frontend\Http;
 
 /*
@@ -18,7 +19,6 @@ namespace TYPO3\CMS\Frontend\Http;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
-use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
 use TYPO3\CMS\Core\Http\NullResponse;
 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
@@ -161,11 +161,6 @@ class RequestHandler implements RequestHandlerInterface, PsrRequestHandlerInterf
         // Finish timetracking
         $this->timeTracker->pull();
 
-        // Admin panel
-        if ($controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication && $GLOBALS['BE_USER']->isAdminPanelVisible()) {
-            $controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $controller->content);
-        }
-
         if ($isOutputting) {
             $response->getBody()->write($controller->content);
         }
index 9f64161..1611085 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Frontend\Middleware;
 
 /*
@@ -83,8 +84,6 @@ class BackendUserAuthenticator implements MiddlewareInterface
             Bootstrap::initializeLanguageObject();
             Bootstrap::initializeBackendRouter();
             Bootstrap::loadExtTables();
-            // Initialize admin panel since simulation settings are required here
-            $GLOBALS['BE_USER']->initializeAdminPanel();
         }
 
         return $handler->handle($request);
index 133c0b6..107b11d 100644 (file)
@@ -18,6 +18,9 @@
        "conflict": {
                "typo3/cms": "*"
        },
+       "suggest": {
+               "typo3/cms-adminpanel": "Provides additional information and functionality for backend users in the frontend."
+       },
        "replace": {
                "frontend": "*"
        },
index d7b3831..4808ea5 100644 (file)
@@ -2081,4 +2081,39 @@ return [
             'Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->initializeAdminPanel' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->initializeFrontendEdit' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->isFrontendEditingActive' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->displayAdminPanel' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->isAdminPanelVisible' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
 ];
index 7877349..b24c1dd 100644 (file)
@@ -376,4 +376,19 @@ return [
             'Deprecation-84295-UseServerRequestInterfaceInFileEditFileController.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->adminPanel' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->extAdminConfig' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->extAdmEnabled' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
 ];
index a9652af..5bb3919 100644 (file)
@@ -9,6 +9,9 @@
                        <trans-unit id="adminPanelTitle">
                                <source>TYPO3 ADMIN PANEL</source>
                        </trans-unit>
+                       <trans-unit id="preview">
+                               <source>Preview</source>
+                       </trans-unit>
                        <trans-unit id="publish">
                                <source>Publish</source>
                        </trans-unit>
index 2ddc33e..807a18e 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Workspaces\Authentication;
 
 /*
@@ -107,34 +108,4 @@ class PreviewUserAuthentication extends BackendUserAuthentication
     {
         return Permission::PAGE_SHOW;
     }
-
-    /**
-     * Stub to ensure that frontend editing is not possible as a preview user
-     *
-     * @return bool
-     */
-    public function initializeFrontendEdit()
-    {
-        return false;
-    }
-
-    /**
-     * Stub to ensure that frontend editing is not possible as a preview user
-     *
-     * @return bool
-     */
-    public function isFrontendEditingActive()
-    {
-        return false;
-    }
-
-    /**
-     * Stub to ensure that admin panel is not visible as a preview user
-     *
-     * @return bool
-     */
-    public function isAdminPanelVisible()
-    {
-        return false;
-    }
 }