Passed
Push — master ( d5a28b...d12ca0 )
by
unknown
17:01
created

TypoScriptTemplateModuleController::getPageRenderer()   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\Template\ModuleTemplateFactory;
25
use TYPO3\CMS\Backend\Utility\BackendUtility;
26
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27
use TYPO3\CMS\Core\Database\ConnectionPool;
28
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
29
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
30
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
31
use TYPO3\CMS\Core\DataHandling\DataHandler;
32
use TYPO3\CMS\Core\Http\HtmlResponse;
33
use TYPO3\CMS\Core\Imaging\Icon;
34
use TYPO3\CMS\Core\Imaging\IconFactory;
35
use TYPO3\CMS\Core\Localization\LanguageService;
36
use TYPO3\CMS\Core\Messaging\FlashMessage;
37
use TYPO3\CMS\Core\Messaging\FlashMessageService;
38
use TYPO3\CMS\Core\Page\PageRenderer;
39
use TYPO3\CMS\Core\Type\Bitmask\Permission;
40
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
41
use TYPO3\CMS\Core\Utility\GeneralUtility;
42
use TYPO3\CMS\Core\Versioning\VersionState;
43
use TYPO3\CMS\Fluid\View\StandaloneView;
44
use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
45
46
/**
47
 * Module: TypoScript Tools
48
 * @internal This is a specific Backend Controller implementation and is not considered part of the Public TYPO3 API.
49
 */
