Passed
Push — master ( ff1a76...9dbd27 )
by
unknown
13:17
created

getBackendUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\Tstemplate\Controller;
17
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use TYPO3\CMS\Backend\Routing\PreviewUriBuilder;
21
use TYPO3\CMS\Backend\Routing\UriBuilder;
22
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
23
use TYPO3\CMS\Backend\Template\ModuleTemplate;
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
use TYPO3\CMS\Core\Database\ConnectionPool;
27
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
28
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
29
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
30
use TYPO3\CMS\Core\DataHandling\DataHandler;
31
use TYPO3\CMS\Core\Http\HtmlResponse;
32
use TYPO3\CMS\Core\Imaging\Icon;
33
use TYPO3\CMS\Core\Localization\LanguageService;
34
use TYPO3\CMS\Core\Messaging\FlashMessage;
35
use TYPO3\CMS\Core\Messaging\FlashMessageService;
36
use TYPO3\CMS\Core\Page\PageRenderer;
37
use TYPO3\CMS\Core\Type\Bitmask\Permission;
38
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
39
use TYPO3\CMS\Core\Utility\GeneralUtility;
40
use TYPO3\CMS\Core\Versioning\VersionState;
41
use TYPO3\CMS\Fluid\View\StandaloneView;
42
use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
43
44
/**
45
 * Module: TypoScript Tools
46
 * @internal This is a specific Backend Controller implementation and is not considered part of the Public TYPO3 API.
47
 */
