Passed
Push — master ( 9bcb07...158d32 )
by
unknown
13:11
created

BackendController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 55
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 40
nc 1
nop 0
dl 0
loc 55
rs 9.28
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Backend\Controller;
17
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
21
use TYPO3\CMS\Backend\Module\ModuleLoader;
22
use TYPO3\CMS\Backend\Routing\UriBuilder;
23
use TYPO3\CMS\Backend\Template\ModuleTemplate;
24
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
25
use TYPO3\CMS\Backend\Utility\BackendUtility;
26
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
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\Information\Typo3Version;
32
use TYPO3\CMS\Core\Localization\LanguageService;
33
use TYPO3\CMS\Core\Page\PageRenderer;
34
use TYPO3\CMS\Core\Type\Bitmask\Permission;
35
use TYPO3\CMS\Core\Type\File\ImageInfo;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Core\Utility\MathUtility;
38
use TYPO3\CMS\Core\Utility\PathUtility;
39
use TYPO3\CMS\Fluid\View\StandaloneView;
40
41
/**
42
 * Class for rendering the TYPO3 backend
43
 */
44
class BackendController
45
{
46
    /**
47
     * @var string
48
     */
49
    protected $css = '';
50
51
    /**
52
     * @var array
53
     */
54
    protected $toolbarItems = [];
55
56
    /**
57
     * @var string
58
     */
59
    protected $templatePath = 'EXT:backend/Resources/Private/Templates/';
60
61
    /**
62
     * @var string
63
     */
64
    protected $partialPath = 'EXT:backend/Resources/Private/Partials/';
65
66
    /**
67
     * @var BackendModuleRepository
68
     */
69
    protected $backendModuleRepository;
70
71
    /**
72
     * @var PageRenderer
73
     */
74
    protected $pageRenderer;
75
76
    /**
77
     * @var IconFactory
78
     */
79
    protected $iconFactory;
80
81
    /**
82
     * @var Typo3Version
83
     */
84
    protected $typo3Version;
85
86
    /**
87
     * @var UriBuilder
88
     */
89
    protected $uriBuilder;
90
91
    /**
92
     * @var \SplObjectStorage
93
     */
94
    protected $moduleStorage;
95
96
    /**
97
     * @var ModuleLoader
98
     */
99
    protected $moduleLoader;
100
101
    /**
102
     * Constructor
103
     */
104
    public function __construct()
105
    {
106
        $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
107
        $this->backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
108
        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
109
        $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
110
        $this->typo3Version = GeneralUtility::makeInstance(Typo3Version::class);
111
        $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
112
        $this->moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
113
        $this->moduleLoader->observeWorkspaces = true;
114
        $this->moduleLoader->load($GLOBALS['TBE_MODULES']);
115
116
        // Add default BE javascript
117
        $this->pageRenderer->addJsFile('EXT:backend/Resources/Public/JavaScript/backend.js');
118
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LoginRefresh', 'function(LoginRefresh) {
119
			LoginRefresh.setIntervalTime(' . MathUtility::forceIntegerInRange((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['sessionTimeout'] - 60, 60) . ');
120
			LoginRefresh.setLoginFramesetUrl(' . GeneralUtility::quoteJSvalue((string)$this->uriBuilder->buildUriFromRoute('login_frameset')) . ');
121
			LoginRefresh.setLogoutUrl(' . GeneralUtility::quoteJSvalue((string)$this->uriBuilder->buildUriFromRoute('logout')) . ');
122
			LoginRefresh.initialize();
123
		}');
124
125
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/BroadcastService', 'function(service) { service.listen(); }');
126
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ModuleMenu');
127
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar');
128
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Notification');
129
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
130
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/InfoWindow');
131
132
        // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed
133
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Storage/Persistent', 'function(PersistentStorage) {
134
            PersistentStorage.load(' . json_encode($this->getBackendUser()->uc) . ');
135
        }');
136
137
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DebugConsole');
138
139
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf');
140
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_misc.xlf');
141
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
142
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf');
143
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/debugger.xlf');
144
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/wizard.xlf');
145
146
        $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('help_cshmanual'));
147
        $this->pageRenderer->addInlineSetting('ShowItem', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('show_item'));
148
        $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('record_history'));
