c22a08b2e51e56e8a9357f5c097eecbcdcc04439
[Packages/TYPO3.CMS.git] / typo3 / sysext / adminpanel / Classes / Controller / MainController.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Adminpanel\Controller;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Adminpanel\ModuleApi\ConfigurableInterface;
21 use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
22 use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
23 use TYPO3\CMS\Adminpanel\ModuleApi\ModuleDataStorageCollection;
24 use TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface;
25 use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface;
26 use TYPO3\CMS\Adminpanel\ModuleApi\ShortInfoProviderInterface;
27 use TYPO3\CMS\Adminpanel\ModuleApi\SubmoduleProviderInterface;
28 use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
29 use TYPO3\CMS\Adminpanel\Service\ModuleLoader;
30 use TYPO3\CMS\Adminpanel\Utility\ResourceUtility;
31 use TYPO3\CMS\Adminpanel\Utility\StateUtility;
32 use TYPO3\CMS\Adminpanel\View\AdminPanelView;
33 use TYPO3\CMS\Backend\Routing\UriBuilder;
34 use TYPO3\CMS\Core\Cache\CacheManager;
35 use TYPO3\CMS\Core\SingletonInterface;
36 use TYPO3\CMS\Core\Utility\GeneralUtility;
37 use TYPO3\CMS\Fluid\View\StandaloneView;
38
39 /**
40 * Main controller for the admin panel
41 *
42 * @internal
43 */
44 class MainController implements SingletonInterface
45 {
46 /**
47 * @var \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[]
48 */
49 protected $modules = [];
50
51 /**
52 * @var ModuleLoader
53 */
54 protected $moduleLoader;
55
56 /**
57 * @var UriBuilder
58 */
59 protected $uriBuilder;
60
61 /**
62 * @var ConfigurationService
63 */
64 protected $configurationService;
65
66 /**
67 * @var array
68 */
69 protected $adminPanelModuleConfiguration;
70
71 /**
72 * @param ModuleLoader $moduleLoader
73 * @param UriBuilder $uriBuilder
74 * @param ConfigurationService $configurationService
75 */
76 public function __construct(
77 ModuleLoader $moduleLoader = null,
78 UriBuilder $uriBuilder = null,
79 ConfigurationService $configurationService = null
80 ) {
81 $this->moduleLoader = $moduleLoader ?? GeneralUtility::makeInstance(ModuleLoader::class);
82 $this->uriBuilder = $uriBuilder ?? GeneralUtility::makeInstance(UriBuilder::class);
83 $this->configurationService = $configurationService
84 ??
85 GeneralUtility::makeInstance(ConfigurationService::class);
86 $this->adminPanelModuleConfiguration = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
87 }
88
89 /**
90 * Initializes settings for the admin panel.
91 *
92 * @param ServerRequestInterface $request
93 */
94 public function initialize(ServerRequestInterface $request): void
95 {
96 $this->modules = $this->moduleLoader->validateSortAndInitializeModules(
97 $this->adminPanelModuleConfiguration
98 );
99
100 if (StateUtility::isActivatedForUser()) {
101 $this->initializeModules($request, $this->modules);
102 }
103 }
104
105 /**
106 * Renders the admin panel - Called in PSR-15 Middleware
107 *
108 * @see \TYPO3\CMS\Adminpanel\Middleware\AdminPanelRenderer
109 * @param \Psr\Http\Message\ServerRequestInterface $request
110 * @return string
111 */
112 public function render(ServerRequestInterface $request): string
113 {
114 // legacy handling, deprecated, will be removed in TYPO3 v10.0.
115 $adminPanelView = GeneralUtility::makeInstance(AdminPanelView::class);
116 $hookObjectContent = $adminPanelView->callDeprecatedHookObject();
117 // end legacy handling
118
119 $resources = ResourceUtility::getResources();
120
121 $view = GeneralUtility::makeInstance(StandaloneView::class);
122 $templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Main.html';
123 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
124 $view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
125 $view->setLayoutRootPaths(['EXT:adminpanel/Resources/Private/Layouts']);
126
127 $view->assignMultiple(
128 [
129 'toggleActiveUrl' => $this->generateBackendUrl('ajax_adminPanel_toggle'),
130 'resources' => $resources,
131 'adminPanelActive' => StateUtility::isOpen(),
132 ]
133 );
134 if (StateUtility::isOpen()) {
135 $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('adminpanel_requestcache');
136 $requestId = $request->getAttribute('adminPanelRequestId');
137 $data = $cache->get($requestId);
138 $moduleResources = ResourceUtility::getAdditionalResourcesForModules($this->modules);
139 $settingsModules = array_filter($this->modules, function (ModuleInterface $module) {
140 return $module instanceof PageSettingsProviderInterface;
141 });
142 $parentModules = array_filter(
143 $this->modules,
144 function (ModuleInterface $module) {
145 return $module instanceof SubmoduleProviderInterface && $module instanceof ShortInfoProviderInterface;
146 }
147 );
148 $view->assignMultiple(
149 [
150 'modules' => $this->modules,
151 'settingsModules' => $settingsModules,
152 'parentModules' => $parentModules,
153 'hookObjectContent' => $hookObjectContent,
154 'saveUrl' => $this->generateBackendUrl('ajax_adminPanel_saveForm'),
155 'moduleResources' => $moduleResources,
156 'requestId' => $requestId,
157 'data' => $data ?? [],
158 ]
159 );
160 }
161 return $view->render();
162 }
163
164 /**
165 * Stores data for admin panel in cache - Called in PSR-15 Middleware
166 *
167 * @see \TYPO3\CMS\Adminpanel\Middleware\AdminPanelDataPersister
168 * @param \Psr\Http\Message\ServerRequestInterface $request
169 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
170 */
171 public function storeData(ServerRequestInterface $request): void
172 {
173 if (StateUtility::isOpen()) {
174 $data = $this->storeDataPerModule(
175 $request,
176 $this->modules,
177 GeneralUtility::makeInstance(ModuleDataStorageCollection::class)
178 );
179 $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('adminpanel_requestcache');
180 $cache->set($request->getAttribute('adminPanelRequestId'), $data);
181 $cache->collectGarbage();
182 }
183 }
184
185 /**
186 * Generate a url to a backend route
187 *
188 * @param string $route
189 * @return string
190 */
191 protected function generateBackendUrl(string $route): string
192 {
193 return (string)$this->uriBuilder->buildUriFromRoute($route);
194 }
195
196 /**
197 * @param \Psr\Http\Message\ServerRequestInterface $request
198 * @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $modules
199 */
200 protected function initializeModules(ServerRequestInterface $request, array $modules): void
201 {
202 foreach ($modules as $module) {
203 if (
204 ($module instanceof InitializableInterface)
205 && (
206 (($module instanceof ConfigurableInterface) && $module->isEnabled())
207 || (!($module instanceof ConfigurableInterface))
208 )
209 ) {
210 $module->initializeModule($request);
211 }
212 if ($module instanceof SubmoduleProviderInterface) {
213 $this->initializeModules($request, $module->getSubModules());
214 }
215 }
216 }
217
218 /**
219 * @param \Psr\Http\Message\ServerRequestInterface $request
220 * @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $modules
221 * @param ModuleDataStorageCollection $data
222 * @return ModuleDataStorageCollection
223 */
224 protected function storeDataPerModule(ServerRequestInterface $request, array $modules, ModuleDataStorageCollection $data): ModuleDataStorageCollection
225 {
226 foreach ($modules as $module) {
227 if (
228 ($module instanceof DataProviderInterface)
229 && (
230 (($module instanceof ConfigurableInterface) && $module->isEnabled())
231 || (!($module instanceof ConfigurableInterface))
232 )
233 ) {
234 $data->addModuleData($module, $module->getDataToStore($request));
235 }
236
237 if ($module instanceof SubmoduleProviderInterface) {
238 $this->storeDataPerModule($request, $module->getSubModules(), $data);
239 }
240 }
241 return $data;
242 }
243 }