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

PageLayoutController::makeActionMenu()   A

Complexity

Conditions 5
Paths 10

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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

403
                    $linkedPath = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars(/** @scrutinizer ignore-type */ $path) . '</a>';
Loading history...
404
                    $message .= sprintf(htmlspecialchars($lang->getLL('pageIsInternalLinkMessage')), $linkedPath);
405
                    $message .= ' (' . htmlspecialchars($lang->sL(BackendUtility::getLabelFromItemlist('pages', 'shortcut_mode', (string)$shortcutMode))) . ')';
406
                    $state = InfoboxViewHelper::STATE_INFO;
407
                }
408
            } else {
409
                $message = htmlspecialchars($lang->getLL('pageIsMisconfiguredInternalLinkMessage'));
410
                $state = InfoboxViewHelper::STATE_ERROR;
411
            }
412
413
            $view->assignMultiple([
414
                'title' => $this->pageinfo['title'],
415
                'message' => $message,
416
                'state' => $state
417
            ]);
418
            $content .= $view->render();
419
        } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_LINK) {
420
            if (empty($this->pageinfo['url'])) {
421
                $view->assignMultiple([
422
                    'title' => $this->pageinfo['title'],
423
                    'message' => $lang->getLL('pageIsMisconfiguredExternalLinkMessage'),
424
                    'state' => InfoboxViewHelper::STATE_ERROR
425
                ]);
426
                $content .= $view->render();
427
            } else {
428
                $externalUrl = GeneralUtility::makeInstance(PageRepository::class)->getExtURL($this->pageinfo);
429
                if (is_string($externalUrl)) {
430
                    $externalUrl = htmlspecialchars($externalUrl);
431
                    $externalUrlHtml = '<a href="' . $externalUrl . '" target="_blank" rel="noreferrer">' . $externalUrl . '</a>';
432
                    $view->assignMultiple([
433
                        'title' => $this->pageinfo['title'],
434
                        'message' => sprintf($lang->getLL('pageIsExternalLinkMessage'), $externalUrlHtml),
435
                        'state' => InfoboxViewHelper::STATE_INFO
436
                    ]);
437
                    $content .= $view->render();
438
                }
439
            }
440
        }
441
        // If content from different pid is displayed
442
        if ($this->pageinfo['content_from_pid']) {
443
            $contentPage = (array)BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
444
            $linkToPid = GeneralUtility::linkThisScript(['id' => $this->pageinfo['content_from_pid']]);
445
            $title = BackendUtility::getRecordTitle('pages', $contentPage);
446
            $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
447
            $message = sprintf($lang->getLL('content_from_pid_title'), $link);
448
            $view->assignMultiple([
449
                'title' => $title,
450
                'message' => $message,
451
                'state' => InfoboxViewHelper::STATE_INFO
452
            ]);
453
            $content .= $view->render();
454
        } else {
455
            $links = $this->getPageLinksWhereContentIsAlsoShownOn($this->pageinfo['uid']);
456
            if (!empty($links)) {
457
                $message = sprintf($lang->getLL('content_on_pid_title'), $links);
458
                $view->assignMultiple([
459
                    'title' => '',
460
                    'message' => $message,
461
                    'state' => InfoboxViewHelper::STATE_INFO
462
                ]);
463
                $content .= $view->render();
464
            }
465
        }
466
        return $content;
467
    }
468
469
    /**
470
     * Get all pages with links where the content of a page $pageId is also shown on
471
     *
472
     * @param int $pageId
473
     * @return string
474
     */
475
    protected function getPageLinksWhereContentIsAlsoShownOn($pageId): string