149
        $this->pageRenderer->addInlineSetting('NewRecord', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('db_new'));
150
        $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('record_edit'));
151
        $this->pageRenderer->addInlineSetting('RecordCommit', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('tce_db'));
152
        $this->pageRenderer->addInlineSetting('FileCommit', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('tce_file'));
153
        $this->pageRenderer->addInlineSetting('WebLayout', 'moduleUrl', (string)$this->uriBuilder->buildUriFromRoute('web_layout'));
154
155
        $this->initializeToolbarItems();
156
        $this->executeHook('constructPostProcess');
157
158
        $this->moduleStorage = $this->backendModuleRepository->loadAllowedModules(['user', 'help']);
159
    }
160
161
    /**
162
     * Initialize toolbar item objects
163
     *
164
     * @throws \RuntimeException
165
     */
166
    protected function initializeToolbarItems()
167
    {
168
        $toolbarItemInstances = [];
169
        foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] ?? [] as $className) {
170
            $toolbarItemInstance = GeneralUtility::makeInstance($className);
171
            if (!$toolbarItemInstance instanceof ToolbarItemInterface) {
172
                throw new \RuntimeException(
173
                    'class ' . $className . ' is registered as toolbar item but does not implement'
174
                        . ToolbarItemInterface::class,
175
                    1415958218
176
                );
177
            }
178
            $index = (int)$toolbarItemInstance->getIndex();
179
            if ($index < 0 || $index > 100) {
180
                throw new \RuntimeException(
181
                    'getIndex() must return an integer between 0 and 100',
182
                    1415968498
183
                );
184
            }
185
            // Find next free position in array
186
            while (array_key_exists($index, $toolbarItemInstances)) {
187
                $index++;
188
            }
189
            $toolbarItemInstances[$index] = $toolbarItemInstance;
190
        }
191
        ksort($toolbarItemInstances);
192
        $this->toolbarItems = $toolbarItemInstances;
193
    }
194
195
    /**
196
     * Main function generating the BE scaffolding
197
     *
198
     * @param ServerRequestInterface $request
199
     * @return ResponseInterface the response with the content
200
     */
201
    public function mainAction(ServerRequestInterface $request): ResponseInterface
202
    {
203
        $this->executeHook('renderPreProcess');
204
205
        $moduleMenuCollapsed = $this->getCollapseStateOfMenu();
206
        $hasModules = count($this->moduleStorage) > 0;
207
        $bodyTag = '<body class="scaffold t3js-scaffold' . (!$moduleMenuCollapsed && $hasModules ? ' scaffold-modulemenu-expanded' : '') . '">';
208
209
        // Prepare the scaffolding, at this point extension may still add javascript and css
210
        $moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
211
        $view = $moduleTemplate->getView();
212
        $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
213
        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePath . 'Backend/Main.html'));
214
        $moduleTemplate->setBodyTag($bodyTag);
215
        $view->assign('moduleMenu', $this->generateModuleMenu());
216
        $view->assign('topbar', $this->renderTopbar());
217
        $view->assign('hasModules', $hasModules);
218
219
        if (!empty($this->css)) {
220
            $this->pageRenderer->addCssInlineBlock('BackendInlineCSS', $this->css);
221
        }
222
        $this->generateJavascript($request);
223
224
        // Set document title
225
        $typo3Version = 'TYPO3 CMS ' . $this->typo3Version->getVersion();
226
        $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ' [' . $typo3Version . ']' : $typo3Version;
227
        $moduleTemplate->setTitle($title);
228
229
        // Renders the backend scaffolding
230
        $content = $moduleTemplate->renderContent();
231
        $this->executeHook('renderPostProcess', ['content' => &$content]);
232
        return new HtmlResponse($content);
233
    }