48
class TypoScriptTemplateModuleController
49
{
50
51
    /**
52
     * @var string
53
     */
54
    protected $perms_clause;
55
56
    /**
57
     * @var string
58
     */
59
    public $modMenu_dontValidateList = '';
60
61
    /**
62
     * @var string Written by client classes
63
     */
64
    public $modMenu_setDefaultList = '';
65
66
    /**
67
     * @var array
68
     */
69
    protected $pageinfo = [];
70
71
    /**
72
     * @var bool
73
     */
74
    protected $access = false;
75
76
    /**
77
     * The name of the module
78
     *
79
     * @var string
80
     */
81
    protected $moduleName = 'web_ts';
82
83
    /**
84
     * ModuleTemplate Container
85
     *
86
     * @var ModuleTemplate
87
     */
88
    protected $moduleTemplate;
89
90
    /**
91
     * @var ExtendedTemplateService
92
     */
93
    protected $templateService;
94
95
    /**
96
     * @var int GET/POST var 'id'
97
     */
98
    protected $id;
99
100
    /**
101
     * The module menu items array. Each key represents a key for which values can range between the items in the array of that key.
102
     * Written by client classes.
103
     *
104
     * @var array
105
     */
106
    public $MOD_MENU = [
107
        'function' => []
108
    ];
109
110
    /**
111
     * Current settings for the keys of the MOD_MENU array, used in client classes
112
     *
113
     * @var array
114
     */
115
    public $MOD_SETTINGS = [];
116
117
    /**
118
     * Module TSconfig based on PAGE TSconfig / USER TSconfig
119
     *
120
     * @var array
121
     */
122
    protected $modTSconfig;
123
124
    /**
125
     * Contains module configuration parts from TBE_MODULES_EXT if found
126
     *
127
     * @var array
128
     */
129
    protected $extClassConf;
130
131
    /**
132
     * May contain an instance of a 'Function menu module' which connects to this backend module.
133
     *
134
     * @see checkExtObj()
135
     * @var object
136
     */
137
    protected $extObj;
138
139
    /**
140
     * @var ServerRequestInterface
141
     */
142
    protected $request;
143
144
    /**
145
     * Constructor
146
     */
147
    public function __construct()
148
    {
149
        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
150
        $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
151
    }
152
153
    /**
154
     * Generates the menu based on $this->MOD_MENU
155
     *
156
     * @throws \InvalidArgumentException
157
     */
158
    protected function generateMenu()
159
    {
160
        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
161
        $menu->setIdentifier('WebFuncJumpMenu');
162
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
163
        foreach ($this->MOD_MENU['function'] as $controller => $title) {
164
            $item = $menu
165
                ->makeMenuItem()
166
                ->setHref(
167
                    (string)$uriBuilder->buildUriFromRoute(
168
                        $this->moduleName,
169
                        [
170
                            'id' => $this->id,
171
                            'SET' => [
172
                                'function' => $controller
173
                            ]
174
                        ]
175
                    )
176
                )
177
                ->setTitle($title);
178
            if ($controller === $this->MOD_SETTINGS['function']) {
179
                $item->setActive(true);
180
            }
181
            $menu->addMenuItem($item);
182
        }
183
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
184
    }
185
186
    /**
187
     * Injects the request object for the current request or subrequest
188
     * Then checks for module functions that have hooked in, and renders menu etc.
189
     *
190
     * @param ServerRequestInterface $request the current request
191
     * @return ResponseInterface the response with the content
192
     */
193
    public function mainAction(ServerRequestInterface $request): ResponseInterface
194
    {
195
        $this->request = $request;
196
        $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
197
        $changedMenuSettings = $request->getParsedBody()['SET'] ?? $request->getQueryParams()['SET'] ?? [];
198
        $changedMenuSettings = is_array($changedMenuSettings) ? $changedMenuSettings : [];
199
        $this->menuConfig($changedMenuSettings);
200
        // Loads $this->extClassConf with the configuration for the CURRENT function of the menu.
201
        $this->extClassConf = $this->getExternalItemConfig('web_ts', 'function', $this->MOD_SETTINGS['function']);
202
        $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
203
204
        // Checking for first level external objects
205
        $this->checkExtObj($changedMenuSettings, $request);
206
207
        // Access check...
208
        // The page will show only if there is a valid page and if this page may be viewed by the user
209
        $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
0 ignored issues
show
Documentation Bug introduced by
It seems like TYPO3\CMS\Backend\Utilit...d, $this->perms_clause) can also be of type false. However, the property $pageinfo is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
210
        $this->access = is_array($this->pageinfo);
211
        $view = $this->getFluidTemplateObject('tstemplate');
212
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
213
        if ($this->id && $this->access) {
214
            $urlParameters = [
215
                'id' => $this->id,
216
                'template' => 'all'
217
            ];
218
            $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
219
220
            // JavaScript
221
            $this->moduleTemplate->addJavaScriptCode(
222
                'TSTemplateInlineJS',
223
                'function uFormUrl(aname) {
224
                    document.forms[0].action = ' . GeneralUtility::quoteJSvalue($aHref . '#') . '+aname;
225
                }
226
                function brPoint(lnumber,t) {
227
                    window.location.href = '
228
                . GeneralUtility::quoteJSvalue(
229
                    $aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\'
230
                    . 'TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='
231
                ) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
232
                    return false;
233
                }
234
                if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';'
235
            );
236
            $this->moduleTemplate->getPageRenderer()->addCssInlineBlock(
237
                'TSTemplateInlineStyle',
238
                'TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
239
                TABLE#typo3-objectBrowser A { text-decoration: none; }
240
                TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
241
                .ts-typoscript { width: 100%; }
242
                .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
243
                .tst-analyzer-options { margin:5px 0; }'
244
            );
245
            // Setting up the context sensitive menu:
246
            $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
247
            // Build the module content
248
            $view->assign('actionName', $aHref);
249
            $view->assign('typoscriptTemplateModuleContent', $this->getExtObjContent());
250
            // Setting up the buttons and markers for docheader
251
            $this->getButtons();
252
            $this->generateMenu();
253
        } else {
254
            $workspaceId = $this->getBackendUser()->workspace;
255
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
256
                ->getQueryBuilderForTable('sys_template');
257
            $queryBuilder->getRestrictions()
258
                ->removeAll()
259
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
260
            $this->applyWorkspaceConstraint(
261
                $queryBuilder,
262
                'sys_template',
263
                $workspaceId
264
            );
265
            $result = $queryBuilder
266
                ->select(
267
                    'uid',
268
                    'pid',
269
                    'title',
270
                    'root',
271
                    'hidden',
272
                    'starttime',
273
                    'endtime',
274
                    't3ver_oid',
275
                    't3ver_wsid',
276
                    't3ver_state'
277
                )
278
                ->from('sys_template')
279
                ->orderBy('sys_template.pid')
280
                ->addOrderBy('sys_template.sorting')
281
                ->execute();
282
            $pArray = [];
283
            while ($record = $result->fetch()) {
284
                BackendUtility::workspaceOL('sys_template', $record, $workspaceId, true);
285
                if (empty($record) || VersionState::cast($record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
286
                    continue;
287
                }
288
                $additionalFieldsForRootline = ['sorting', 'shortcut'];
289
                $rootline = BackendUtility::BEgetRootLine($record['pid'], '', true, $additionalFieldsForRootline);
290
                $this->setInPageArray($pArray, $rootline, $record);
291
            }
292
293
            $view->getRenderingContext()->setControllerAction('PageZero');
294
            $view->assign('pageTree', $pArray);
295
296
            // RENDER LIST of pages with templates, END
297
            // Setting up the buttons and markers for docheader
298
            $this->getButtons();
299
        }
300
        $this->moduleTemplate->setContent($view->render());
301
        return new HtmlResponse($this->moduleTemplate->renderContent());
302
    }
