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

PageLayoutController::getSearchBox()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 11
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Backend\Controller;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Backend\Module\ModuleLoader;
23
use TYPO3\CMS\Backend\Routing\PreviewUriBuilder;
24
use TYPO3\CMS\Backend\Routing\UriBuilder;
25
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
26
use TYPO3\CMS\Backend\Template\ModuleTemplate;
27
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
28
use TYPO3\CMS\Backend\Utility\BackendUtility;
29
use TYPO3\CMS\Backend\View\BackendLayoutView;
30
use TYPO3\CMS\Backend\View\PageLayoutContext;
31
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
32
use TYPO3\CMS\Core\Database\ConnectionPool;
33
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
34
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
35
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
36
use TYPO3\CMS\Core\Http\HtmlResponse;
37
use TYPO3\CMS\Core\Imaging\Icon;
38
use TYPO3\CMS\Core\Imaging\IconFactory;
39
use TYPO3\CMS\Core\Localization\LanguageService;
40
use TYPO3\CMS\Core\Page\PageRenderer;
41
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
42
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
43
use TYPO3\CMS\Core\Type\Bitmask\Permission;
44
use TYPO3\CMS\Core\Utility\GeneralUtility;
45
use TYPO3\CMS\Core\Versioning\VersionState;
46
use TYPO3\CMS\Fluid\View\StandaloneView;
47
use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
48
use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
49
50
/**
51
 * Script Class for Web > Layout module
52
 */
53
class PageLayoutController
54
{
55
    /**
56
     * Page Id for which to make the listing
57
     *
58
     * @var int
59
     * @internal
60
     */
61
    public $id;
62
63
    /**
64
     * Module TSconfig
65
     *
66
     * @var array
67
     */
68
    protected $modTSconfig = [];
69
70
    /**
71
     * Module shared TSconfig
72
     *
73
     * @var array
74
     */
75
    protected $modSharedTSconfig = [];
76
77
    /**
78
     * Current ids page record
79
     *
80
     * @var array|bool
81
     * @internal
82
     */
83
    public $pageinfo;
84
85
    /**
86
     * List of column-integers to edit. Is set from TSconfig, default is "1,0,2,3"
87
     *
88
     * @var string
89
     */
90
    protected $colPosList;
91
92
    /**
93
     * Currently selected language for editing content elements
94
     *
95
     * @var int
96
     */
97
    protected $current_sys_language;
98
99
    /**
100
     * Menu configuration
101
     *
102
     * @var array
103
     */
104
    protected $MOD_MENU = [];
105
106
    /**
107
     * Module settings (session variable)
108
     *
109
     * @var array
110
     * @internal
111
     */
112
    public $MOD_SETTINGS = [];
113
114
    /**
115
     * List of column-integers accessible to the current BE user.
116
     * Is set from TSconfig, default is $colPosList
117
     *
118
     * @var string
119
     */
120
    protected $activeColPosList;
121
122
    /**
123
     * The name of the module
124
     *
125
     * @var string
126
     */
127
    protected $moduleName = 'web_layout';
128
129
    /**
130
     * @var ModuleTemplate
131
     */
132
    protected $moduleTemplate;
133
134
    /**
135
     * @var ButtonBar
136
     */
137
    protected $buttonBar;
138
139
    /**
140
     * @var string
141
     */
142
    protected $searchContent;
143
144
    /**
145
     * @var SiteLanguage[]
146
     */
147
    protected $availableLanguages;
148
149
    /**
150
     * @var PageLayoutContext|null
151
     */
152
    protected $context;
153
154
    protected IconFactory $iconFactory;
155
    protected PageRenderer $pageRenderer;
156
    protected UriBuilder $uriBuilder;
157
    protected PageRepository $pageRepository;
158
    protected ModuleTemplateFactory $moduleTemplateFactory;
159
160
    public function __construct(
161
        IconFactory $iconFactory,
162
        PageRenderer $pageRenderer,
163
        UriBuilder $uriBuilder,
164
        PageRepository $pageRepository,
165
        ModuleTemplateFactory $moduleTemplateFactory
166
    ) {
167
        $this->iconFactory = $iconFactory;
168
        $this->pageRenderer = $pageRenderer;
169
        $this->uriBuilder = $uriBuilder;
170
        $this->pageRepository = $pageRepository;
171
        $this->moduleTemplateFactory = $moduleTemplateFactory;
172
    }
173
    /**
174
     * Injects the request object for the current request or subrequest
175
     * As this controller goes only through the main() method, it is rather simple for now
176
     *
177
     * @param ServerRequestInterface $request the current request
178
     * @return ResponseInterface the response with the content
179
     */
180
    public function mainAction(ServerRequestInterface $request): ResponseInterface
181
    {
182
        $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
183
        $this->buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
184
        $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
185
        // Setting module configuration / page select clause
186
        $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
187
188
        // Load page info array
189
        $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
190
        if ($this->pageinfo !== false) {
191
            // If page info is not resolved, user has no access or the ID parameter was malformed.
192
            $this->context = GeneralUtility::makeInstance(
193
                PageLayoutContext::class,
194
                $this->pageinfo,
195
                GeneralUtility::makeInstance(BackendLayoutView::class)->getBackendLayoutForPage($this->id)
196
            );
197
        }
198
199
        /** @var SiteInterface $currentSite */
200
        $currentSite = $request->getAttribute('site');
201
        $this->availableLanguages = $currentSite->getAvailableLanguages($this->getBackendUser(), false, $this->id);
202
        // initialize page/be_user TSconfig settings
203
        $pageTsConfig = BackendUtility::getPagesTSconfig($this->id);
204
        $this->modSharedTSconfig['properties'] = $pageTsConfig['mod.']['SHARED.'] ?? [];
205
        $this->modTSconfig['properties'] = $pageTsConfig['mod.']['web_layout.'] ?? [];
206
207
        // Initialize menu
208
        $this->menuConfig($request);
209
        // Setting sys language from session var
210
        $this->current_sys_language = (int)$this->MOD_SETTINGS['language'];
211
212
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/ClearCache');
213
214
        $this->main($request);
215
        return new HtmlResponse($this->moduleTemplate->renderContent());
216
    }
217
218
    /**
219
     * Initialize menu array
220
     * @param ServerRequestInterface $request
221
     */
222
    protected function menuConfig(ServerRequestInterface $request): void
223
    {
224
        // MENU-ITEMS:
225
        $this->MOD_MENU = [
226
            'tt_content_showHidden' => '',
227
            'function' => [
228
                1 => $this->getLanguageService()->getLL('m_function_1'),
229
                2 => $this->getLanguageService()->getLL('m_function_2')
230
            ],
231
            'language' => [
232
                0 => $this->getLanguageService()->getLL('m_default')
233
            ]
234
        ];
235
236
        // First, select all localized page records on the current page.
237
        // Each represents a possibility for a language on the page. Add these to language selector.
238
        if ($this->id) {
239
            // Compile language data for pid != 0 only. The language drop-down is not shown on pid 0
240
            // since pid 0 can't be localized.
241
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
242
            $queryBuilder->getRestrictions()->removeAll()
243
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
244
                ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
245
            $statement = $queryBuilder->select('uid', $GLOBALS['TCA']['pages']['ctrl']['languageField'])
246
                ->from('pages')
247
                ->where(
248
                    $queryBuilder->expr()->eq(
249
                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
250
                        $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
251
                    )
252
                )->execute();
253
            while ($pageTranslation = $statement->fetch()) {
254
                $languageId = $pageTranslation[$GLOBALS['TCA']['pages']['ctrl']['languageField']];
255
                if (isset($this->availableLanguages[$languageId])) {
256
                    $this->MOD_MENU['language'][$languageId] = $this->availableLanguages[$languageId]->getTitle();
257
                }
258
            }
259
            // Override the label
260
            if (isset($this->availableLanguages[0])) {
261
                $this->MOD_MENU['language'][0] = $this->availableLanguages[0]->getTitle();
262
            }
263
        }
264
        // Initialize the available actions
265
        $actions = $this->initActions();
266
        // Clean up settings
267
        $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $request->getParsedBody()['SET'] ?? $request->getQueryParams()['SET'] ?? [], $this->moduleName);
268
        // For all elements to be shown in draft workspaces & to also show hidden elements by default if user hasn't disabled the option
269
        if ($this->getBackendUser()->workspace != 0
270
            || !isset($this->MOD_SETTINGS['tt_content_showHidden'])
271
            || $this->MOD_SETTINGS['tt_content_showHidden'] !== '0'
272
        ) {
273
            $this->MOD_SETTINGS['tt_content_showHidden'] = 1;
274
        }
275
        // Make action menu from available actions
276
        $this->makeActionMenu($actions);
277
    }