234
235
    /**
236
     * Renders the topbar, containing the backend logo, sitename etc.
237
     *
238
     * @return string
239
     */
240
    protected function renderTopbar()
241
    {
242
        $view = $this->getFluidTemplateObject($this->partialPath . 'Backend/Topbar.html');
243
244
        // Extension Configuration to find the TYPO3 logo in the left corner
245
        $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('backend');
246
        $logoPath = '';
247
        if (!empty($extConf['backendLogo'])) {
248
            $customBackendLogo = GeneralUtility::getFileAbsFileName(ltrim($extConf['backendLogo'], '/'));
249
            if (!empty($customBackendLogo)) {
250
                $logoPath = $customBackendLogo;
251
            }
252
        }
253
        // if no custom logo was set or the path is invalid, use the original one
254
        if (empty($logoPath) || !file_exists($logoPath)) {
255
            $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg');
256
            $logoWidth = 22;
257
            $logoHeight = 22;
258
        } else {
259
            // set width/height for custom logo
260
            $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $logoPath);
261
            $logoWidth = $imageInfo->getWidth() ?? '22';
262
            $logoHeight = $imageInfo->getHeight() ?? '22';
263
264
            // High-resolution?
265
            if (strpos($logoPath, '@2x.') !== false) {
266
                $logoWidth /= 2;
267
                $logoHeight /= 2;
268
            }
269
        }
270
271
        $view->assign('hasModules', count($this->moduleStorage) > 0);
272
        $view->assign('modulesHaveNavigationComponent', $this->backendModuleRepository->modulesHaveNavigationComponent());
273
        $view->assign('logoUrl', PathUtility::getAbsoluteWebPath($logoPath));
274
        $view->assign('logoWidth', $logoWidth);
275
        $view->assign('logoHeight', $logoHeight);
276
        $view->assign('applicationVersion', $this->typo3Version->getVersion());
277
        $view->assign('siteName', $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
278
        $view->assign('toolbar', $this->renderToolbar());
279
280
        return $view->render();
281
    }
282
283
    /**
284
     * Renders the items in the top toolbar
285
     *
286
     * @return string top toolbar elements as HTML
287
     */
288
    protected function renderToolbar()
289
    {
290
        $toolbar = [];
291
        foreach ($this->toolbarItems as $toolbarItem) {
292
            /** @var ToolbarItemInterface $toolbarItem */
293
            if ($toolbarItem->checkAccess()) {
294
                $hasDropDown = (bool)$toolbarItem->hasDropDown();
295
                $additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
296
297
                $liAttributes = [];
298
299
                // Merge class: Add dropdown class if hasDropDown, add classes from additional attributes
300
                $classes = [];
301
                $classes[] = 'toolbar-item';
302
                $classes[] = 't3js-toolbar-item';
303
                if (isset($additionalAttributes['class'])) {
304
                    $classes[] = $additionalAttributes['class'];
305
                    unset($additionalAttributes['class']);
306
                }
307
                $liAttributes['class'] = implode(' ', $classes);
308
309
                // Add further attributes
310
                foreach ($additionalAttributes as $name => $value) {
311
                    $liAttributes[(string)$name] = (string)$value;
312
                }
313
314
                // Create a unique id from class name
315
                $fullyQualifiedClassName = \get_class($toolbarItem);
316
                $className = GeneralUtility::underscoredToLowerCamelCase($fullyQualifiedClassName);
317
                $className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
318
                $className = str_replace(['_', '\\'], '-', $className);
319
                $liAttributes['id'] = $className;
320
321
                // Create data attribute identifier
322
                $shortName = substr($fullyQualifiedClassName, (int)strrpos($fullyQualifiedClassName, '\\') + 1);
323
                $dataToolbarIdentifier = GeneralUtility::camelCaseToLowerCaseUnderscored($shortName);
324
                $dataToolbarIdentifier = str_replace('_', '-', $dataToolbarIdentifier);
325
                $liAttributes['data-toolbar-identifier'] = $dataToolbarIdentifier;
326
327
                $toolbar[] = '<li ' . GeneralUtility::implodeAttributes($liAttributes, true) . '>';
328
329
                if ($hasDropDown) {
330
                    $toolbar[] = '<a href="#" class="toolbar-item-link dropdown-toggle" data-bs-toggle="dropdown">';
331
                    $toolbar[] = $toolbarItem->getItem();
332
                    $toolbar[] = '</a>';
333
                    $toolbar[] = '<div class="dropdown-menu" role="menu">';
334
                    $toolbar[] = $toolbarItem->getDropDown();
335
                    $toolbar[] = '</div>';
336
                } else {
337
                    $toolbar[] = $toolbarItem->getItem();
338
                }
339
                $toolbar[] = '</li>';
340
            }
341
        }
342
        return implode(LF, $toolbar);
343
    }