303
304
    /**
305
     * Create the panel of buttons for submitting the form or otherwise perform operations.
306
     */
307
    protected function getButtons()
308
    {
309
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
310
        $lang = $this->getLanguageService();
311
312
        if ($this->id && $this->access) {
313
            // View page
314
            $previewDataAttributes = PreviewUriBuilder::create((int)$this->pageinfo['uid'])
315
                ->withRootLine(BackendUtility::BEgetRootLine($this->pageinfo['uid']))
316
                ->buildDispatcherDataAttributes();
317
            $viewButton = $buttonBar->makeLinkButton()
318
                ->setHref('#')
319
                ->setDataAttributes($previewDataAttributes ?? [])
320
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
321
                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-page', Icon::SIZE_SMALL));
322
            $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
323
324
            $sObj = $this->request->getParsedBody()['sObj'] ?? $this->request->getQueryParams()['sObj'] ?? null;
325
            if ($this->extClassConf['name'] === TypoScriptTemplateInformationModuleFunctionController::class) {
326
                // NEW button
327
                $urlParameters = [
328
                    'id' => $this->id,
329
                    'template' => 'all',
330
                    'createExtension' => 'new'
331
                ];
332
                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
333
                $newButton = $buttonBar->makeLinkButton()
334
                    ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
335
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:db_new.php.pagetitle'))
336
                    ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
337
                        'actions-add',
338
                        Icon::SIZE_SMALL
339
                    ));
340
                $buttonBar->addButton($newButton);
341
            } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class
342
                && !empty($this->MOD_MENU['constant_editor_cat'])) {
343
                // SAVE button
344
                $saveButton = $buttonBar->makeInputButton()
345
                    ->setName('_savedok')
346
                    ->setValue('1')
347
                    ->setForm('TypoScriptTemplateModuleController')
348
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
349
                    ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
350
                        'actions-document-save',
351
                        Icon::SIZE_SMALL
352
                    ))
353
                    ->setShowLabelText(true);
354
                $buttonBar->addButton($saveButton);
355
            } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class
356
                && !empty($sObj)
357
            ) {
358
                // back button in edit mode of object browser. "sObj" is set by ExtendedTemplateService
359
                $urlParameters = [
360
                    'id' => $this->id
361
                ];
362
                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
363
                $backButton = $buttonBar->makeLinkButton()
364
                    ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
365
                    ->setClasses('typo3-goBack')
366
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
367
                    ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
368
                        'actions-view-go-back',
369
                        Icon::SIZE_SMALL
370
                    ));