278
279
    /**
280
     * Initializes the available actions this module provides
281
     *
282
     * @return array the available actions
283
     */
284
    protected function initActions(): array
285
    {
286
        $actions = [
287
            1 => $this->getLanguageService()->getLL('m_function_1')
288
        ];
289
        // Find if there are ANY languages at all (and if not, do not show the language option from function menu).
290
        if (count($this->availableLanguages) > 1) {
291
            $actions[2] = $this->getLanguageService()->getLL('m_function_2');
292
        }
293
        $this->makeLanguageMenu();
294
        // Page / user TSconfig blinding of menu-items
295
        $blindActions = $this->modTSconfig['properties']['menu.']['functions.'] ?? [];
296
        foreach ($blindActions as $key => $value) {
297
            if (!$value && array_key_exists($key, $actions)) {
298
                unset($actions[$key]);
299
            }
300
        }
301
302
        return $actions;
303
    }
304
305
    /**
306
     * This creates the dropdown menu with the different actions this module is able to provide.
307
     * For now they are Columns and Languages.
308
     *
309
     * @param array $actions array with the available actions
310
     */
311
    protected function makeActionMenu(array $actions): void
312
    {
313
        $actionMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
314
        $actionMenu->setIdentifier('actionMenu');
315
        $actionMenu->setLabel('');
316
317
        $defaultKey = null;
318
        $foundDefaultKey = false;
319
        foreach ($actions as $key => $action) {
320
            $menuItem = $actionMenu
321
                ->makeMenuItem()
322
                ->setTitle($action)
323
                ->setHref((string)$this->uriBuilder->buildUriFromRoute($this->moduleName) . '&id=' . $this->id . '&SET[function]=' . $key);
324
325
            if (!$foundDefaultKey) {
326
                $defaultKey = $key;
327
                $foundDefaultKey = true;
328
            }
329
            if ((int)$this->MOD_SETTINGS['function'] === $key) {
330
                $menuItem->setActive(true);
331
                $defaultKey = null;
332
            }
333
            $actionMenu->addMenuItem($menuItem);
334
        }
335
        if (isset($defaultKey)) {
336
            $this->MOD_SETTINGS['function'] = $defaultKey;
337
        }
338
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($actionMenu);
339
    }