344
345
    /**
346
     * Generates the JavaScript code for the backend.
347
     *
348
     * @param ServerRequestInterface $request
349
     */
350
    protected function generateJavascript(ServerRequestInterface $request)
351
    {
352
        $beUser = $this->getBackendUser();
353
        // Needed for FormEngine manipulation (date picker)
354
        $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? ['MM-DD-Y', 'HH:mm MM-DD-Y'] : ['DD-MM-Y', 'HH:mm DD-MM-Y']);
355
        $this->pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
356
357
        // If another page module was specified, replace the default Page module with the new one
358
        $newPageModule = trim($beUser->getTSConfig()['options.']['overridePageModule'] ?? '');
359
        $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
360
        $pageModuleUrl = '';
361
        if (!$beUser->check('modules', $pageModule)) {
362
            $pageModule = '';
363
        } else {
364
            $pageModuleUrl = (string)$this->uriBuilder->buildUriFromRoute($pageModule);
365
        }
366
        $t3Configuration = [
367
            'username' => htmlspecialchars($beUser->user['username']),
368
            'pageModule' => $pageModule,
369
            'pageModuleUrl' => $pageModuleUrl,
370
            'inWorkspace' => $beUser->workspace !== 0,
371
            'showRefreshLoginPopup' => (bool)($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] ?? false)
372
        ];
373
374
        $this->pageRenderer->addJsInlineCode(
375
            'BackendConfiguration',
376
            '
377
        TYPO3.configuration = ' . json_encode($t3Configuration) . ';
378
        /**
379
         * Frameset Module object
380
         *
381
         * Used in main modules with a frameset for submodules to keep the ID between modules
382
         * Typically that is set by something like this in a Web>* sub module:
383
         *		if (top.fsMod) top.fsMod.recentIds["web"] = "\'.(int)$this->id.\'";
384
         * 		if (top.fsMod) top.fsMod.recentIds["file"] = "...(file reference/string)...";
385
         */
386
        var fsMod = {
387
            recentIds: [],					// used by frameset modules to track the most recent used id for list frame.
388
            navFrameHighlightedID: [],		// used by navigation frames to track which row id was highlighted last time
389
            currentBank: "0"
390
        };
391
392
        top.goToModule = function(modName, addGetVars) {
393
            TYPO3.ModuleMenu.App.showModule(modName, addGetVars);
394
        }
395
        ' . $this->setStartupModule($request)
396
          . $this->handlePageEditing($request),
397
            false
398
        );
399
    }
400
401
    /**
402
     * Checking if the "&edit" variable was sent so we can open it for editing the page.
403
     */
404
    protected function handlePageEditing(ServerRequestInterface $request): string