371
                $buttonBar->addButton($backButton);
372
            }
373
        }
374
        // Shortcut
375
        $shortcutButton = $buttonBar->makeShortcutButton()
376
            ->setModuleName('web_ts')
377
            ->setDisplayName($this->getShortcutTitle())
378
            ->setArguments([
379
                'route' => $this->request->getQueryParams()['route'],
380
                'id' => (int)$this->id
381
            ]);
382
        $buttonBar->addButton($shortcutButton);
383
    }
384
385
    /**
386
     * Wrap title for link in template, called from client classes.
387
     *
388
     * @param string $title
389
     * @param string $onlyKey
390
     * @return string
391
     */
392
    public function linkWrapTemplateTitle($title, $onlyKey = '')
393
    {
394
        $urlParameters = [
395
            'id' => $this->id
396
        ];
397
        if ($onlyKey) {
398
            $urlParameters['e'] = [$onlyKey => 1];
399
        } else {
400
            $urlParameters['e'] = ['constants' => 1];
401
        }
402
        $urlParameters['SET'] = ['function' => TypoScriptTemplateInformationModuleFunctionController::class];
403
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
404
        $url = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
405
        return '<a href="' . htmlspecialchars($url) . '">' . htmlspecialchars($title) . '</a>';
406
    }
407
408
    /**
409
     * No template, called from client classes.
410
     *
411
     * @param int $newStandardTemplate
412
     * @return string
413
     */
414
    public function noTemplate($newStandardTemplate = 0)
415
    {
416
        $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
417
418
        $moduleContent = [];
419
        $moduleContent['state'] = InfoboxViewHelper::STATE_INFO;
420
421
        // New standard?
422
        if ($newStandardTemplate) {
423
            $selector = '';
424
            $staticsText = '';
425
            // Hook to change output, implemented for statictemplates
426
            $hookObject = $this->getHookObjectForAction('newStandardTemplateView');
427
            if (!empty($hookObject)) {
428
                $reference = [
429
                    'selectorHtml' => &$selector,
430
                    'staticsText' => &$staticsText
431
                ];
432
                GeneralUtility::callUserFunction(
433
                    $hookObject,
434
                    $reference,
435
                    $this
436
                );
437
                $selector = $reference['selectorHtml'];
438
                $staticsText = $reference['staticsText'];
439
            }
440
            // Extension?
441
            $moduleContent['staticsText'] = $staticsText;
442
            $moduleContent['selector'] = $selector;
443
        }
444
        // Go to previous Page with Template...
445
        $previousPage = $this->templateService->ext_prevPageWithTemplate($this->id, $this->perms_clause);
446
        if ($previousPage) {
447
            $urlParameters = [
448
                'id' => $previousPage['uid']
449
            ];
450
            $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
451
            $previousPage['aHref'] = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
452
            $moduleContent['previousPage'] = $previousPage;
453
        }
454
        $view = $this->getFluidTemplateObject('tstemplate', 'NoTemplate');
0 ignored issues
show
Bug introduced by
The method getFluidTemplateObject() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

454
        /** @scrutinizer ignore-call */ 
455
        $view = $this->getFluidTemplateObject('tstemplate', 'NoTemplate');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
455
        $view->assign('content', $moduleContent);
456
        return $view->render();
457
    }
458
459
    /**
460
     * Render template menu, called from client classes.
461
     *
462
     * @param ServerRequestInterface $request
463
     * @return string
464
     */
465
    public function templateMenu(ServerRequestInterface $request)