50
class TypoScriptTemplateModuleController
51
{
52
53
    /**
54
     * @var string
55
     */
56
    protected $perms_clause;
57
58
    /**
59
     * @var string
60
     */
61
    public $modMenu_dontValidateList = '';
62
63
    /**
64
     * @var string Written by client classes
65
     */
66
    public $modMenu_setDefaultList = '';
67
68
    /**
69
     * @var array
70
     */
71
    protected $pageinfo = [];
72
73
    /**
74
     * @var bool
75
     */
76
    protected $access = false;
77
78
    /**
79
     * The name of the module
80
     *
81
     * @var string
82
     */
83
    protected $moduleName = 'web_ts';
84
85
    /**
86
     * ModuleTemplate Container
87
     *
88
     * @var ModuleTemplate
89
     */
90
    protected $moduleTemplate;
91
92
    /**
93
     * @var ExtendedTemplateService
94
     */
95
    protected $templateService;
96
97
    /**
98
     * @var int GET/POST var 'id'
99
     */
100
    protected $id;
101
102
    /**
103
     * The module menu items array. Each key represents a key for which values can range between the items in the array of that key.
104
     * Written by client classes.
105
     *
106
     * @var array
107
     */
108
    public $MOD_MENU = [
109
        'function' => []
110
    ];
111
112
    /**
113
     * Current settings for the keys of the MOD_MENU array, used in client classes
114
     *
115
     * @var array
116
     */
117
    public $MOD_SETTINGS = [];
118
119
    /**
120
     * Module TSconfig based on PAGE TSconfig / USER TSconfig
121
     *
122
     * @var array
123
     */
124
    protected $modTSconfig;
125
126
    /**
127
     * Contains module configuration parts from TBE_MODULES_EXT if found
128
     *
129
     * @var array
130
     */
131
    protected $extClassConf;
132
133
    /**
134
     * May contain an instance of a 'Function menu module' which connects to this backend module.
135
     *
136
     * @see checkExtObj()
137
     * @var object
138
     */
139
    protected $extObj;
140
141
    /**
142
     * @var ServerRequestInterface
143
     */
144
    protected $request;
145
146
    protected IconFactory $iconFactory;
147
    protected PageRenderer $pageRenderer;
148
    protected UriBuilder $uriBuilder;
149
    protected ModuleTemplateFactory $moduleTemplateFactory;
150
151
    public function __construct(
152
        IconFactory $iconFactory,
153
        PageRenderer $pageRenderer,
154
        UriBuilder $uriBuilder,
155
        ModuleTemplateFactory $moduleTemplateFactory
156
    ) {
157
        $this->iconFactory = $iconFactory;
158
        $this->pageRenderer = $pageRenderer;
159
        $this->uriBuilder = $uriBuilder;
160
        $this->moduleTemplateFactory = $moduleTemplateFactory;
161
    }
162
163
    /**
164
     * Generates the menu based on $this->MOD_MENU
165
     *
166
     * @throws \InvalidArgumentException
167
     */
168
    protected function generateMenu()
169
    {
170
        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
171
        $menu->setIdentifier('WebFuncJumpMenu');
172
        foreach ($this->MOD_MENU['function'] as $controller => $title) {
173
            $item = $menu
174
                ->makeMenuItem()
175
                ->setHref(
176
                    (string)$this->uriBuilder->buildUriFromRoute(
177
                        $this->moduleName,
178
                        [
179
                            'id' => $this->id,
180
                            'SET' => [
181
                                'function' => $controller
182
                            ]
183
                        ]
184
                    )
185
                )
186
                ->setTitle($title);
187
            if ($controller === $this->MOD_SETTINGS['function']) {
188
                $item->setActive(true);
189
            }
190
            $menu->addMenuItem($item);
191
        }
192
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
193
    }
194
195
    /**
196
     * Injects the request object for the current request or subrequest
197
     * Then checks for module functions that have hooked in, and renders menu etc.
198
     *
199
     * @param ServerRequestInterface $request the current request
200
     * @return ResponseInterface the response with the content
201
     */
202
    public function mainAction(ServerRequestInterface $request): ResponseInterface
203
    {
204
        $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
205
        $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
206
        $this->request = $request;
207
        $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
208
        $changedMenuSettings = $request->getParsedBody()['SET'] ?? $request->getQueryParams()['SET'] ?? [];
209
        $changedMenuSettings = is_array($changedMenuSettings) ? $changedMenuSettings : [];
210
        $this->menuConfig($changedMenuSettings);
211
        // Loads $this->extClassConf with the configuration for the CURRENT function of the menu.
212
        $this->extClassConf = $this->getExternalItemConfig('web_ts', 'function', $this->MOD_SETTINGS['function']);
213
        $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
214
215
        // Checking for first level external objects
216
        $this->checkExtObj($changedMenuSettings, $request);
217
218
        // Access check...
219
        // The page will show only if there is a valid page and if this page may be viewed by the user
220
        $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...
221
        $this->access = is_array($this->pageinfo);
222
        $view = $this->getFluidTemplateObject('tstemplate');
223
        if ($this->id && $this->access) {
224
            $urlParameters = [
225
                'id' => $this->id,
226
                'template' => 'all'
227
            ];
228
            $aHref = (string)$this->uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
229
230
            // JavaScript
231
            $this->moduleTemplate->addJavaScriptCode(
232
                'TSTemplateInlineJS',
233
                'function uFormUrl(aname) {
234
                    document.forms[0].action = ' . GeneralUtility::quoteJSvalue($aHref . '#') . '+aname;
235
                }
236
                if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';'
237
            );
238
            // Setting up the context sensitive menu:
239
            $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
240
            // Build the module content
241
            $view->assign('actionName', $aHref);
242
            $view->assign('typoscriptTemplateModuleContent', $this->getExtObjContent());
243
            // Setting up the buttons and markers for docheader
244
            $this->getButtons();
245
            $this->generateMenu();
246
        } else {
247
            $workspaceId = $this->getBackendUser()->workspace;
248
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
249
                ->getQueryBuilderForTable('sys_template');
250
            $queryBuilder->getRestrictions()
251
                ->removeAll()
252
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
253
            $this->applyWorkspaceConstraint(
254
                $queryBuilder,
255
                'sys_template',
256
                $workspaceId
257
            );
258
            $result = $queryBuilder
259
                ->select(
260
                    'uid',
261
                    'pid',
262
                    'title',
263
                    'root',
264
                    'hidden',
265
                    'starttime',
266
                    'endtime',
267
                    't3ver_oid',
268
                    't3ver_wsid',
269
                    't3ver_state'
270
                )
271
                ->from('sys_template')
272
                ->orderBy('sys_template.pid')
273
                ->addOrderBy('sys_template.sorting')
274
                ->execute();
275
            $pArray = [];
276
            while ($record = $result->fetch()) {
277
                BackendUtility::workspaceOL('sys_template', $record, $workspaceId, true);
278
                if (empty($record) || VersionState::cast($record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
279
                    continue;
280
                }
281
                $additionalFieldsForRootline = ['sorting', 'shortcut'];
282
                $rootline = BackendUtility::BEgetRootLine($record['pid'], '', true, $additionalFieldsForRootline);
283
                $this->setInPageArray($pArray, $rootline, $record);
284
            }
285
286
            $view->getRenderingContext()->setControllerAction('PageZero');
287
            $view->assign('pageTree', $pArray);
288
289
            // RENDER LIST of pages with templates, END
290
            // Setting up the buttons and markers for docheader
291
            $this->getButtons();
292
        }
293
        $this->moduleTemplate->setContent($view->render());
294
        return new HtmlResponse($this->moduleTemplate->renderContent());
295
    }
296
297
    /**
298
     * Create the panel of buttons for submitting the form or otherwise perform operations.
299
     */
300
    protected function getButtons()
301
    {
302
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
303
        $lang = $this->getLanguageService();
304
305
        if ($this->id && $this->access) {
306
            // View page
307
            $previewDataAttributes = PreviewUriBuilder::create((int)$this->pageinfo['uid'])
308
                ->withRootLine(BackendUtility::BEgetRootLine($this->pageinfo['uid']))
309
                ->buildDispatcherDataAttributes();
310
            $viewButton = $buttonBar->makeLinkButton()
311
                ->setHref('#')
312
                ->setDataAttributes($previewDataAttributes ?? [])
313
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
314
                ->setIcon($this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL));
315
            $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
316
317
            $sObj = $this->request->getParsedBody()['sObj'] ?? $this->request->getQueryParams()['sObj'] ?? null;
318
            if ($this->extClassConf['name'] === TypoScriptTemplateInformationModuleFunctionController::class) {
319
                // NEW button
320
                $urlParameters = [
321
                    'id' => $this->id,
322
                    'template' => 'all',
323
                    'createExtension' => 'new'
324
                ];
325
                $newButton = $buttonBar->makeLinkButton()
326
                    ->setHref((string)$this->uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
327
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:db_new.php.pagetitle'))
328
                    ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL));
329
                $buttonBar->addButton($newButton);
330
            } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class
331
                && !empty($this->MOD_MENU['constant_editor_cat'])) {
332
                // SAVE button
333
                $saveButton = $buttonBar->makeInputButton()
334
                    ->setName('_savedok')
335
                    ->setValue('1')
336
                    ->setForm('TypoScriptTemplateModuleController')
337
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
338
                    ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
339
                    ->setShowLabelText(true);
340
                $buttonBar->addButton($saveButton);
341
            } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class