476
    {
477
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
478
        $queryBuilder->getRestrictions()->removeAll();
479
        $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
480
        $queryBuilder
481
            ->select('*')
482
            ->from('pages')
483
            ->where($queryBuilder->expr()->eq('content_from_pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)));
484
485
        $links = [];
486
        $rows = $queryBuilder->execute()->fetchAll();
487
        if (!empty($rows)) {
488
            foreach ($rows as $row) {
489
                $linkToPid = GeneralUtility::linkThisScript(['id' => $row['uid']]);
490
                $title = BackendUtility::getRecordTitle('pages', $row);
491
                $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$row['uid'] . ')</a>';
492
                $links[] = $link;
493
            }
494
        }
495
        return implode(', ', $links);
496
    }
497
498
    /**
499
     * @return string $title
500
     */
501
    protected function getLocalizedPageTitle(): string
502
    {
503
        if ($this->current_sys_language > 0) {
504
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
505
                ->getQueryBuilderForTable('pages');
506
            $queryBuilder->getRestrictions()
507
                ->removeAll()
508
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
509
                ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
510
            $localizedPage = $queryBuilder
511
                ->select('*')
512
                ->from('pages')
513
                ->where(
514
                    $queryBuilder->expr()->eq(
515
                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
516
                        $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
517
                    ),
518
                    $queryBuilder->expr()->eq(
519
                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
520
                        $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
521
                    )
522
                )
523
                ->setMaxResults(1)
524
                ->execute()
525
                ->fetch();
526
            BackendUtility::workspaceOL('pages', $localizedPage);
527
            return $localizedPage['title'];
528
        }
529
        return $this->pageinfo['title'];
530
    }
531
532
    /**
533
     * Main function.
534
     * Creates some general objects and calls other functions for the main rendering of module content.
535
     *
536
     * @param ServerRequestInterface $request
537
     */
538
    protected function main(ServerRequestInterface $request): void
539
    {
540
        $content = '';
541
        // Access check...
542
        // The page will show only if there is a valid page and if this page may be viewed by the user
543
        if ($this->id && is_array($this->pageinfo)) {
544
            $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
545
546
            $this->moduleTemplate->addJavaScriptCode('mainJsFunctions', '
547
                if (top.fsMod) {
548
                    top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
549
                    top.fsMod.navFrameHighlightedID["web"] = top.fsMod.currentBank + "_" + ' . (int)$this->id . ';
550
                }
551
                function deleteRecord(table,id,url) {   //
552
                    window.location.href = ' . GeneralUtility::quoteJSvalue((string)$this->uriBuilder->buildUriFromRoute('tce_db') . '&cmd[')
553
                                            . ' + table + "][" + id + "][delete]=1&redirect=" + encodeURIComponent(url);
554
                    return false;
555
                }
556
            ');
557
558
            if ($this->context instanceof PageLayoutContext) {
559
                $backendLayout = $this->context->getBackendLayout();
560
561
                // Find backend layout / columns
562
                if (!empty($backendLayout->getColumnPositionNumbers())) {
563
                    $this->colPosList = implode(',', $backendLayout->getColumnPositionNumbers());
564
                }
565
                // Removing duplicates, if any
566
                $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...
567
                // Accessible columns
568
                if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
569
                    $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...
570
                    // Match with the list which is present in the colPosList for the current page
571
                    if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
572
                        $this->activeColPosList = array_unique(array_intersect(
573
                            $this->activeColPosList,
574
                            $this->colPosList
575
                        ));
576
                    }
577
                } else {
578
                    $this->activeColPosList = $this->colPosList;
579
                }
580
                $this->activeColPosList = implode(',', $this->activeColPosList);
581
                $this->colPosList = implode(',', $this->colPosList);
582
            }
583
584
            $content .= $this->getHeaderFlashMessagesForCurrentPid();
585
586
            // Render the primary module content:
587
            $content .= '<form action="' . htmlspecialchars((string)$this->uriBuilder->buildUriFromRoute($this->moduleName, ['id' => $this->id])) . '" id="PageLayoutController" method="post">';
588
            // Page title
589
            $content .= '<h1 class="' . ($this->isPageEditable($this->current_sys_language) ? 't3js-title-inlineedit' : '') . '">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>';
590
            // All other listings
591
            $content .= $this->renderContent();
592
            $content .= '</form>';
593
            $content .= $this->searchContent;
594
            // Setting up the buttons for the docheader
595
            $this->makeButtons($request);
596
597
            // Create LanguageMenu
598
            $this->makeLanguageMenu();
599
        } else {
600
            $this->moduleTemplate->addJavaScriptCode(
601
                'mainJsFunctions',
602
                'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
603
            );
604
            $content .= '<h1>' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '</h1>';
605
            $view = GeneralUtility::makeInstance(StandaloneView::class);
606
            $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
607
            $view->assignMultiple([
608
                'title' => $this->getLanguageService()->getLL('clickAPage_header'),
609
                'message' => $this->getLanguageService()->getLL('clickAPage_content'),
610
                'state' => InfoboxViewHelper::STATE_INFO
611
            ]);
612
            $content .= $view->render();
613
        }
614
        // Set content
615
        $this->moduleTemplate->setContent($content);
616
    }
617
618
    /**
619
     * Rendering content
620
     *
621
     * @return string
622
     */
623
    protected function renderContent(): string
624
    {
625
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
626
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
627
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Localization');
628
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
629
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
630
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste');
631
        $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
632
633
        $tableOutput = '';
634
        $numberOfHiddenElements = 0;
635
636
        if ($this->context instanceof PageLayoutContext) {
637
            // Context may not be set, which happens if the page module is viewed by a user with no access to the
638
            // current page, or if the ID parameter is malformed. In this case we do not resolve any backend layout
639
            // or other page structure information and we do not render any "table output" for the module.
640
            $backendLayout = $this->context->getBackendLayout();
0 ignored issues
show
Unused Code introduced by
The assignment to $backendLayout is dead and can be removed.
Loading history...
641
642
            $configuration = $this->context->getDrawingConfiguration();
643
            $configuration->setDefaultLanguageBinding(!empty($this->modTSconfig['properties']['defLangBinding']));
644
            $configuration->setActiveColumns(GeneralUtility::trimExplode(',', $this->activeColPosList));
645
            $configuration->setShowHidden((bool)$this->MOD_SETTINGS['tt_content_showHidden']);
646
            $configuration->setLanguageColumns($this->MOD_MENU['language']);
647
            $configuration->setShowNewContentWizard(empty($this->modTSconfig['properties']['disableNewContentElementWizard']));
648
            $configuration->setSelectedLanguageId((int)$this->MOD_SETTINGS['language']);
649
            if ($this->MOD_SETTINGS['function'] == 2) {
650
                $configuration->setLanguageMode(true);
651
            }
652
653
            $numberOfHiddenElements = $this->getNumberOfHiddenElements($configuration->getLanguageColumns());
654
655
            $pageLayoutDrawer = $this->context->getBackendLayoutRenderer();
656
657
            $pageActionsCallback = null;
658
            if ($this->context->isPageEditable()) {
659
                $languageOverlayId = 0;
660
                $pageLocalizationRecord = BackendUtility::getRecordLocalization('pages', $this->id, (int)$this->current_sys_language);
661
                if (is_array($pageLocalizationRecord)) {
662
                    $pageLocalizationRecord = reset($pageLocalizationRecord);
663
                }
664
                if (!empty($pageLocalizationRecord['uid'])) {
665
                    $languageOverlayId = $pageLocalizationRecord['uid'];
666
                }
667
                $pageActionsCallback = 'function(PageActions) {
668
                    PageActions.setPageId(' . (int)$this->id . ');
669
                    PageActions.setLanguageOverlayId(' . $languageOverlayId . ');
670
                }';
671
            }
672
            $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', $pageActionsCallback);
673
            $tableOutput = $pageLayoutDrawer->drawContent();
674
        }
675
676
        if ($this->getBackendUser()->check('tables_select', 'tt_content') && $numberOfHiddenElements > 0) {
677
            // Toggle hidden ContentElements
678
            $tableOutput .= '
679
                <div class="checkbox">
680
                    <label for="checkTt_content_showHidden">
681
                        <input type="checkbox" id="checkTt_content_showHidden" class="checkbox" name="SET[tt_content_showHidden]" value="1" ' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? 'checked="checked"' : '') . ' />
682
                        ' . htmlspecialchars($this->getLanguageService()->getLL('hiddenCE')) . ' (<span class="t3js-hidden-counter">' . $numberOfHiddenElements . '</span>)
683
                    </label>
684
                </div>';
685
        }
686
687
        // Init the content
688
        $content = '';
689
        // Additional header content
690
        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'] ?? [] as $hook) {
691
            $params = [];
692
            $content .= GeneralUtility::callUserFunction($hook, $params, $this);
693
        }
694
        $content .= $tableOutput;
695
        // Making search form:
696
        if (!$this->modTSconfig['properties']['disableSearchBox']) {
697
            $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

697
            /** @scrutinizer ignore-call */ 
698
            $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...
698
            if ($this->searchContent) {
699
                $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
700
                $toggleSearchFormButton = $this->buttonBar->makeLinkButton()
701
                    ->setClasses('t3js-toggle-search-toolbox')
702
                    ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
703
                    ->setIcon($this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL))
704
                    ->setHref('#');
705
                $this->buttonBar->addButton($toggleSearchFormButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
706
            }
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
            ->setModuleName($this->moduleName)
770
            ->setDisplayName($this->getShortcutTitle())
771
            ->setArguments([
772
                'route' => $request->getQueryParams()['route'],
773
                'id' => (int)$this->id,
774
                'SET' => [
775
                    'tt_content_showHidden' => (bool)$this->MOD_SETTINGS['tt_content_showHidden'],
776
                    'function' => (int)$this->MOD_SETTINGS['function'],
777
                    'language' => (int)$this->current_sys_language,
778
                ]
779
            ]);
780
        $this->buttonBar->addButton($shortcutButton);
781
782
        // Cache
783
        $clearCacheButton = $this->buttonBar->makeLinkButton()
784
            ->setHref('#')
785
            ->setDataAttributes(['id' => $this->pageinfo['uid']])
786
            ->setClasses('t3js-clear-page-cache')
787
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
788
            ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL));