405
    {
406
        $beUser = $this->getBackendUser();
407
        $userTsConfig = $this->getBackendUser()->getTSConfig();
408
        // EDIT page
409
        $editId = preg_replace('/[^[:alnum:]_]/', '', $request->getQueryParams()['edit'] ?? '') ?? '';
410
        if ($editId) {
411
            // Looking up the page to edit, checking permissions:
412
            $where = ' AND (' . $beUser->getPagePermsClause(Permission::PAGE_EDIT) . ' OR ' . $beUser->getPagePermsClause(Permission::CONTENT_EDIT) . ')';
413
            $editRecord = null;
414
            if (MathUtility::canBeInterpretedAsInteger($editId)) {
415
                $editRecord = BackendUtility::getRecordWSOL('pages', (int)$editId, '*', $where);
416
            }
417
            // If the page was accessible, then let the user edit it.
418
            if (is_array($editRecord) && $beUser->isInWebMount($editRecord)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $beUser->isInWebMount($editRecord) of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
419
                // Checking page edit parameter:
420
                if (!($userTsConfig['options.']['bookmark_onEditId_dontSetPageTree'] ?? false)) {
421
                    $bookmarkKeepExpanded = (bool)($userTsConfig['options.']['bookmark_onEditId_keepExistingExpanded'] ?? false);
422
                    // Expanding page tree:
423
                    BackendUtility::openPageTree((int)$editRecord['pid'], !$bookmarkKeepExpanded);
424
                }
425
                // Setting JS code to open editing:
426
                return '
427
		// Load page to edit:
428
	window.setTimeout("top.loadEditId(' . (int)$editRecord['uid'] . ');", 500);
429
			';
430
            }
431
            return '
432
            // Warning about page editing:
433
            require(["TYPO3/CMS/Backend/Modal", "TYPO3/CMS/Backend/Severity"], function(Modal, Severity) {
434
                Modal.show("", ' . GeneralUtility::quoteJSvalue(sprintf($this->getLanguageService()->getLL('noEditPage'), (string)$editId)) . ', Severity.notice, [{
435
                    text: ' . GeneralUtility::quoteJSvalue($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:close')) . ',
436
                    active: true,
437
                    btnClass: "btn-info",
438
                    name: "cancel",
439
                    trigger: function () {
440
                        Modal.currentModal.trigger("modal-dismiss");
441
                    }
442
                }])
443
            });';
444
        }
445
        return '';
446
    }
447
448
    /**
449
     * Sets the startup module from either GETvars module and modParams or user configuration.
450
     *
451
     * @param ServerRequestInterface $request
452
     * @return string the JavaScript code for the startup module
453
     */
454
    protected function setStartupModule(ServerRequestInterface $request)
455
    {
456
        $startModule = preg_replace('/[^[:alnum:]_]/', '', $request->getQueryParams()['module'] ?? '');
457
        $startModuleParameters = '';
458
        if (!$startModule) {
459
            $beUser = $this->getBackendUser();
460
            // start module on first login, will be removed once used the first time
461
            if (isset($beUser->uc['startModuleOnFirstLogin'])) {
462
                $startModule = $beUser->uc['startModuleOnFirstLogin'];
463
                unset($beUser->uc['startModuleOnFirstLogin']);
464
                $beUser->writeUC();
465
            } elseif ($this->moduleLoader->checkMod($beUser->uc['startModule']) !== 'notFound') {
466
                $startModule = $beUser->uc['startModule'];
467
            } else {
468
                $startModule = $this->determineFirstAvailableBackendModule();
469
            }
470
471
            // check if the start module has additional parameters, so a redirect to a specific
472
            // action is possible
473
            if (strpos($startModule, '->') !== false) {
474
                [$startModule, $startModuleParameters] = explode('->', $startModule, 2);
475
            }
476
        }
477
478
        $moduleParameters = $request->getQueryParams()['modParams'] ?? '';
479
        // if no GET parameters are set, check if there are parameters given from the UC
480
        if (!$moduleParameters && $startModuleParameters) {
481
            $moduleParameters = $startModuleParameters;
482
        }
483
484
        if ($startModule) {
485
            return '
486
					// start in module:
487
				top.startInModule = [' . GeneralUtility::quoteJSvalue($startModule) . ', ' . GeneralUtility::quoteJSvalue($moduleParameters) . '];
488
			';
489
        }
490
        return '';
491
    }
492
493
    protected function determineFirstAvailableBackendModule(): string