340
341
    /**
342
     * Generate the flashmessages for current pid
343
     *
344
     * @return string HTML content with flashmessages
345
     */
346
    protected function getHeaderFlashMessagesForCurrentPid(): string
347
    {
348
        $content = '';
349
        $lang = $this->getLanguageService();
350
351
        $view = GeneralUtility::makeInstance(StandaloneView::class);
352
        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
353
354
        // If page is a folder
355
        if ($this->pageinfo['doktype'] == PageRepository::DOKTYPE_SYSFOLDER) {
356
            $moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
357
            $moduleLoader->load($GLOBALS['TBE_MODULES']);
358
            $modules = $moduleLoader->modules;
359
            if (is_array($modules['web']['sub']['list'])) {
360
                $title = $lang->getLL('goToListModule');
361
                $message = '<p>' . $lang->getLL('goToListModuleMessage') . '</p>';
362
                $message .= '<a class="btn btn-info" href="javascript:top.goToModule(\'web_list\');">' . $lang->getLL('goToListModule') . '</a>';
363
                $view->assignMultiple([
364
                    'title' => $title,
365
                    'message' => $message,
366
                    'state' => InfoboxViewHelper::STATE_INFO
367
                ]);
368
                $content .= $view->render();
369
            }
370
        } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_SHORTCUT) {
371
            $shortcutMode = (int)$this->pageinfo['shortcut_mode'];
372
            $targetPage = [];
373
            $message = '';
374
            $state = InfoboxViewHelper::STATE_ERROR;
375
376
            if ($shortcutMode || $this->pageinfo['shortcut']) {
377
                switch ($shortcutMode) {
378
                    case PageRepository::SHORTCUT_MODE_NONE:
379
                        $targetPage = $this->getTargetPageIfVisible($this->pageRepository->getPage($this->pageinfo['shortcut']));
380
                        $message .= $targetPage === [] ? $lang->getLL('pageIsMisconfiguredOrNotAccessibleInternalLinkMessage') : '';
381
                        break;
382
                    case PageRepository::SHORTCUT_MODE_FIRST_SUBPAGE:
383
                        $menuOfPages = $this->pageRepository->getMenu($this->pageinfo['uid'], '*', 'sorting', 'AND hidden = 0');
384
                        $targetPage = reset($menuOfPages) ?: [];
385
                        $message .= $targetPage === [] ? $lang->getLL('pageIsMisconfiguredFirstSubpageMessage') : '';
386
                        break;
387
                    case PageRepository::SHORTCUT_MODE_PARENT_PAGE:
388
                        $targetPage = $this->getTargetPageIfVisible($this->pageRepository->getPage($this->pageinfo['pid']));
389
                        $message .= $targetPage === [] ? $lang->getLL('pageIsMisconfiguredParentPageMessage') : '';
390
                        break;
391
                    case PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE:
392
                        $possibleTargetPages = $this->pageRepository->getMenu($this->pageinfo['uid'], '*', 'sorting', 'AND hidden = 0');
393
                        if ($possibleTargetPages === []) {
394
                            $message .= $lang->getLL('pageIsMisconfiguredOrNotAccessibleRandomInternalLinkMessage');
395
                            break;
396
                        }
397
                        $message = $lang->getLL('pageIsRandomInternalLinkMessage');
398
                        $state = InfoboxViewHelper::STATE_INFO;
399
                        break;
400
                }
401
                $message = htmlspecialchars($message);
402
                if ($targetPage !== [] && $shortcutMode !== PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
403
                    $linkToPid = GeneralUtility::linkThisScript(['id' => $targetPage['uid']]);
404
                    $path = BackendUtility::getRecordPath($targetPage['uid'], $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW), 1000);
405
                    $linkedPath = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($path) . '</a>';
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type array<integer,string>; however, parameter $string of htmlspecialchars() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

405
                    $linkedPath = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars(/** @scrutinizer ignore-type */ $path) . '</a>';
Loading history...
406
                    $message .= sprintf(htmlspecialchars($lang->getLL('pageIsInternalLinkMessage')), $linkedPath);
407
                    $message .= ' (' . htmlspecialchars($lang->sL(BackendUtility::getLabelFromItemlist('pages', 'shortcut_mode', (string)$shortcutMode))) . ')';
408
                    $state = InfoboxViewHelper::STATE_INFO;
409
                }
410
            } else {
411
                $message = htmlspecialchars($lang->getLL('pageIsMisconfiguredInternalLinkMessage'));
412
                $state = InfoboxViewHelper::STATE_ERROR;
413
            }
414
415
            $view->assignMultiple([
416
                'title' => $this->pageinfo['title'],
417
                'message' => $message,
418
                'state' => $state
419
            ]);
420
            $content .= $view->render();