342
                && !empty($sObj)
343
            ) {
344
                // back button in edit mode of object browser. "sObj" is set by ExtendedTemplateService
345
                $urlParameters = [
346
                    'id' => $this->id
347
                ];
348
                $backButton = $buttonBar->makeLinkButton()
349
                    ->setHref((string)$this->uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
350
                    ->setClasses('typo3-goBack')
351
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
352
                    ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
353
                $buttonBar->addButton($backButton);
354
            }
355
        }
356
        // Shortcut
357
        $shortcutButton = $buttonBar->makeShortcutButton()
358
            ->setRouteIdentifier('web_ts')
359
            ->setDisplayName($this->getShortcutTitle())
360
            ->setArguments(['id' => (int)$this->id]);
361
        $buttonBar->addButton($shortcutButton);
362
    }
363
364
    /**
365
     * Wrap title for link in template, called from client classes.
366
     *
367
     * @param string $title
368
     * @param string $onlyKey
369
     * @return string
370
     */
371
    public function linkWrapTemplateTitle($title, $onlyKey = '')
372
    {
373
        $urlParameters = [
374
            'id' => $this->id
375
        ];
376
        if ($onlyKey) {
377
            $urlParameters['e'] = [$onlyKey => 1];
378
        } else {
379
            $urlParameters['e'] = ['constants' => 1];
380
        }
381
        $urlParameters['SET'] = ['function' => TypoScriptTemplateInformationModuleFunctionController::class];
382
        $url = (string)$this->uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
383
        return '<a href="' . htmlspecialchars($url) . '">' . htmlspecialchars($title) . '</a>';
384
    }
385
386
    /**
387
     * No template, called from client classes.
388
     *
389
     * @param int $newStandardTemplate
390
     * @return string
391
     */
392
    public function noTemplate($newStandardTemplate = 0)
393
    {
394
        $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
395
396
        $moduleContent = [];
397
        $moduleContent['state'] = InfoboxViewHelper::STATE_INFO;
398
399
        // New standard?
400
        if ($newStandardTemplate) {
401
            $selector = '';
402
            $staticsText = '';
403
            // Hook to change output, implemented for statictemplates
404
            $hookObject = $this->getHookObjectForAction('newStandardTemplateView');
405
            if (!empty($hookObject)) {
406
                $reference = [
407
                    'selectorHtml' => &$selector,
408
                    'staticsText' => &$staticsText
409
                ];
410
                GeneralUtility::callUserFunction(
411
                    $hookObject,
412
                    $reference,
413
                    $this
414
                );
415
                $selector = $reference['selectorHtml'];
416
                $staticsText = $reference['staticsText'];
417
            }
418
            // Extension?
419
            $moduleContent['staticsText'] = $staticsText;
420
            $moduleContent['selector'] = $selector;
421
        }
422
        $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

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