789
        $this->buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
790
791
        if (empty($this->modTSconfig['properties']['disableIconToolbar'])) {
792
            // Edit page properties and page language overlay icons
793
            if ($this->isPageEditable(0)) {
794
                /** @var \TYPO3\CMS\Core\Http\NormalizedParams */
795
                $normalizedParams = $request->getAttribute('normalizedParams');
796
                // Edit localized pages only when one specific language is selected
797
                if ($this->MOD_SETTINGS['function'] == 1 && $this->current_sys_language > 0) {
798
                    $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
799
                    $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'];
800
                    $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
801
                        ->getQueryBuilderForTable('pages');
802
                    $queryBuilder->getRestrictions()
803
                        ->removeAll()
804
                        ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
805
                        ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
806
                    $overlayRecord = $queryBuilder
807
                        ->select('uid')
808
                        ->from('pages')
809
                        ->where(
810
                            $queryBuilder->expr()->eq(
811
                                $localizationParentField,
812
                                $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
813
                            ),
814
                            $queryBuilder->expr()->eq(
815
                                $languageField,
816
                                $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
817
                            )
818
                        )
819
                        ->setMaxResults(1)
820
                        ->execute()
821
                        ->fetch();
822
                    BackendUtility::workspaceOL('pages', $overlayRecord, (int)$this->getBackendUser()->workspace);
823
                    // Edit button
824
                    $urlParameters = [
825
                        'edit' => [
826
                            'pages' => [
827
                                $overlayRecord['uid'] => 'edit'
828
                            ]
829
                        ],
830
                        'returnUrl' => $normalizedParams->getRequestUri(),
831
                    ];
832
833
                    $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
834
                    $editLanguageButton = $this->buttonBar->makeLinkButton()
835
                        ->setHref($url)
836
                        ->setTitle($lang->getLL('editPageLanguageOverlayProperties'))
837
                        ->setIcon($this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL));
838
                    $this->buttonBar->addButton($editLanguageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
839
                }
840
                $urlParameters = [
841
                    'edit' => [
842
                        'pages' => [
843
                            $this->id => 'edit'
844
                        ]
845
                    ],
846
                    'returnUrl' => $normalizedParams->getRequestUri(),
847
                ];
848
                $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
849
                $editPageButton = $this->buttonBar->makeLinkButton()
850
                    ->setHref($url)
851
                    ->setTitle($lang->getLL('editPageProperties'))
852
                    ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL));