421
        } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_LINK) {
422
            if (empty($this->pageinfo['url'])) {
423
                $view->assignMultiple([
424
                    'title' => $this->pageinfo['title'],
425
                    'message' => $lang->getLL('pageIsMisconfiguredExternalLinkMessage'),
426
                    'state' => InfoboxViewHelper::STATE_ERROR
427
                ]);
428
                $content .= $view->render();
429
            } else {
430
                $externalUrl = $this->pageRepository->getExtURL($this->pageinfo);
0 ignored issues
show
Bug introduced by
It seems like $this->pageinfo can also be of type boolean; however, parameter $pagerow of TYPO3\CMS\Core\Domain\Re...Repository::getExtURL() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

430
                $externalUrl = $this->pageRepository->getExtURL(/** @scrutinizer ignore-type */ $this->pageinfo);
Loading history...
431
                if (is_string($externalUrl)) {
432
                    $externalUrl = htmlspecialchars($externalUrl);
433
                    $externalUrlHtml = '<a href="' . $externalUrl . '" target="_blank" rel="noreferrer">' . $externalUrl . '</a>';
434
                    $view->assignMultiple([
435
                        'title' => $this->pageinfo['title'],
436
                        'message' => sprintf($lang->getLL('pageIsExternalLinkMessage'), $externalUrlHtml),
437
                        'state' => InfoboxViewHelper::STATE_INFO
438
                    ]);
439
                    $content .= $view->render();
440
                }
441
            }
442
        }
443
        // If content from different pid is displayed
444
        if ($this->pageinfo['content_from_pid']) {
445
            $contentPage = (array)BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
446
            $linkToPid = GeneralUtility::linkThisScript(['id' => $this->pageinfo['content_from_pid']]);
447
            $title = BackendUtility::getRecordTitle('pages', $contentPage);
448
            $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
449
            $message = sprintf($lang->getLL('content_from_pid_title'), $link);
450
            $view->assignMultiple([
451
                'title' => $title,
452
                'message' => $message,
453
                'state' => InfoboxViewHelper::STATE_INFO
454
            ]);
455
            $content .= $view->render();
456
        } else {
457
            $links = $this->getPageLinksWhereContentIsAlsoShownOn($this->pageinfo['uid']);
458
            if (!empty($links)) {
459
                $message = sprintf($lang->getLL('content_on_pid_title'), $links);
460
                $view->assignMultiple([
461
                    'title' => '',
462
                    'message' => $message,
463
                    'state' => InfoboxViewHelper::STATE_INFO
464
                ]);
465
                $content .= $view->render();
466
            }
467
        }
468
        return $content;
469
    }
470
471
    /**
472
     * Get all pages with links where the content of a page $pageId is also shown on
473
     *
474
     * @param int $pageId
475
     * @return string
476
     */
477
    protected function getPageLinksWhereContentIsAlsoShownOn($pageId): string
