‪TYPO3CMS  ‪main
BackendController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
43 use TYPO3\CMS\Core\Type\File\ImageInfo;
48 
53 #[Controller]
55 {
57 
61  protected array ‪$modules;
62 
63  public function ‪__construct(
64  protected readonly ‪Typo3Version $typo3Version,
65  protected readonly ‪UriBuilder $uriBuilder,
66  protected readonly ‪PageRenderer $pageRenderer,
67  protected readonly ‪ModuleProvider $moduleProvider,
68  protected readonly ‪ToolbarItemsRegistry $toolbarItemsRegistry,
69  protected readonly ‪ExtensionConfiguration $extensionConfiguration,
70  protected readonly ‪BackendViewFactory $viewFactory,
71  protected readonly EventDispatcherInterface $eventDispatcher,
72  ) {
73  $this->modules = $this->moduleProvider->getModulesForModuleMenu($this->‪getBackendUser());
74  }
75 
79  public function ‪mainAction(ServerRequestInterface $request): ResponseInterface
80  {
81  $backendUser = $this->‪getBackendUser();
82  $pageRenderer = $this->pageRenderer;
83  // apply nonce hint for elements that are shown in a modal
84  $pageRenderer->setApplyNonceHint(true);
85 
86  $this->‪setUpBasicPageRendererForBackend($pageRenderer, $this->extensionConfiguration, $request, $this->‪getLanguageService());
87 
88  $javaScriptRenderer = $pageRenderer->getJavaScriptRenderer();
89  $javaScriptRenderer->addGlobalAssignment(['window' => [
90  'name' => 'typo3-backend', // reset window name to a standardized value
91  'opener' => null, // remove any previously set opener value
92  ]]);
93  $javaScriptRenderer->addJavaScriptModuleInstruction(
94  ‪JavaScriptModuleInstruction::create('@typo3/backend/login-refresh.js')
95  ->invoke('initialize', [
96  'intervalTime' => ‪MathUtility::forceIntegerInRange((int)‪$GLOBALS['TYPO3_CONF_VARS']['BE']['sessionTimeout'] - 60, 60),
97  'requestTokenUrl' => (string)$this->uriBuilder->buildUriFromRoute('login_request_token'),
98  'loginFramesetUrl' => (string)$this->uriBuilder->buildUriFromRoute('login_frameset'),
99  'logoutUrl' => (string)$this->uriBuilder->buildUriFromRoute('logout'),
100  ])
101  );
102  $javaScriptRenderer->addJavaScriptModuleInstruction(
103  ‪JavaScriptModuleInstruction::create('@typo3/backend/broadcast-service.js')->invoke('listen')
104  );
105  // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed
106  $javaScriptRenderer->addJavaScriptModuleInstruction(
107  ‪JavaScriptModuleInstruction::create('@typo3/backend/storage/persistent.js')
108  ->invoke('load', $backendUser->uc)
109  );
110  $javaScriptRenderer->addGlobalAssignment([
111  'TYPO3' => [
112  'configuration' => [
113  'username' => htmlspecialchars($backendUser->user['username']),
114  'showRefreshLoginPopup' => (bool)(‪$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] ?? false),
115  ],
116  ],
117  ]);
118  $javaScriptRenderer->includeTaggedImports('backend.module');
119  $javaScriptRenderer->includeTaggedImports('backend.navigation-component');
120 
121  // @todo: This loads a ton of labels into JS. This should be reviewed what is really needed.
122  // This could happen when the localization API gets an overhaul.
123  $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf');
124  $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
125  $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
126  $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
127  $pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/wizard.xlf');
128 
129  // @todo: We can not put this into the template since PageRendererViewHelper does not deal with namespace in addInlineSettings argument
130  $pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('show_item'));
131  $pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('record_history'));
132  $pageRenderer->addInlineSetting('NewRecord', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('db_new'));
133  $pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('record_edit'));
134  $pageRenderer->addInlineSetting('RecordCommit', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('tce_db'));
135  $pageRenderer->addInlineSetting('FileCommit', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('tce_file'));
136  $pageRenderer->addInlineSetting('Clipboard', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('clipboard_process'));
137  $dateFormat = ['dd-MM-yyyy', 'HH:mm dd-MM-yyyy'];
138  // Needed for FormEngine manipulation (date picker)
139  $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
140  $typo3Version = 'TYPO3 CMS ' . $this->typo3Version->getVersion();
141  $title = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [' . $typo3Version . ']' : $typo3Version;
142  $pageRenderer->setTitle($title);
143 
144  $view = $this->viewFactory->create($request);
145  $this->‪assignTopbarDetailsToView($request, $view);
146  $view->assignMultiple([
147  'modules' => $this->modules,
148  'modulesCollapsed' => $this->‪getCollapseStateOfMenu(),
149  'modulesInformation' => GeneralUtility::jsonEncodeForHtmlAttribute($this->‪getModulesInformation(), false),
150  'startupModule' => $this->‪getStartupModule($request),
151  'stateTracker' => (string)$this->uriBuilder->buildUriFromRoute('state-tracker'),
152  'sitename' => $title,
153  'sitenameFirstInBackendTitle' => ($backendUser->uc['backendTitleFormat'] ?? '') === 'sitenameFirst',
154  ]);
155  $content = $view->render('Backend/Main');
156  $content = $this->eventDispatcher->dispatch(new ‪AfterBackendPageRenderEvent($content, $view))->getContent();
157  $pageRenderer->addBodyContent('<body>' . $content);
158  return $pageRenderer->renderResponse();
159  }
160 
166  public function ‪getModuleMenu(ServerRequestInterface $request): ResponseInterface
167  {
168  $view = $this->viewFactory->create($request);
169  $view->assignMultiple([
170  'modulesInformation' => GeneralUtility::jsonEncodeForHtmlAttribute($this->‪getModulesInformation(), false),
171  'modules' => $this->modules,
172  ]);
173  return new JsonResponse(['menu' => $view->render('Backend/ModuleMenu')]);
174  }
175 
180  public function ‪getTopbar(ServerRequestInterface $request): ResponseInterface
181  {
182  $view = $this->viewFactory->create($request);
183  $this->‪assignTopbarDetailsToView($request, $view);
184  return new JsonResponse(['topbar' => $view->render('Backend/Topbar')]);
185  }
186 
190  protected function ‪assignTopbarDetailsToView(ServerRequestInterface $request, ViewInterface $view): void
191  {
192  // Extension Configuration to find the TYPO3 logo in the left corner
193  ‪$extConf = $this->extensionConfiguration->get('backend');
194  $logoPath = '';
195  if (!empty(‪$extConf['backendLogo'])) {
196  $customBackendLogo = GeneralUtility::getFileAbsFileName(ltrim(‪$extConf['backendLogo'], '/'));
197  if (!empty($customBackendLogo)) {
198  $logoPath = $customBackendLogo;
199  }
200  }
201  // if no custom logo was set or the path is invalid, use the original one
202  if (empty($logoPath) || !file_exists($logoPath)) {
203  $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg');
204  $logoWidth = 22;
205  $logoHeight = 22;
206  } else {
207  // set width/height for custom logo
208  $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $logoPath);
209  $logoWidth = $imageInfo->getWidth() ?: 22;
210  $logoHeight = $imageInfo->getHeight() ?: 22;
211 
212  // High-resolution?
213  if (str_contains($logoPath, '@2x.')) {
214  $logoWidth /= 2;
215  $logoHeight /= 2;
216  }
217  }
218  $view->assign('hasModules', (bool)$this->modules);
219  $view->assign('logoUrl', ‪PathUtility::getAbsoluteWebPath($logoPath));
220  $view->assign('logoWidth', $logoWidth);
221  $view->assign('logoHeight', $logoHeight);
222  $view->assign('applicationVersion', $this->typo3Version->getVersion());
223  $view->assign('siteName', ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
224  $view->assign('toolbarItems', $this->‪getToolbarItems($request));
225  $view->assign('isInWorkspace', $this->‪getBackendUser()->workspace > 0);
226  }
227 
231  protected function ‪getToolbarItems(ServerRequestInterface $request): array
232  {
233  return array_map(static function (ToolbarItemInterface $toolbarItem) use ($request): ToolbarItemInterface {
234  if ($toolbarItem instanceof RequestAwareToolbarItemInterface) {
235  $toolbarItem->setRequest($request);
236  }
237  return $toolbarItem;
238  }, array_filter(
239  $this->toolbarItemsRegistry->getToolbarItems(),
240  static fn(ToolbarItemInterface $toolbarItem): bool => $toolbarItem->checkAccess()
241  ));
242  }
243 
247  protected function ‪getStartupModule(ServerRequestInterface $request): array
248  {
249  $startModule = null;
250  $moduleParameters = [];
251  try {
252  $redirect = ‪RouteRedirect::createFromRequest($request);
253  if ($request->getMethod() === 'GET' && $redirect !== null) {
254  // Only redirect to existing non-ajax routes with no restriction to a specific method
255  $redirect->resolve(GeneralUtility::makeInstance(Router::class));
256  $startModule = $redirect->getName();
257  $moduleParameters = $redirect->getParameters();
258  }
259  } finally {
260  // No valid redirect, check for the start module
261  if (!$startModule) {
262  $backendUser = $this->‪getBackendUser();
263  // start module on first login, will be removed once used the first time
264  if (isset($backendUser->uc['startModuleOnFirstLogin'])) {
265  $startModule = $backendUser->uc['startModuleOnFirstLogin'];
266  unset($backendUser->uc['startModuleOnFirstLogin']);
267  $backendUser->writeUC();
268  } elseif (isset($backendUser->uc['startModule']) && $this->moduleProvider->accessGranted($backendUser->uc['startModule'], $backendUser)) {
269  $startModule = $backendUser->uc['startModule'];
270  } elseif ($firstAccessibleModule = $this->moduleProvider->getFirstAccessibleModule($backendUser)) {
271  $startModule = $firstAccessibleModule->getIdentifier();
272  }
273 
274  // check if the start module has additional parameters, so a redirect to a specific
275  // action is possible
276  if (is_string($startModule) && str_contains($startModule, '->')) {
277  [$startModule, $startModuleParameters] = explode('->', $startModule, 2);
278  // if no GET parameters are set, check if there are parameters given from the UC
279  if (!$moduleParameters && $startModuleParameters) {
280  $moduleParameters = $startModuleParameters;
281  }
282  }
283  }
284  }
285  if ($startModule) {
286  if ($this->moduleProvider->isModuleRegistered($startModule)) {
287  // startModule may be an alias, resolve original module name
288  $startModule = $this->moduleProvider->getModule($startModule, $this->‪getBackendUser())->getIdentifier();
289  }
290  if (is_array($moduleParameters)) {
291  $parameters = $moduleParameters;
292  } else {
293  $parameters = [];
294  parse_str($moduleParameters, $parameters);
295  }
296  $deepLink = $this->uriBuilder->buildUriFromRoute($startModule, $parameters);
297  return [$startModule, (string)$deepLink];
298  }
299  return [null, null];
300  }
301 
305  protected function ‪getModulesInformation(): array
306  {
307  ‪$modules = [];
308  foreach ($this->moduleProvider->getModules(user: $this->getBackendUser(), grouped: false) as ‪$identifier => $module) {
309  $menuModule = new MenuModule(clone $module);
311  'name' => ‪$identifier,
312  'component' => $menuModule->getComponent(),
313  'navigationComponentId' => $menuModule->getNavigationComponent(),
314  'parent' => $menuModule->hasParentModule() ? $menuModule->getParentIdentifier() : '',
315  'link' => $menuModule->getShouldBeLinked() ? (string)$this->uriBuilder->buildUriFromRoute($module->getIdentifier()) : '',
316  ];
317  }
318 
319  return ‪$modules;
320  }
321 
322  protected function ‪getCollapseStateOfMenu(): bool
323  {
324  $backendUser = $this->‪getBackendUser();
325  $uc = json_decode((string)json_encode($backendUser->uc), true);
326  $collapseState = $uc['BackendComponents']['States']['typo3-module-menu']['collapsed'] ?? false;
327  return $collapseState === true || $collapseState === 'true';
328  }
329 
330  protected function ‪getBackendUser(): ‪BackendUserAuthentication
331  {
332  return ‪$GLOBALS['BE_USER'];
333  }
334 
335  protected function ‪getLanguageService(): ‪LanguageService
336  {
337  return ‪$GLOBALS['LANG'];
338  }
339 }
‪TYPO3\CMS\Backend\Controller\BackendController\assignTopbarDetailsToView
‪assignTopbarDetailsToView(ServerRequestInterface $request, ViewInterface $view)
Definition: BackendController.php:189
‪TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface
Definition: ToolbarItemInterface.php:22
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\View\ViewInterface
Definition: ViewInterface.php:24
‪TYPO3\CMS\Backend\Controller\BackendController\getToolbarItems
‪ToolbarItemInterface[] getToolbarItems(ServerRequestInterface $request)
Definition: BackendController.php:230
‪TYPO3\CMS\Core\Information\Typo3Version
Definition: Typo3Version.php:21
‪TYPO3\CMS\Backend\View\BackendViewFactory
Definition: BackendViewFactory.php:35
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:47
‪TYPO3\CMS\Backend\Controller\BackendController\mainAction
‪mainAction(ServerRequestInterface $request)
Definition: BackendController.php:78
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Template\PageRendererBackendSetupTrait
Definition: PageRendererBackendSetupTrait.php:45
‪TYPO3\CMS\Backend\Controller\BackendController\getBackendUser
‪getBackendUser()
Definition: BackendController.php:329
‪TYPO3\CMS\Backend\Attribute\Controller
Definition: Controller.php:25
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Toolbar\ToolbarItemsRegistry
Definition: ToolbarItemsRegistry.php:25
‪TYPO3\CMS\Backend\Module\ModuleProvider
Definition: ModuleProvider.php:29
‪TYPO3\CMS\Backend\Controller\BackendController\getModulesInformation
‪getModulesInformation()
Definition: BackendController.php:304
‪TYPO3\CMS\Core\View\ViewInterface\assign
‪assign(string $key, mixed $value)
‪TYPO3\CMS\Backend\Controller\Event\AfterBackendPageRenderEvent
Definition: AfterBackendPageRenderEvent.php:29
‪TYPO3\CMS\Backend\Controller\BackendController\getStartupModule
‪getStartupModule(ServerRequestInterface $request)
Definition: BackendController.php:246
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath(string $targetPath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:52
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:46
‪TYPO3\CMS\Backend\Routing\RouteRedirect
Definition: RouteRedirect.php:30
‪TYPO3\CMS\Backend\Controller\BackendController\getModuleMenu
‪getModuleMenu(ServerRequestInterface $request)
Definition: BackendController.php:165
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Backend\Module\MenuModule
Definition: MenuModule.php:26
‪TYPO3\CMS\Backend\Controller\BackendController\getLanguageService
‪getLanguageService()
Definition: BackendController.php:334
‪TYPO3\CMS\Backend\Module\ModuleInterface
Definition: ModuleInterface.php:24
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:64
‪TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface\checkAccess
‪bool checkAccess()
‪TYPO3\CMS\Backend\Controller\BackendController
Definition: BackendController.php:55
‪TYPO3\CMS\Backend\Controller\BackendController\getTopbar
‪getTopbar(ServerRequestInterface $request)
Definition: BackendController.php:179
‪TYPO3\CMS\Backend\Controller\BackendController\getCollapseStateOfMenu
‪getCollapseStateOfMenu()
Definition: BackendController.php:321
‪TYPO3\CMS\Backend\Toolbar\RequestAwareToolbarItemInterface
Definition: RequestAwareToolbarItemInterface.php:27
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Controller\BackendController\__construct
‪__construct(protected readonly Typo3Version $typo3Version, protected readonly UriBuilder $uriBuilder, protected readonly PageRenderer $pageRenderer, protected readonly ModuleProvider $moduleProvider, protected readonly ToolbarItemsRegistry $toolbarItemsRegistry, protected readonly ExtensionConfiguration $extensionConfiguration, protected readonly BackendViewFactory $viewFactory, protected readonly EventDispatcherInterface $eventDispatcher,)
Definition: BackendController.php:62
‪TYPO3\CMS\Backend\Controller\BackendController\$modules
‪array $modules
Definition: BackendController.php:60
‪TYPO3\CMS\Backend\Template\PageRendererBackendSetupTrait\setUpBasicPageRendererForBackend
‪setUpBasicPageRendererForBackend(PageRenderer $pageRenderer, ExtensionConfiguration $extensionConfiguration, ServerRequestInterface $request, LanguageService $languageService,)
Definition: PageRendererBackendSetupTrait.php:49
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Backend\Routing\RouteRedirect\createFromRequest
‪static createFromRequest(ServerRequestInterface $request)
Definition: RouteRedirect.php:58
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪$extConf
‪$extConf
Definition: ext_localconf.php:56
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Backend\Routing\Router
Definition: Router.php:39
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:18
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37