853
                $this->buttonBar->addButton($editPageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
854
            }
855
        }
856
    }
857
858
    /*******************************
859
     *
860
     * Other functions
861
     *
862
     ******************************/
863
    /**
864
     * Returns the number of hidden elements (including those hidden by start/end times)
865
     * on the current page (for the current sys_language)
866
     *
867
     * @param array $languageColumns
868
     * @return int
869
     */
870
    protected function getNumberOfHiddenElements(array $languageColumns): int
871
    {
872
        $andWhere = [];
873
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
874
        $queryBuilder->getRestrictions()
875
            ->removeAll()
876
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
877
            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
878
879
        $queryBuilder
880
            ->count('uid')
881
            ->from('tt_content')
882
            ->where(
883
                $queryBuilder->expr()->eq(
884
                    'pid',
885
                    $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
886
                )
887
            );
888
889
        if (!empty($languageColumns)) {
890
            // Multi-language view is active
891
            if ($this->current_sys_language > 0) {
892
                $queryBuilder->andWhere(
893
                    $queryBuilder->expr()->in(
894
                        'sys_language_uid',
895
                        [0, $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)]
896
                    )
897
                );
898
            }
899
        } else {
900
            $queryBuilder->andWhere(
901
                $queryBuilder->expr()->eq(
902
                    'sys_language_uid',
903
                    $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
904
                )
905
            );
906
        }