478
    {
479
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
480
        $queryBuilder->getRestrictions()->removeAll();
481
        $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
482
        $queryBuilder
483
            ->select('*')
484
            ->from('pages')
485
            ->where($queryBuilder->expr()->eq('content_from_pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)));
486
487
        $links = [];
488
        $rows = $queryBuilder->execute()->fetchAll();
489
        if (!empty($rows)) {
490
            foreach ($rows as $row) {
491
                $linkToPid = GeneralUtility::linkThisScript(['id' => $row['uid']]);
492
                $title = BackendUtility::getRecordTitle('pages', $row);
493
                $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$row['uid'] . ')</a>';
494
                $links[] = $link;
495
            }
496
        }
497
        return implode(', ', $links);
498
    }
499
500
    /**
501
     * @return string $title
502
     */
503
    protected function getLocalizedPageTitle(): string
504
    {
505
        if ($this->current_sys_language > 0) {
506
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
507
                ->getQueryBuilderForTable('pages');
508
            $queryBuilder->getRestrictions()
509
                ->removeAll()
510
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
511
                ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
512
            $localizedPage = $queryBuilder
513
                ->select('*')
514
                ->from('pages')
515
                ->where(
516
                    $queryBuilder->expr()->eq(
517
                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
518
                        $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
519
                    ),
520
                    $queryBuilder->expr()->eq(
521
                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
522
                        $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
523
                    )
524
                )
525
                ->setMaxResults(1)
526
                ->execute()
527
                ->fetch();
528
            BackendUtility::workspaceOL('pages', $localizedPage);
529
            return $localizedPage['title'];
530
        }
531
        return $this->pageinfo['title'];
532
    }
533
534
    /**
535
     * Main function.
536
     * Creates some general objects and calls other functions for the main rendering of module content.
537
     *
538
     * @param ServerRequestInterface $request
539
     */
540
    protected function main(ServerRequestInterface $request): void
541
    {
542
        $content = '';
543
        // Access check...
544
        // The page will show only if there is a valid page and if this page may be viewed by the user
545
        if ($this->id && is_array($this->pageinfo)) {
546
            $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
547
548
            $this->moduleTemplate->addJavaScriptCode('mainJsFunctions', '
549
                if (top.fsMod) {
550
                    top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
551
                    top.fsMod.navFrameHighlightedID["web"] = top.fsMod.currentBank + "_" + ' . (int)$this->id . ';
552
                }
553
                function deleteRecord(table,id,url) {   //
554
                    window.location.href = ' . GeneralUtility::quoteJSvalue((string)$this->uriBuilder->buildUriFromRoute('tce_db') . '&cmd[')
555
                                            . ' + table + "][" + id + "][delete]=1&redirect=" + encodeURIComponent(url);
556
                    return false;
557
                }
558
            ');
559
560
            if ($this->context instanceof PageLayoutContext) {
561
                $backendLayout = $this->context->getBackendLayout();
562
563
                // Find backend layout / columns
564
                if (!empty($backendLayout->getColumnPositionNumbers())) {
565
                    $this->colPosList = implode(',', $backendLayout->getColumnPositionNumbers());
566
                }
567
                // Removing duplicates, if any
568
                $this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList));
0 ignored issues
show
Documentation Bug introduced by
It seems like array_unique(TYPO3\CMS\C...,', $this->colPosList)) of type array is incompatible with the declared type string of property $colPosList.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
569
                // Accessible columns
570
                if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
571
                    $this->activeColPosList = array_unique(GeneralUtility::intExplode(',', trim($this->modSharedTSconfig['properties']['colPos_list'])));
0 ignored issues
show
Documentation Bug introduced by
It seems like array_unique(TYPO3\CMS\C...ies']['colPos_list']))) of type array is incompatible with the declared type string of property $activeColPosList.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
572
                    // Match with the list which is present in the colPosList for the current page
573
                    if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
574
                        $this->activeColPosList = array_unique(array_intersect(
575
                            $this->activeColPosList,
576
                            $this->colPosList
577
                        ));
578
                    }
579
                } else {
580
                    $this->activeColPosList = $this->colPosList;
581
                }
582
                $this->activeColPosList = implode(',', $this->activeColPosList);
583
                $this->colPosList = implode(',', $this->colPosList);
584
            }
585
586
            $content .= $this->getHeaderFlashMessagesForCurrentPid();
587
588
            // Render the primary module content:
589
            $content .= '<form action="' . htmlspecialchars((string)$this->uriBuilder->buildUriFromRoute($this->moduleName, ['id' => $this->id])) . '" id="PageLayoutController" method="post">';
590
            // Page title
591
            $content .= '<h1 class="' . ($this->isPageEditable($this->current_sys_language) ? 't3js-title-inlineedit' : '') . '">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>';
592
            // All other listings
593
            $content .= $this->renderContent();
594
            $content .= '</form>';
595
            $content .= $this->searchContent;
596
            // Setting up the buttons for the docheader
597
            $this->makeButtons($request);
598
599
            // Create LanguageMenu
600
            $this->makeLanguageMenu();
601
        } else {
602
            $this->moduleTemplate->addJavaScriptCode(
603
                'mainJsFunctions',
604
                'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
605
            );
606
            $content .= '<h1>' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '</h1>';
607
            $view = GeneralUtility::makeInstance(StandaloneView::class);
608
            $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
609
            $view->assignMultiple([
610
                'title' => $this->getLanguageService()->getLL('clickAPage_header'),
611
                'message' => $this->getLanguageService()->getLL('clickAPage_content'),
612
                'state' => InfoboxViewHelper::STATE_INFO
613
            ]);
614
            $content .= $view->render();
615
        }
616
        // Set content
617
        $this->moduleTemplate->setContent($content);
618
    }
619
620
    /**
621
     * Rendering content
622
     *
623
     * @return string
624
     */
625
    protected function renderContent(): string
626
    {
627
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
628
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
629
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Localization');
630
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
631
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
632
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste');
633
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
634
635
        $tableOutput = '';
636
        $numberOfHiddenElements = 0;
637
638
        if ($this->context instanceof PageLayoutContext) {
639
            // Context may not be set, which happens if the page module is viewed by a user with no access to the
640
            // current page, or if the ID parameter is malformed. In this case we do not resolve any backend layout
641
            // or other page structure information and we do not render any "table output" for the module.
642
            $backendLayout = $this->context->getBackendLayout();
0 ignored issues
show
Unused Code introduced by
The assignment to $backendLayout is dead and can be removed.
Loading history...
643
644
            $configuration = $this->context->getDrawingConfiguration();
645
            $configuration->setDefaultLanguageBinding(!empty($this->modTSconfig['properties']['defLangBinding']));
646
            $configuration->setActiveColumns(GeneralUtility::trimExplode(',', $this->activeColPosList));
647
            $configuration->setShowHidden((bool)$this->MOD_SETTINGS['tt_content_showHidden']);
648
            $configuration->setLanguageColumns($this->MOD_MENU['language']);
649
            $configuration->setShowNewContentWizard(empty($this->modTSconfig['properties']['disableNewContentElementWizard']));
650
            $configuration->setSelectedLanguageId((int)$this->MOD_SETTINGS['language']);
651
            if ($this->MOD_SETTINGS['function'] == 2) {
652
                $configuration->setLanguageMode(true);
653
            }
654
655
            $numberOfHiddenElements = $this->getNumberOfHiddenElements($configuration->getLanguageColumns());
656
657
            $pageLayoutDrawer = $this->context->getBackendLayoutRenderer();
658
659
            $pageActionsCallback = null;
660
            if ($this->context->isPageEditable()) {
661
                $languageOverlayId = 0;
662
                $pageLocalizationRecord = BackendUtility::getRecordLocalization('pages', $this->id, (int)$this->current_sys_language);
663
                if (is_array($pageLocalizationRecord)) {
664
                    $pageLocalizationRecord = reset($pageLocalizationRecord);
665
                }
666
                if (!empty($pageLocalizationRecord['uid'])) {
667
                    $languageOverlayId = $pageLocalizationRecord['uid'];
668
                }
669
                $pageActionsCallback = 'function(PageActions) {
670
                    PageActions.setPageId(' . (int)$this->id . ');
671
                    PageActions.setLanguageOverlayId(' . $languageOverlayId . ');
672
                }';
673
            }
674
            $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', $pageActionsCallback);
675
            $tableOutput = $pageLayoutDrawer->drawContent();
676
        }
677
678
        if ($this->getBackendUser()->check('tables_select', 'tt_content') && $numberOfHiddenElements > 0) {
679
            // Toggle hidden ContentElements
680
            $tableOutput .= '
681
                <div class="form-check">
682
                    <input type="checkbox" id="checkTt_content_showHidden" class="form-check-input" name="SET[tt_content_showHidden]" value="1" ' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? 'checked="checked"' : '') . ' />
683
                    <label class="form-check-label" for="checkTt_content_showHidden">
684
                        ' . htmlspecialchars($this->getLanguageService()->getLL('hiddenCE')) . ' (<span class="t3js-hidden-counter">' . $numberOfHiddenElements . '</span>)
685
                    </label>
686
                </div>';
687
        }
688
689
        // Init the content
690
        $content = '';
691
        // Additional header content
692
        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'] ?? [] as $hook) {
693
            $params = [];
694
            $content .= GeneralUtility::callUserFunction($hook, $params, $this);
695
        }
696
        $content .= $tableOutput;
697
        // Making search form:
698
        $this->searchContent = $this->getSearchBox();
0 ignored issues
show
Bug introduced by
The method getSearchBox() 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

698
        /** @scrutinizer ignore-call */ 
699
        $this->searchContent = $this->getSearchBox();

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...
699
        if ($this->searchContent) {
700
            $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
701
            $toggleSearchFormButton = $this->buttonBar->makeLinkButton()
702
                ->setClasses('t3js-toggle-search-toolbox')
703
                ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
704
                ->setIcon($this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL))
705
                ->setHref('#');
706
            $this->buttonBar->addButton($toggleSearchFormButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
707
        }
708
        // Additional footer content
709
        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'] ?? [] as $hook) {
710
            $params = [];
711
            $content .= GeneralUtility::callUserFunction($hook, $params, $this);
712
        }