466
    {
467
        $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
468
469
        $all = $this->templateService->ext_getAllTemplates($this->id);
470
        if (count($all) > 1) {
471
            $this->MOD_MENU['templatesOnPage'] = [];
472
            foreach ($all as $d) {
473
                $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
474
            }
475
        }
476
        $this->MOD_SETTINGS = BackendUtility::getModuleData(
477
            $this->MOD_MENU,
478
            $request->getParsedBody()['SET'] ?? $request->getQueryParams()['SET'] ?? [],
479
            'web_ts',
480
            '',
481
            $this->modMenu_dontValidateList,
482
            $this->modMenu_setDefaultList
483
        );
484
        return BackendUtility::getFuncMenu(
485
            $this->id,
486
            'SET[templatesOnPage]',
487
            $this->MOD_SETTINGS['templatesOnPage'],
488
            $this->MOD_MENU['templatesOnPage']
489
        );
490
    }
491
492
    /**
493
     * Create template, called from client classes.
494
     *
495
     * @param int $id
496
     * @param int $actTemplateId
497
     * @return string
498
     */
499
    public function createTemplate($id, $actTemplateId = 0)
500
    {
501
        $recData = [];
502
        $tce = GeneralUtility::makeInstance(DataHandler::class);
503
504
        if ($this->request->getParsedBody()['createExtension'] ?? $this->request->getQueryParams()['createExtension'] ?? false) {
505
            $recData['sys_template']['NEW'] = [
506
                'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
507
                'title' => '+ext'
508
            ];
509
            $tce->start($recData, []);
510
            $tce->process_datamap();
511
        } elseif ($this->request->getParsedBody()['newWebsite'] ?? $this->request->getQueryParams()['newWebsite'] ?? false) {
512
            // Hook to handle row data, implemented for statictemplates
513
            $hookObject = $this->getHookObjectForAction('newStandardTemplateHandler');
514
            if (!empty($hookObject)) {
515
                $reference = [
516
                    'recData' => &$recData,
517
                    'id' => $id,
518
                ];
519
                GeneralUtility::callUserFunction(
520
                    $hookObject,
521
                    $reference,
522
                    $this
523
                );
524
                $recData = $reference['recData'];
525
            } else {
526
                $recData['sys_template']['NEW'] = [
527
                    'pid' => $id,
528
                    'title' => $this->getLanguageService()->getLL('titleNewSite'),
529
                    'sorting' => 0,
530
                    'root' => 1,
531
                    'clear' => 3,
532
                    'config' => '
533
# Default PAGE object:
534
page = PAGE
535
page.10 = TEXT
536
page.10.value = HELLO WORLD!
537
'
538
                ];
539
            }
540
            $tce->start($recData, []);
541
            $tce->process_datamap();
542
        }
543
        return $tce->substNEWwithIDs['NEW'];
544
    }
545
546
    /**
547
     * Set page in array
548
     * To render list of page tree with templates
549
     *
550
     * @param array $pArray Multidimensional array of page tree with template records
551
     * @param array $rlArr Rootline array
552
     * @param array $row Record of sys_template
553
     */
554
    protected function setInPageArray(&$pArray, $rlArr, $row)
555
    {
556
        ksort($rlArr);
557
        reset($rlArr);
558
        if (!$rlArr[0]['uid']) {
559
            array_shift($rlArr);
560
        }
561
        $cEl = current($rlArr);
562
        if (empty($pArray[$cEl['uid']])) {
563
            $pArray[$cEl['uid']] = $cEl;
564
        }
565
        array_shift($rlArr);
566
        if (!empty($rlArr)) {
567
            if (empty($pArray[$cEl['uid']]['_nodes'])) {
568
                $pArray[$cEl['uid']]['_nodes'] = [];
569
            }
570
            $this->setInPageArray($pArray[$cEl['uid']]['_nodes'], $rlArr, $row);
571
        } else {
572
            $pArray[$cEl['uid']]['_templates'][] = $row;
573
        }
574
        uasort($pArray, function ($a, $b) {
575
            return $a['sorting'] - $b['sorting'];
576
        });
577
    }
578
579
    /**
580
     * Returns a new standalone view, shorthand function
581
     *
582
     * @param string $extensionName
583
     * @param string $templateName
584
     * @return StandaloneView
585
     */
586
    protected function getFluidTemplateObject($extensionName, $templateName = 'Main')