907
908
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'])) {
909
            $andWhere[] = $queryBuilder->expr()->neq(
910
                'hidden',
911
                $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
912
            );
913
        }
914
915
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'])) {
916
            $andWhere[] = $queryBuilder->expr()->andX(
917
                $queryBuilder->expr()->neq(
918
                    'starttime',
919
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
920
                ),
921
                $queryBuilder->expr()->gt(
922
                    'starttime',
923
                    $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
924
                )
925
            );
926
        }
927
928
        if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'])) {
929
            $andWhere[] = $queryBuilder->expr()->andX(
930
                $queryBuilder->expr()->neq(
931
                    'endtime',
932
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
933
                ),
934
                $queryBuilder->expr()->lte(
935
                    'endtime',
936
                    $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
937
                )
938
            );
939
        }
940
941
        if (!empty($andWhere)) {
942
            $queryBuilder->andWhere(
943
                $queryBuilder->expr()->orX(...$andWhere)
944
            );
945
        }
946
947
        $count = $queryBuilder
948
            ->execute()
949
            ->fetchColumn(0);
950
951
        return (int)$count;
952
    }
953
954
    /**
955
     * Check if page can be edited by current user
956
     *
957
     * @param int $languageId
958
     * @return bool
959
     */
960
    protected function isPageEditable(int $languageId): bool
961
    {
962
        if ($this->getBackendUser()->isAdmin()) {
963
            return true;
964
        }
965
966
        return !$this->pageinfo['editlock']
967
            && $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

967
            && $this->getBackendUser()->doesUserHaveAccess(/** @scrutinizer ignore-type */ $this->pageinfo, Permission::PAGE_EDIT)
Loading history...
968
            && $this->getBackendUser()->checkLanguageAccess($languageId);
969
    }
970
971
    /**
972
     * Check if content can be edited by current user
973
     *
974
     * @param int $languageId
975
     * @return bool
976
     */
977
    protected function isContentEditable(int $languageId): bool
978
    {
979
        if ($this->getBackendUser()->isAdmin()) {
980
            return true;
981
        }
982
983
        return !$this->pageinfo['editlock']
984
            && $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

984
            && $this->getBackendUser()->doesUserHaveAccess(/** @scrutinizer ignore-type */ $this->pageinfo, Permission::CONTENT_EDIT)
Loading history...
985
            && $this->getBackendUser()->checkLanguageAccess($languageId);
986
    }
987
988
    /**
989
     * Returns LanguageService
990
     *
991
     * @return LanguageService
992
     */
993
    protected function getLanguageService(): LanguageService
994
    {
995
        return $GLOBALS['LANG'];
996
    }
997
998
    /**
999
     * Returns the current BE user.
1000
     *
1001
     * @return BackendUserAuthentication
1002
     */
1003
    protected function getBackendUser(): BackendUserAuthentication
1004
    {
1005
        return $GLOBALS['BE_USER'];
1006
    }
1007
1008
    /**
1009
     * Make the LanguageMenu
1010
     */
1011
    protected function makeLanguageMenu(): void
1012
    {
1013
        if (count($this->MOD_MENU['language']) > 1) {
1014
            $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
1015
            $languageMenu->setIdentifier('languageMenu');
1016
            foreach ($this->MOD_MENU['language'] as $key => $language) {
1017
                $menuItem = $languageMenu
1018
                    ->makeMenuItem()
1019
                    ->setTitle($language)
1020
                    ->setHref((string)$this->uriBuilder->buildUriFromRoute($this->moduleName) . '&id=' . $this->id . '&SET[language]=' . $key);
1021
                if ((int)$this->current_sys_language === $key) {
1022
                    $menuItem->setActive(true);
1023
                }
1024
                $languageMenu->addMenuItem($menuItem);
1025
            }
1026
            $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
1027
        }
1028
    }
1029
1030
    /**
1031
     * Returns the target page if visible
1032
     *
1033
     * @param array $targetPage
1034
     *
1035
     * @return array
1036
     */
1037
    protected function getTargetPageIfVisible(array $targetPage): array