713
        return $content;
714
    }
715
716
    /***************************
717
     *
718
     * Sub-content functions, rendering specific parts of the module content.
719
     *
720
     ***************************/
721
    /**
722
     * This creates the buttons for the modules
723
     * @param ServerRequestInterface $request
724
     */
725
    protected function makeButtons(ServerRequestInterface $request): void
726
    {
727
        // Add CSH (Context Sensitive Help) icon to tool bar
728
        $contextSensitiveHelpButton = $this->buttonBar->makeHelpButton()
729
            ->setModuleName('_MOD_' . $this->moduleName)
730
            ->setFieldName('columns_' . $this->MOD_SETTINGS['function']);
731
        $this->buttonBar->addButton($contextSensitiveHelpButton);
732
        $lang = $this->getLanguageService();
733
        // View page
734
        $pageTsConfig = BackendUtility::getPagesTSconfig($this->id);
735
        // Exclude sysfolders, spacers and recycler by default
736
        $excludeDokTypes = [
737
            PageRepository::DOKTYPE_RECYCLER,
738
            PageRepository::DOKTYPE_SYSFOLDER,
739
            PageRepository::DOKTYPE_SPACER
740
        ];
741
        // Custom override of values
742
        if (isset($pageTsConfig['TCEMAIN.']['preview.']['disableButtonForDokType'])) {
743
            $excludeDokTypes = GeneralUtility::intExplode(
744
                ',',
745
                $pageTsConfig['TCEMAIN.']['preview.']['disableButtonForDokType'],
746
                true
747
            );
748
        }
749
750
        if (
751
            !in_array((int)$this->pageinfo['doktype'], $excludeDokTypes, true)
752
            && !VersionState::cast($this->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)
753
        ) {
754
            $languageParameter = $this->current_sys_language ? ('&L=' . $this->current_sys_language) : '';
755
            $previewDataAttributes = PreviewUriBuilder::create((int)$this->pageinfo['uid'])
756
                ->withRootLine(BackendUtility::BEgetRootLine($this->pageinfo['uid']))
757
                ->withAdditionalQueryParameters($languageParameter)
758
                ->buildDispatcherDataAttributes();
759
            $viewButton = $this->buttonBar->makeLinkButton()
760
                ->setDataAttributes($previewDataAttributes ?? [])
761
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
762
                ->setIcon($this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL))
763
                ->setHref('#');
764
765
            $this->buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
766
        }
767
        // Shortcut
768
        $shortcutButton = $this->buttonBar->makeShortcutButton()
769
            ->setRouteIdentifier($this->moduleName)