494
    {
495
        foreach ($this->moduleLoader->modules as $mainMod => $modData) {
496
            $hasSubmodules = !empty($modData['sub']) && is_array($modData['sub']);
497
            $isStandalone = $modData['standalone'] ?? false;
498
            if ($isStandalone) {
499
                return $modData['name'];
500
            }
501
502
            if ($hasSubmodules) {
503
                $firstSubmodule = reset($modData['sub']);
504
                return $firstSubmodule['name'];
505
            }
506
        }
507
508
        return '';
509
    }
510
511
    /**
512
     * Adds a css snippet to the backend
513
     *
514
     * @param string $css Css snippet
515
     * @throws \InvalidArgumentException
516
     */
517
    public function addCss($css)
518
    {
519
        if (!is_string($css)) {
0 ignored issues
show
introduced by
The condition is_string($css) is always true.
Loading history...
520
            throw new \InvalidArgumentException('parameter $css must be of type string', 1195129642);
521
        }
522
        $this->css .= $css;
523
    }
524
525
    /**
526
     * Executes defined hooks functions for the given identifier.
527
     *
528
     * These hook identifiers are valid:
529
     * + constructPostProcess
530
     * + renderPreProcess
531
     * + renderPostProcess
532
     *
533
     * @param string $identifier Specific hook identifier
534
     * @param array $hookConfiguration Additional configuration passed to hook functions
535
     */
536
    protected function executeHook($identifier, array $hookConfiguration = [])
537
    {
538
        $options = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php'];
539
        foreach ($options[$identifier] ?? [] as $hookFunction) {
540
            GeneralUtility::callUserFunction($hookFunction, $hookConfiguration, $this);
541
        }
542
    }
543
544
    /**
545
     * loads all modules from the repository
546
     * and renders it with a template
547
     *
548
     * @return string
549
     */
550
    protected function generateModuleMenu()
551
    {
552
        $view = $this->getFluidTemplateObject($this->templatePath . 'ModuleMenu/Main.html');
553
        $view->assign('modules', $this->moduleStorage);
554
        return $view->render();
555
    }
556
557
    protected function getCollapseStateOfMenu(): bool
558
    {
559
        $uc = json_decode((string)json_encode($this->getBackendUser()->uc), true);
560
        $collapseState = $uc['BackendComponents']['States']['typo3-module-menu']['collapsed'] ?? false;
561
562
        return $collapseState === true || $collapseState === 'true';
563
    }
564
565
    /**
566
     * Returns the Module menu for the AJAX request
567
     *
568
     * @return ResponseInterface
569
     */
570
    public function getModuleMenu(): ResponseInterface
571
    {
572
        return new JsonResponse(['menu' => $this->generateModuleMenu()]);
573
    }
574
575
    /**
576
     * Returns the toolbar for the AJAX request
577
     *
578
     * @return ResponseInterface
579
     */
580
    public function getTopbar(): ResponseInterface
581
    {
582
        return new JsonResponse(['topbar' => $this->renderTopbar()]);
583
    }
584
585
    /**
586
     * returns a new standalone view, shorthand function
587
     *
588
     * @param string $templatePathAndFileName optional the path to set the template path and filename
589
     * @return \TYPO3\CMS\Fluid\View\StandaloneView
590
     */
591
    protected function getFluidTemplateObject($templatePathAndFileName = null)
592
    {
593
        $view = GeneralUtility::makeInstance(StandaloneView::class);
594
        $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
595
        if ($templatePathAndFileName) {
596
            $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
597
        }
598
        return $view;
599
    }
600
601
    /**
602
     * Returns LanguageService
603
     *
604
     * @return LanguageService
605
     */
606
    protected function getLanguageService()
607
    {
608
        return $GLOBALS['LANG'];
609
    }
610
611
    /**
612
     * Returns the current BE user.
613
     *
614
     * @return BackendUserAuthentication
615
     */
616
    protected function getBackendUser()
617
    {
618
        return $GLOBALS['BE_USER'];
619
    }
620
}
621