[TASK] Deprecate PageRenderer->loadJQuery()
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / BackendController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
19 use TYPO3\CMS\Backend\Module\ModuleLoader;
20 use TYPO3\CMS\Backend\Routing\UriBuilder;
21 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
24 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
25 use TYPO3\CMS\Core\Database\ConnectionPool;
26 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
27 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28 use TYPO3\CMS\Core\Http\HtmlResponse;
29 use TYPO3\CMS\Core\Http\JsonResponse;
30 use TYPO3\CMS\Core\Imaging\IconFactory;
31 use TYPO3\CMS\Core\Page\PageRenderer;
32 use TYPO3\CMS\Core\Type\Bitmask\Permission;
33 use TYPO3\CMS\Core\Type\File\ImageInfo;
34 use TYPO3\CMS\Core\Utility\GeneralUtility;
35 use TYPO3\CMS\Core\Utility\MathUtility;
36 use TYPO3\CMS\Core\Utility\PathUtility;
37 use TYPO3\CMS\Fluid\View\StandaloneView;
38
39 /**
40 * Class for rendering the TYPO3 backend
41 */
42 class BackendController
43 {
44 use PublicMethodDeprecationTrait;
45
46 /**
47 * @var array
48 */
49 private $deprecatedPublicMethods = [
50 'render' => 'Using BackendController::render() is deprecated and will not be possible anymore in TYPO3 v10.',
51 ];
52
53 /**
54 * @var string
55 */
56 protected $content = '';
57
58 /**
59 * @var string
60 */
61 protected $css = '';
62
63 /**
64 * @var array
65 */
66 protected $cssFiles = [];
67
68 /**
69 * @var string
70 */
71 protected $js = '';
72
73 /**
74 * @var array
75 */
76 protected $jsFiles = [];
77
78 /**
79 * @var array
80 */
81 protected $toolbarItems = [];
82
83 /**
84 * @var bool
85 */
86 protected $debug;
87
88 /**
89 * @var string
90 */
91 protected $templatePath = 'EXT:backend/Resources/Private/Templates/';
92
93 /**
94 * @var string
95 */
96 protected $partialPath = 'EXT:backend/Resources/Private/Partials/';
97
98 /**
99 * @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository
100 */
101 protected $backendModuleRepository;
102
103 /**
104 * @var \TYPO3\CMS\Backend\Module\ModuleLoader Object for loading backend modules
105 */
106 protected $moduleLoader;
107
108 /**
109 * @var PageRenderer
110 */
111 protected $pageRenderer;
112
113 /**
114 * @var IconFactory
115 */
116 protected $iconFactory;
117
118 /**
119 * Constructor
120 */
121 public function __construct()
122 {
123 $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
124
125 $this->backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
126 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
127 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
128 // Set debug flag for BE development only
129 $this->debug = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1;
130 // Initializes the backend modules structure for use later.
131 $this->moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
132 $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
133 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
134 // Add default BE javascript
135 $this->jsFiles = [
136 'md5' => 'EXT:backend/Resources/Public/JavaScript/md5.js',
137 'evalfield' => 'EXT:backend/Resources/Public/JavaScript/jsfunc.evalfield.js',
138 'backend' => 'EXT:backend/Resources/Public/JavaScript/backend.js',
139 ];
140 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LoginRefresh', 'function(LoginRefresh) {
141 LoginRefresh.setIntervalTime(' . MathUtility::forceIntegerInRange((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['sessionTimeout'] - 60, 60) . ');
142 LoginRefresh.setLoginFramesetUrl(' . GeneralUtility::quoteJSvalue((string)$uriBuilder->buildUriFromRoute('login_frameset')) . ');
143 LoginRefresh.setLogoutUrl(' . GeneralUtility::quoteJSvalue((string)$uriBuilder->buildUriFromRoute('logout')) . ');
144 LoginRefresh.initialize();
145 }');
146
147 // load module menu
148 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ModuleMenu');
149
150 // load Toolbar class
151 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar');
152
153 // load Utility class
154 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Utility');
155
156 // load Notification functionality
157 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Notification');
158
159 // load Modals
160 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
161
162 // load InfoWindow
163 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/InfoWindow');
164
165 // load ContextMenu
166 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
167
168 // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed
169 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Storage');
170 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Storage/Persistent', 'function(PersistentStorage) {
171 PersistentStorage.load(' . json_encode($this->getBackendUser()->uc) . ');
172 }');
173
174 // load debug console
175 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DebugConsole');
176
177 $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf');
178 $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
179 $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
180 $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
181
182 $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/debugger.xlf');
183 $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/wizard.xlf');
184
185 $this->pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('show_item'));
186 $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_history'));
187 $this->pageRenderer->addInlineSetting('NewRecord', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('db_new'));
188 $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('record_edit'));
189 $this->pageRenderer->addInlineSetting('RecordCommit', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('tce_db'));
190 $this->pageRenderer->addInlineSetting('WebLayout', 'moduleUrl', (string)$uriBuilder->buildUriFromRoute('web_layout'));
191
192 $this->css = '';
193
194 $this->initializeToolbarItems();
195 $this->executeHook('constructPostProcess');
196 }
197
198 /**
199 * Initialize toolbar item objects
200 *
201 * @throws \RuntimeException
202 */
203 protected function initializeToolbarItems()
204 {
205 $toolbarItemInstances = [];
206 foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] ?? [] as $className) {
207 $toolbarItemInstance = GeneralUtility::makeInstance($className);
208 if (!$toolbarItemInstance instanceof ToolbarItemInterface) {
209 throw new \RuntimeException(
210 'class ' . $className . ' is registered as toolbar item but does not implement'
211 . ToolbarItemInterface::class,
212 1415958218
213 );
214 }
215 $index = (int)$toolbarItemInstance->getIndex();
216 if ($index < 0 || $index > 100) {
217 throw new \RuntimeException(
218 'getIndex() must return an integer between 0 and 100',
219 1415968498
220 );
221 }
222 // Find next free position in array
223 while (array_key_exists($index, $toolbarItemInstances)) {
224 $index++;
225 }
226 $toolbarItemInstances[$index] = $toolbarItemInstance;
227 }
228 ksort($toolbarItemInstances);
229 $this->toolbarItems = $toolbarItemInstances;
230 }
231
232 /**
233 * Injects the request object for the current request or subrequest
234 * As this controller goes only through the render() method, it is rather simple for now
235 *
236 * @return ResponseInterface the response with the content
237 */
238 public function mainAction(): ResponseInterface
239 {
240 $this->render();
241 return new HtmlResponse($this->content);
242 }
243
244 /**
245 * Main function generating the BE scaffolding
246 */
247 protected function render()
248 {
249 $this->executeHook('renderPreProcess');
250
251 // Prepare the scaffolding, at this point extension may still add javascript and css
252 $view = $this->getFluidTemplateObject($this->templatePath . 'Backend/Main.html');
253
254 $view->assign('moduleMenu', $this->generateModuleMenu());
255 $view->assign('topbar', $this->renderTopbar());
256
257 /******************************************************
258 * Now put the complete backend document together
259 ******************************************************/
260 foreach ($this->cssFiles as $cssFileName => $cssFile) {
261 $this->pageRenderer->addCssFile($cssFile);
262 // Load additional css files to overwrite existing core styles
263 if (!empty($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName])) {
264 $this->pageRenderer->addCssFile($GLOBALS['TBE_STYLES']['stylesheets'][$cssFileName]);
265 }
266 }
267 if (!empty($this->css)) {
268 $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
269 }
270 foreach ($this->jsFiles as $jsFile) {
271 $this->pageRenderer->addJsFile($jsFile);
272 }
273 $this->generateJavascript();
274 $this->pageRenderer->addJsInlineCode('BackendInlineJavascript', $this->js, false);
275
276 // Set document title:
277 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [TYPO3 CMS ' . TYPO3_version . ']' : 'TYPO3 CMS ' . TYPO3_version;
278 // Renders the module page
279 $this->content = $this->getDocumentTemplate()->render($title, $view->render());
280 $hookConfiguration = ['content' => &$this->content];
281 $this->executeHook('renderPostProcess', $hookConfiguration);
282 }
283
284 /**
285 * Renders the topbar, containing the backend logo, sitename etc.
286 *
287 * @return string
288 */
289 protected function renderTopbar()
290 {
291 $view = $this->getFluidTemplateObject($this->partialPath . 'Backend/Topbar.html');
292
293 // Extension Configuration to find the TYPO3 logo in the left corner
294 $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('backend');
295 $logoPath = '';
296 if (!empty($extConf['backendLogo'])) {
297 $customBackendLogo = GeneralUtility::getFileAbsFileName($extConf['backendLogo']);
298 if (!empty($customBackendLogo)) {
299 $logoPath = $customBackendLogo;
300 }
301 }
302 // if no custom logo was set or the path is invalid, use the original one
303 if (empty($logoPath) || !file_exists($logoPath)) {
304 $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg');
305 $logoWidth = 22;
306 $logoHeight = 22;
307 } else {
308 // set width/height for custom logo
309 $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $logoPath);
310 $logoWidth = $imageInfo->getWidth() ?? '22';
311 $logoHeight = $imageInfo->getHeight() ?? '22';
312
313 // High-resolution?
314 if (strpos($logoPath, '@2x.') !== false) {
315 $logoWidth /= 2;
316 $logoHeight /= 2;
317 }
318 }
319
320 $view->assign('logoUrl', PathUtility::getAbsoluteWebPath($logoPath));
321 $view->assign('logoWidth', $logoWidth);
322 $view->assign('logoHeight', $logoHeight);
323 $view->assign('applicationVersion', TYPO3_version);
324 $view->assign('siteName', $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
325 $view->assign('toolbar', $this->renderToolbar());
326
327 return $view->render();
328 }
329
330 /**
331 * Renders the items in the top toolbar
332 *
333 * @return string top toolbar elements as HTML
334 */
335 protected function renderToolbar()
336 {
337 $toolbar = [];
338 foreach ($this->toolbarItems as $toolbarItem) {
339 /** @var \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface $toolbarItem */
340 if ($toolbarItem->checkAccess()) {
341 $hasDropDown = (bool)$toolbarItem->hasDropDown();
342 $additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
343
344 $liAttributes = [];
345
346 // Merge class: Add dropdown class if hasDropDown, add classes from additional attributes
347 $classes = [];
348 $classes[] = 'toolbar-item';
349 $classes[] = 't3js-toolbar-item';
350 if (isset($additionalAttributes['class'])) {
351 $classes[] = $additionalAttributes['class'];
352 unset($additionalAttributes['class']);
353 }
354 $liAttributes['class'] = implode(' ', $classes);
355
356 // Add further attributes
357 foreach ($additionalAttributes as $name => $value) {
358 $liAttributes[$name] = $value;
359 }
360
361 // Create a unique id from class name
362 $fullyQualifiedClassName = \get_class($toolbarItem);
363 $className = GeneralUtility::underscoredToLowerCamelCase($fullyQualifiedClassName);
364 $className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
365 $className = str_replace(['_', '\\'], '-', $className);
366 $liAttributes['id'] = $className;
367
368 // Create data attribute identifier
369 $shortName = substr($fullyQualifiedClassName, strrpos($fullyQualifiedClassName, '\\') + 1);
370 $dataToolbarIdentifier = GeneralUtility::camelCaseToLowerCaseUnderscored($shortName);
371 $dataToolbarIdentifier = str_replace('_', '-', $dataToolbarIdentifier);
372 $liAttributes['data-toolbar-identifier'] = $dataToolbarIdentifier;
373
374 $toolbar[] = '<li ' . GeneralUtility::implodeAttributes($liAttributes, true) . '>';
375
376 if ($hasDropDown) {
377 $toolbar[] = '<a href="#" class="toolbar-item-link dropdown-toggle" data-toggle="dropdown">';
378 $toolbar[] = $toolbarItem->getItem();
379 $toolbar[] = '</a>';
380 $toolbar[] = '<div class="dropdown-menu" role="menu">';
381 $toolbar[] = $toolbarItem->getDropDown();
382 $toolbar[] = '</div>';
383 } else {
384 $toolbar[] = $toolbarItem->getItem();
385 }
386 $toolbar[] = '</li>';
387 }
388 }
389 return implode(LF, $toolbar);
390 }
391
392 /**
393 * Generates the JavaScript code for the backend.
394 */
395 protected function generateJavascript()
396 {
397 $beUser = $this->getBackendUser();
398 // Needed for FormEngine manipulation (date picker)
399 $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? ['MM-DD-YYYY', 'HH:mm MM-DD-YYYY'] : ['DD-MM-YYYY', 'HH:mm DD-MM-YYYY']);
400 $this->pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
401
402 // If another page module was specified, replace the default Page module with the new one
403 $newPageModule = trim($beUser->getTSConfig()['options.']['overridePageModule'] ?? '');
404 $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
405 if (!$beUser->check('modules', $pageModule)) {
406 $pageModule = '';
407 }
408 $t3Configuration = [
409 'username' => htmlspecialchars($beUser->user['username']),
410 'pageModule' => $pageModule,
411 'inWorkspace' => $beUser->workspace !== 0,
412 'showRefreshLoginPopup' => (bool)($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] ?? false)
413 ];
414 $this->js .= '
415 TYPO3.configuration = ' . json_encode($t3Configuration) . ';
416 /**
417 * Frameset Module object
418 *
419 * Used in main modules with a frameset for submodules to keep the ID between modules
420 * Typically that is set by something like this in a Web>* sub module:
421 * if (top.fsMod) top.fsMod.recentIds["web"] = "\'.(int)$this->id.\'";
422 * if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
423 */
424 var fsMod = {
425 recentIds: [], // used by frameset modules to track the most recent used id for list frame.
426 navFrameHighlightedID: [], // used by navigation frames to track which row id was highlighted last time
427 currentBank: "0"
428 };
429
430 top.goToModule = function(modName, cMR_flag, addGetVars) {
431 TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
432 }
433 ' . $this->setStartupModule();
434 // Check editing of page:
435 $this->handlePageEditing();
436 }
437
438 /**
439 * Checking if the "&edit" variable was sent so we can open it for editing the page.
440 */
441 protected function handlePageEditing()
442 {
443 $beUser = $this->getBackendUser();
444 $userTsConfig = $this->getBackendUser()->getTSConfig();
445 // EDIT page:
446 $editId = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('edit'));
447 if ($editId) {
448 // Looking up the page to edit, checking permissions:
449 $where = ' AND (' . $beUser->getPagePermsClause(Permission::PAGE_EDIT) . ' OR ' . $beUser->getPagePermsClause(Permission::CONTENT_EDIT) . ')';
450 if (MathUtility::canBeInterpretedAsInteger($editId)) {
451 $editRecord = BackendUtility::getRecordWSOL('pages', $editId, '*', $where);
452 } else {
453 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
454 $queryBuilder->getRestrictions()
455 ->removeAll()
456 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
457 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
458
459 $editRecord = $queryBuilder->select('*')
460 ->from('pages')
461 ->where(
462 $queryBuilder->expr()->eq(
463 'alias',
464 $queryBuilder->createNamedParameter($editId, \PDO::PARAM_STR)
465 ),
466 $queryBuilder->expr()->orX(
467 $beUser->getPagePermsClause(Permission::PAGE_EDIT),
468 $beUser->getPagePermsClause(Permission::CONTENT_EDIT)
469 )
470 )
471 ->setMaxResults(1)
472 ->execute()
473 ->fetch();
474
475 if ($editRecord !== false) {
476 BackendUtility::workspaceOL('pages', $editRecord);
477 }
478 }
479 // If the page was accessible, then let the user edit it.
480 if (is_array($editRecord) && $beUser->isInWebMount($editRecord['uid'])) {
481 // Setting JS code to open editing:
482 $this->js .= '
483 // Load page to edit:
484 window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
485 ';
486 // Checking page edit parameter:
487 if (!($userTsConfig['options.']['bookmark_onEditId_dontSetPageTree'] ?? false)) {
488 $bookmarkKeepExpanded = (bool)($userTsConfig['options.']['bookmark_onEditId_keepExistingExpanded'] ?? false);
489 // Expanding page tree:
490 BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
491 }
492 } else {
493 $this->js .= '
494 // Warning about page editing:
495 require(["TYPO3/CMS/Backend/Modal", "TYPO3/CMS/Backend/Severity"], function(Modal, Severity) {
496 Modal.show("", ' . GeneralUtility::quoteJSvalue(sprintf($this->getLanguageService()->getLL('noEditPage'), $editId)) . ', Severity.notice, [{
497 text: ' . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:close')) . ',
498 active: true,
499 btnClass: "btn-info",
500 name: "cancel",
501 trigger: function () {
502 Modal.currentModal.trigger("modal-dismiss");
503 }
504 }])
505 });';
506 }
507 }
508 }
509
510 /**
511 * Sets the startup module from either GETvars module and modParams or user configuration.
512 *
513 * @return string the JavaScript code for the startup module
514 */
515 protected function setStartupModule()
516 {
517 $startModule = preg_replace('/[^[:alnum:]_]/', '', GeneralUtility::_GET('module'));
518 $startModuleParameters = '';
519 if (!$startModule) {
520 $beUser = $this->getBackendUser();
521 // start module on first login, will be removed once used the first time
522 if (isset($beUser->uc['startModuleOnFirstLogin'])) {
523 $startModule = $beUser->uc['startModuleOnFirstLogin'];
524 unset($beUser->uc['startModuleOnFirstLogin']);
525 $beUser->writeUC();
526 } elseif ($beUser->uc['startModule']) {
527 $startModule = $beUser->uc['startModule'];
528 }
529
530 // check if the start module has additional parameters, so a redirect to a specific
531 // action is possible
532 if (strpos($startModule, '->') !== false) {
533 list($startModule, $startModuleParameters) = explode('->', $startModule, 2);
534 }
535 }
536
537 $moduleParameters = GeneralUtility::_GET('modParams');
538 // if no GET parameters are set, check if there are parameters given from the UC
539 if (!$moduleParameters && $startModuleParameters) {
540 $moduleParameters = $startModuleParameters;
541 }
542
543 if ($startModule) {
544 return '
545 // start in module:
546 top.startInModule = [' . GeneralUtility::quoteJSvalue($startModule) . ', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
547 ';
548 }
549 return '';
550 }
551
552 /**
553 * Adds a css snippet to the backend
554 *
555 * @param string $css Css snippet
556 * @throws \InvalidArgumentException
557 */
558 public function addCss($css)
559 {
560 if (!is_string($css)) {
561 throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
562 }
563 $this->css .= $css;
564 }
565
566 /**
567 * Executes defined hooks functions for the given identifier.
568 *
569 * These hook identifiers are valid:
570 * + constructPostProcess
571 * + renderPreProcess
572 * + renderPostProcess
573 *
574 * @param string $identifier Specific hook identifier
575 * @param array $hookConfiguration Additional configuration passed to hook functions
576 */
577 protected function executeHook($identifier, array $hookConfiguration = [])
578 {
579 $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
580 foreach ($options[$identifier] ?? [] as $hookFunction) {
581 GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
582 }
583 }
584
585 /**
586 * loads all modules from the repository
587 * and renders it with a template
588 *
589 * @return string
590 */
591 protected function generateModuleMenu()
592 {
593 // get all modules except the user modules for the side menu
594 $moduleStorage = $this->backendModuleRepository->loadAllowedModules(['user', 'help']);
595
596 $view = $this->getFluidTemplateObject($this->templatePath . 'ModuleMenu/Main.html');
597 $view->assign('modules', $moduleStorage);
598 return $view->render();
599 }
600
601 /**
602 * Returns the Module menu for the AJAX request
603 *
604 * @return ResponseInterface
605 */
606 public function getModuleMenu(): ResponseInterface
607 {
608 return new JsonResponse(['menu' => $this->generateModuleMenu()]);
609 }
610
611 /**
612 * Returns the toolbar for the AJAX request
613 *
614 * @return ResponseInterface
615 */
616 public function getTopbar(): ResponseInterface
617 {
618 return new JsonResponse(['topbar' => $this->renderTopbar()]);
619 }
620
621 /**
622 * returns a new standalone view, shorthand function
623 *
624 * @param string $templatePathAndFileName optional the path to set the template path and filename
625 * @return \TYPO3\CMS\Fluid\View\StandaloneView
626 */
627 protected function getFluidTemplateObject($templatePathAndFileName = null)
628 {
629 $view = GeneralUtility::makeInstance(StandaloneView::class);
630 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
631 if ($templatePathAndFileName) {
632 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
633 }
634 return $view;
635 }
636
637 /**
638 * Returns LanguageService
639 *
640 * @return \TYPO3\CMS\Core\Localization\LanguageService
641 */
642 protected function getLanguageService()
643 {
644 return $GLOBALS['LANG'];
645 }
646
647 /**
648 * Returns the current BE user.
649 *
650 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
651 */
652 protected function getBackendUser()
653 {
654 return $GLOBALS['BE_USER'];
655 }
656
657 /**
658 * Returns an instance of DocumentTemplate
659 *
660 * @return \TYPO3\CMS\Backend\Template\DocumentTemplate
661 */
662 protected function getDocumentTemplate()
663 {
664 return $GLOBALS['TBE_TEMPLATE'];
665 }
666 }