1038
    {
1039
        return !(bool)($targetPage['hidden'] ?? false) ? $targetPage : [];
1040
    }
1041
1042
    /**
1043
     * Creates the search box
1044
     *
1045
     * @return string HTML for the search box
1046
     */
1047
    protected function getSearchBox(): string
1048
    {
1049
        if (!$this->getBackendUser()->check('modules', 'web_list')) {
1050
            return '';
1051
        }
1052
        $lang = $this->getLanguageService();
1053
        $listModule = $this->uriBuilder->buildUriFromRoute('web_list', ['id' => $this->id]);
1054
        // Make level selector:
1055
        $opt = [];
1056
1057
        // "New" generation of search levels ... based on TS config
1058
        $config = BackendUtility::getPagesTSconfig($this->id);
1059
        $searchLevelsFromTSconfig = $config['mod.']['web_list.']['searchLevel.']['items.'];
1060
        $searchLevelItems = [];
1061
1062
        // get translated labels for search levels from pagets
1063
        foreach ($searchLevelsFromTSconfig as $keySearchLevel => $labelConfigured) {
1064
            $label = $lang->sL('LLL:' . $labelConfigured);
1065
            if ($label === '') {
1066
                $label = $labelConfigured;
1067
            }
1068
            $searchLevelItems[$keySearchLevel] = $label;
1069
        }
1070
1071
        foreach ($searchLevelItems as $kv => $label) {
1072
            $opt[] = '<option value="' . $kv . '"' . ($kv === 0 ? ' selected="selected"' : '') . '>'
1073
                . htmlspecialchars($label)
1074
                . '</option>';
1075
        }
1076
        $searchLevelLabel = $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search_levels');
1077
        $searchStringLabel = $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.searchString');
1078
        $lMenu = '<select class="form-control" name="search_levels" title="' . htmlspecialchars($searchLevelLabel) . '" id="search_levels">' . implode('', $opt) . '</select>';
1079
        return '<div class="db_list-searchbox-form db_list-searchbox-toolbar module-docheader-bar module-docheader-bar-search t3js-module-docheader-bar t3js-module-docheader-bar-search" id="db_list-searchbox-toolbar" style="display: none;">
1080
			<form action="' . htmlspecialchars((string)$listModule) . '" method="post">
1081
                <div id="typo3-dblist-search">
1082
                    <div class="panel panel-default">
1083
                        <div class="panel-body">
1084
                            <div class="row">
1085
                                <div class="form-group col-xs-12">
1086
                                    <label for="search_field">' . htmlspecialchars($searchStringLabel) . ': </label>
1087
									<input class="form-control" type="search" placeholder="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchString')) . '" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchString')) . '" name="search_field" id="search_field" value="" />
1088
                                </div>
1089
                                <div class="form-group col-xs-12 col-sm-6">
1090
									<label for="search_levels">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.search_levels')) . ': </label>
1091
									' . $lMenu . '
1092
                                </div>
1093
                                <div class="form-group col-xs-12 col-sm-6">
1094
									<label for="showLimit">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.limit')) . ': </label>
1095
									<input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.limit')) . '" name="showLimit" id="showLimit" value="" />
1096
                                </div>
1097
                                <div class="form-group col-xs-12">
1098
                                    <div class="form-control-wrap">
1099
                                        <button type="submit" class="btn btn-default" name="search" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search')) . '">
1100
                                            ' . $this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.search')) . '
1101
                                        </button>
1102
                                    </div>
1103
                                </div>
1104
                            </div>
1105
                        </div>
1106
                    </div>
1107
                </div>
1108
            </form>
1109
        </div>';
1110
    }
1111
1112
    /**
1113
     * Returns the shortcut title for the current page
1114
     *
1115
     * @return string
1116
     */
1117
    protected function getShortcutTitle(): string
1118
    {
1119
        return sprintf(
1120
            '%s: %s [%d]',
1121
            $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tablabel'),
1122
            BackendUtility::getRecordTitle('pages', $this->pageinfo),
0 ignored issues
show
Bug introduced by
It seems like $this->pageinfo can also be of type boolean; however, parameter $row of TYPO3\CMS\Backend\Utilit...ility::getRecordTitle() 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

1122
            BackendUtility::getRecordTitle('pages', /** @scrutinizer ignore-type */ $this->pageinfo),
Loading history...
1123
            $this->id
1124
        );
1125
    }
1126
}
1127