770
            ->setDisplayName($this->getShortcutTitle())
771
            ->setArguments([
772
                'id' => (int)$this->id,
773
                'SET' => [
774
                    'tt_content_showHidden' => (bool)$this->MOD_SETTINGS['tt_content_showHidden'],
775
                    'function' => (int)$this->MOD_SETTINGS['function'],
776
                    'language' => (int)$this->current_sys_language,
777
                ]
778
            ]);
779
        $this->buttonBar->addButton($shortcutButton);
780
781
        // Cache
782
        $clearCacheButton = $this->buttonBar->makeLinkButton()
783
            ->setHref('#')
784
            ->setDataAttributes(['id' => $this->pageinfo['uid']])
785
            ->setClasses('t3js-clear-page-cache')
786
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
787
            ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL));
788
        $this->buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
789
790
        // Edit page properties and page language overlay icons
791
        if ($this->isPageEditable(0)) {
792
            /** @var \TYPO3\CMS\Core\Http\NormalizedParams */
793
            $normalizedParams = $request->getAttribute('normalizedParams');
794
            // Edit localized pages only when one specific language is selected
795
            if ($this->MOD_SETTINGS['function'] == 1 && $this->current_sys_language > 0) {
796
                $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
797
                $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'];
798
                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
799
                    ->getQueryBuilderForTable('pages');
800
                $queryBuilder->getRestrictions()
801
                    ->removeAll()
802
                    ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
803
                    ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
804
                $overlayRecord = $queryBuilder
805
                    ->select('uid')
806
                    ->from('pages')
807
                    ->where(
808
                        $queryBuilder->expr()->eq(
809
                            $localizationParentField,
810
                            $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
811
                        ),
812
                        $queryBuilder->expr()->eq(
813
                            $languageField,
814
                            $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
815
                        )
816
                    )
817
                    ->setMaxResults(1)
818
                    ->execute()
819
                    ->fetch();
820
                BackendUtility::workspaceOL('pages', $overlayRecord, (int)$this->getBackendUser()->workspace);
821
                // Edit button
822
                $urlParameters = [
823
                    'edit' => [
824
                        'pages' => [
825
                            $overlayRecord['uid'] => 'edit'
826
                        ]
827
                    ],
828
                    'returnUrl' => $normalizedParams->getRequestUri(),
829
                ];
830
831
                $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
832
                $editLanguageButton = $this->buttonBar->makeLinkButton()
833
                    ->setHref($url)
834
                    ->setTitle($lang->getLL('editPageLanguageOverlayProperties'))
835
                    ->setIcon($this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL));
836
                $this->buttonBar->addButton($editLanguageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
837
            }
838
            $urlParameters = [
839
                'edit' => [
840
                    'pages' => [
841
                        $this->id => 'edit'
842
                    ]
843
                ],
844
                'returnUrl' => $normalizedParams->getRequestUri(),
845
            ];
846
            $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
847
            $editPageButton = $this->buttonBar->makeLinkButton()
848
                ->setHref($url)
849
                ->setTitle($lang->getLL('editPageProperties'))
850
                ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL));
851
            $this->buttonBar->addButton($editPageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
852
        }
853
    }
854
855
    /*******************************
856
     *
857
     * Other functions
858
     *
859
     ******************************/
860
    /**
861
     * Returns the number of hidden elements (including those hidden by start/end times)
862
     * on the current page (for the current sys_language)
863
     *
864
     * @param array $languageColumns
865
     * @return int
866
     */
867
    protected function getNumberOfHiddenElements(array $languageColumns): int
868
    {
869
        $andWhere = [];
870
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
871
        $queryBuilder->getRestrictions()
872
            ->removeAll()
873
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
874
            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
875
876
        $queryBuilder
877
            ->count('uid')
878
            ->from('tt_content')
879
            ->where(
880
                $queryBuilder->expr()->eq(
881
                    'pid',
882
                    $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
883
                )
884
            );
885
886
        if (!empty($languageColumns)) {
887
            // Multi-language view is active
888
            if ($this->current_sys_language > 0) {
889
                $queryBuilder->andWhere(
890
                    $queryBuilder->expr()->in(
891
                        'sys_language_uid',
892
                        [0, $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)]
893
                    )
894
                );
895
            }
896
        } else {
897
            $queryBuilder->andWhere(
898
                $queryBuilder->expr()->eq(
899
                    'sys_language_uid',
900
                    $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
901
                )
902
            );
903
        }
904
905
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'])) {
906
            $andWhere[] = $queryBuilder->expr()->neq(
907
                'hidden',
908
                $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
909
            );
910
        }
911
912
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'])) {
913
            $andWhere[] = $queryBuilder->expr()->andX(
914
                $queryBuilder->expr()->neq(
915
                    'starttime',
916
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
917
                ),
918
                $queryBuilder->expr()->gt(
919
                    'starttime',
920
                    $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
921
                )
922
            );
923
        }
924
925
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'])) {
926
            $andWhere[] = $queryBuilder->expr()->andX(
927
                $queryBuilder->expr()->neq(
928
                    'endtime',
929
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
930
                ),
931
                $queryBuilder->expr()->lte(
932
                    'endtime',
933
                    $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
934
                )
935
            );
936
        }