587
    {
588
        $view = GeneralUtility::makeInstance(StandaloneView::class);
589
        $view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName($extensionName);
590
        $view->getRenderingContext()->setControllerAction($templateName);
591
        $view->getRequest()->setControllerExtensionName('tstemplate');
592
        return $view;
593
    }
594
595
    /**
596
     * Fetching all live records, and versioned records that do not have a "online ID" counterpart,
597
     * as this is then handled via the BackendUtility::workspaceOL().
598
     *
599
     * @param QueryBuilder $queryBuilder
600
     * @param string $tableName
601
     * @param int $workspaceId
602
     */
603
    protected function applyWorkspaceConstraint(
604
        QueryBuilder $queryBuilder,
605
        string $tableName,
606
        int $workspaceId
607
    ) {
608
        if (!BackendUtility::isTableWorkspaceEnabled($tableName)) {
609
            return;
610
        }
611
612
        $queryBuilder->getRestrictions()->add(
613
            GeneralUtility::makeInstance(WorkspaceRestriction::class, $workspaceId)
614
        );
615
    }
616
617
    /**
618
     * @param string $action
619
     * @return string
620
     */
621
    protected function getHookObjectForAction($action)
622
    {
623
        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action])) {
624
            return $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action];
625
        }
626
        return null;
627
    }
628
629
    /**
630
     * Initializes the internal MOD_MENU array setting and unsetting items based on various conditions. It also merges in external menu items from the global array TBE_MODULES_EXT (see mergeExternalItems())
631
     * Then MOD_SETTINGS array is cleaned up (see \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()) so it contains only valid values. It's also updated with any SET[] values submitted.
632
     * Also loads the modTSconfig internal variable.
633
     *
634
     * @param array $changedSettings can be anything
635
     * @see mainAction()
636
     * @see \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()
637
     * @see mergeExternalItems()
638
     */
639
    protected function menuConfig($changedSettings)
640
    {
641
        // Page / user TSconfig settings and blinding of menu-items
642
        $this->modTSconfig['properties'] = BackendUtility::getPagesTSconfig($this->id)['mod.']['web_ts.'] ?? [];
643
        $this->MOD_MENU['function'] = $this->mergeExternalItems('web_ts', 'function', $this->MOD_MENU['function']);
644
        $blindActions = $this->modTSconfig['properties']['menu.']['function.'] ?? [];
645
        foreach ($blindActions as $key => $value) {
646
            if (!$value && array_key_exists($key, $this->MOD_MENU['function'])) {
647
                unset($this->MOD_MENU['function'][$key]);
648
            }
649
        }
650
        $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $changedSettings, 'web_ts', '', $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
651
    }
652
653
    /**
654
     * Merges menu items from global array $TBE_MODULES_EXT
655
     *
656
     * @param string $modName Module name for which to find value
657
     * @param string $menuKey Menu key, eg. 'function' for the function menu.
658
     * @param array $menuArr The part of a MOD_MENU array to work on.
659
     * @return array Modified array part.
660
     * @internal
661
     * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction()
662
     * @see menuConfig()
663
     */
664
    protected function mergeExternalItems($modName, $menuKey, $menuArr)
665
    {
666
        $mergeArray = $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
667
        if (is_array($mergeArray)) {
668
            foreach ($mergeArray as $k => $v) {
669
                if (((string)$v['ws'] === '' || ($this->getBackendUser()->workspace === 0 && GeneralUtility::inList($v['ws'], 'online')))
670
                    || ($this->getBackendUser()->workspace > 0 && GeneralUtility::inList($v['ws'], 'custom'))
671
                ) {
672
                    $menuArr[$k] = $this->getLanguageService()->sL($v['title']);
673
                }
674
            }
675
        }
676
        return $menuArr;
677
    }