937
938
        if (!empty($andWhere)) {
939
            $queryBuilder->andWhere(
940
                $queryBuilder->expr()->orX(...$andWhere)
941
            );
942
        }
943
944
        $count = $queryBuilder
945
            ->execute()
946
            ->fetchColumn(0);
947
948
        return (int)$count;
949
    }
950
951
    /**
952
     * Check if page can be edited by current user
953
     *
954
     * @param int $languageId
955
     * @return bool
956
     */
957
    protected function isPageEditable(int $languageId): bool
958
    {
959
        if ($this->getBackendUser()->isAdmin()) {
960
            return true;
961
        }
962
963
        return !$this->pageinfo['editlock']
964
            && $this->getBackendUser()->doesUserHaveAccess($this->pageinfo, Permission::PAGE_EDIT)
0 ignored issues
show
Bug introduced by
It seems like $this->pageinfo can also be of type boolean; however, parameter $row of TYPO3\CMS\Core\Authentic...n::doesUserHaveAccess() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

964
            && $this->getBackendUser()->doesUserHaveAccess(/** @scrutinizer ignore-type */ $this->pageinfo, Permission::PAGE_EDIT)
Loading history...
965
            && $this->getBackendUser()->checkLanguageAccess($languageId);
966
    }
967
968
    /**
969
     * Check if content can be edited by current user
970
     *
971
     * @param int $languageId
972
     * @return bool
973
     */
974
    protected function isContentEditable(int $languageId): bool
975
    {
976
        if ($this->getBackendUser()->isAdmin()) {
977
            return true;
978
        }
979
980
        return !$this->pageinfo['editlock']
981
            && $this->getBackendUser()->doesUserHaveAccess($this->pageinfo, Permission::CONTENT_EDIT)
0 ignored issues
show
Bug introduced by
It seems like $this->pageinfo can also be of type boolean; however, parameter $row of TYPO3\CMS\Core\Authentic...n::doesUserHaveAccess() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

981
            && $this->getBackendUser()->doesUserHaveAccess(/** @scrutinizer ignore-type */ $this->pageinfo, Permission::CONTENT_EDIT)
Loading history...
982
            && $this->getBackendUser()->checkLanguageAccess($languageId);
983
    }
984
985
    /**
986
     * Returns LanguageService
987
     *
988
     * @return LanguageService
989
     */
990
    protected function getLanguageService(): LanguageService
991
    {
992
        return $GLOBALS['LANG'];
993
    }
994
995
    /**
996
     * Returns the current BE user.
997
     *
998
     * @return BackendUserAuthentication
999
     */
1000
    protected function getBackendUser(): BackendUserAuthentication
1001
    {
1002
        return $GLOBALS['BE_USER'];
1003
    }
1004
1005
    /**
1006
     * Make the LanguageMenu
1007
     */
1008
    protected function makeLanguageMenu(): void
1009
    {
1010
        if (count($this->MOD_MENU['language']) > 1) {
1011
            $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
1012
            $languageMenu->setIdentifier('languageMenu');
1013
            foreach ($this->MOD_MENU['language'] as $key => $language) {
1014
                $menuItem = $languageMenu
1015
                    ->makeMenuItem()
1016
                    ->setTitle($language)
1017
                    ->setHref((string)$this->uriBuilder->buildUriFromRoute($this->moduleName) . '&id=' . $this->id . '&SET[language]=' . $key);
1018
                if ((int)$this->current_sys_language === $key) {
1019
                    $menuItem->setActive(true);
1020
                }
1021
                $languageMenu->addMenuItem($menuItem);
1022
            }
1023
            $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
1024
        }
1025
    }
1026
1027
    /**
1028
     * Returns the target page if visible
1029
     *
1030
     * @param array $targetPage
1031
     *
1032
     * @return array
1033
     */
1034
    protected function getTargetPageIfVisible(array $targetPage): array
1035
    {
1036
        return !(bool)($targetPage['hidden'] ?? false) ? $targetPage : [];
1037
    }
1038
1039
    /**
1040
     * Creates the search box
1041
     *
1042
     * @return string HTML for the search box
1043
     */
1044
    protected function getSearchBox(): string
1045
    {
1046
        if (!$this->getBackendUser()->check('modules', 'web_list')) {
1047
            return '';
1048
        }
1049
1050
        $dbList = GeneralUtility::makeInstance(DatabaseRecordList::class);
1051
        $dbList->start($this->id, '', '');
1052
        $formUrl = $this->uriBuilder->buildUriFromRoute('web_list', ['id' => $this->id]);
1053
1054
        return '<div class="module-docheader-bar t3js-module-docheader-bar t3js-module-docheader-bar-search" id="db_list-searchbox-toolbar" style="display: none;"><div class="panel panel-default"><div class="p-2 ps-4">' . $dbList->getSearchBox((string)$formUrl) . '</div></div></div>';
1055
    }
1056
1057
    /**
1058
     * Returns the shortcut title for the current page
1059
     *
1060
     * @return string
1061
     */
1062
    protected function getShortcutTitle(): string
1063
    {
1064
        return sprintf(
1065
            '%s: %s [%d]',
1066
            $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tablabel'),
1067
            BackendUtility::getRecordTitle('pages', (array)$this->pageinfo),
1068
            $this->id
1069
        );
1070
    }
1071
}
1072