678
679
    /**
680
     * Returns configuration values from the global variable $TBE_MODULES_EXT for the module given.
681
     * For example if the module is named "web_info" and the "function" key ($menuKey) of MOD_SETTINGS is "stat" ($value) then you will have the values of $TBE_MODULES_EXT['webinfo']['MOD_MENU']['function']['stat'] returned.
682
     *
683
     * @param string $modName Module name
684
     * @param string $menuKey Menu key, eg. "function" for the function menu. See $this->MOD_MENU
685
     * @param string $value Optionally the value-key to fetch from the array that would otherwise have been returned if this value was not set. Look source...
686
     * @return mixed The value from the TBE_MODULES_EXT array.
687
     */
688
    protected function getExternalItemConfig($modName, $menuKey, $value = '')
689
    {
690
        if (isset($GLOBALS['TBE_MODULES_EXT'][$modName])) {
691
            return (string)$value !== ''
692
                ? $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey][$value]
693
                : $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
694
        }
695
        return null;
696
    }
697
698
    /**
699
     * Creates an instance of the class found in $this->extClassConf['name'] in $this->extObj if any (this should hold three keys, "name", "path" and "title" if a "Function menu module" tries to connect...)
700
     * This value in extClassConf might be set by an extension (in an ext_tables/ext_localconf file) which thus "connects" to a module.
701
     * The array $this->extClassConf is set based on the value of MOD_SETTINGS[function]
702
     * If an instance is created it is initiated with $this passed as value and $this->extClassConf as second argument. Further the $this->MOD_SETTING is cleaned up again after calling the init function.
703
     *
704
     * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction()
705
     * @param array $changedSettings
706
     * @param ServerRequestInterface $request
707
     */
708
    protected function checkExtObj($changedSettings, ServerRequestInterface $request)
709
    {
710
        if (is_array($this->extClassConf) && $this->extClassConf['name']) {
711
            $this->extObj = GeneralUtility::makeInstance($this->extClassConf['name']);
712
            $this->extObj->init($this, $request);
713
            // Re-write:
714
            $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $changedSettings, 'web_ts', '', $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
715
        }
716
    }
717
718
    /**
719
     * Return the content of the 'main' function inside the "Function menu module" if present
720
     *
721
     * @return string|null
722
     */
723
    protected function getExtObjContent()
724
    {
725
        // Calls the 'main' function inside the "Function menu module" if present
726
        if ($this->extObj === null) {
727
            $flashMessage = GeneralUtility::makeInstance(
728
                FlashMessage::class,
729
                $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:no_modules_registered'),
730
                $this->getLanguageService()->getLL('title'),
731
                FlashMessage::ERROR
732
            );
733
            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
734
            /** @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue $defaultFlashMessageQueue */
735
            $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
736
            $defaultFlashMessageQueue->enqueue($flashMessage);
737
        } elseif (is_callable([$this->extObj, 'main'])) {
738
            return $this->extObj->main();
739
        }
740
741
        return null;
742
    }
743
744
    /**
745
     * Returns the shortcut title for the current page
746
     *
747
     * @return string
748
     */
749
    protected function getShortcutTitle(): string
750
    {
751
        return sprintf(
752
            '%s: %s [%d]',
753
            $this->getLanguageService()->sL('LLL:EXT:tstemplate/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tablabel'),
754
            BackendUtility::getRecordTitle('pages', $this->pageinfo),
755
            $this->id
756
        );
757
    }
758
759
    /**
760
     * Returns the Language Service
761
     * @return LanguageService
762
     */
763
    protected function getLanguageService(): LanguageService
764
    {
765
        return $GLOBALS['LANG'];
766
    }
767
768
    /**
769
     * Returns the Backend User
770
     * @return BackendUserAuthentication
771
     */
772
    protected function getBackendUser(): BackendUserAuthentication
773
    {
774
        return $GLOBALS['BE_USER'];
775
    }
776
777
    /**
778
     * @return PageRenderer
779
     */
780
    protected function getPageRenderer(): PageRenderer
781
    {
782
        return GeneralUtility::makeInstance(PageRenderer::class);
783
    }
784
}
785