8de4e4f3f9784612635b84c3e4bc3b432058d20d
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / PageLayoutController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\ModuleLoader;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Backend\View\BackendLayoutView;
24 use TYPO3\CMS\Backend\View\PageLayoutView;
25 use TYPO3\CMS\Core\Database\ConnectionPool;
26 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
27 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
28 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
29 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
30 use TYPO3\CMS\Core\DataHandling\DataHandler;
31 use TYPO3\CMS\Core\Imaging\Icon;
32 use TYPO3\CMS\Core\Imaging\IconFactory;
33 use TYPO3\CMS\Core\Page\PageRenderer;
34 use TYPO3\CMS\Core\Type\Bitmask\Permission;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36 use TYPO3\CMS\Core\Utility\MathUtility;
37 use TYPO3\CMS\Core\Versioning\VersionState;
38 use TYPO3\CMS\Fluid\View\StandaloneView;
39 use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
40 use TYPO3\CMS\Frontend\Page\PageRepository;
41 use TYPO3\CMS\Recordlist\RecordList;
42
43 /**
44 * Script Class for Web > Layout module
45 */
46 class PageLayoutController
47 {
48 /**
49 * Page Id for which to make the listing
50 *
51 * @var int
52 */
53 public $id;
54
55 /**
56 * Pointer - for browsing list of records.
57 *
58 * @var int
59 */
60 public $pointer;
61
62 /**
63 * Thumbnails or not
64 *
65 * @var string
66 */
67 public $imagemode;
68
69 /**
70 * Search-fields
71 *
72 * @var string
73 */
74 public $search_field;
75
76 /**
77 * Search-levels
78 *
79 * @var int
80 */
81 public $search_levels;
82
83 /**
84 * Show-limit
85 *
86 * @var int
87 */
88 public $showLimit;
89
90 /**
91 * Return URL
92 *
93 * @var string
94 */
95 public $returnUrl;
96
97 /**
98 * Clear-cache flag - if set, clears page cache for current id.
99 *
100 * @var bool
101 */
102 public $clear_cache;
103
104 /**
105 * PopView id - for opening a window with the page
106 *
107 * @var bool
108 */
109 public $popView;
110
111 /**
112 * QuickEdit: Variable, that tells quick edit what to show/edit etc.
113 * Format is [tablename]:[uid] with some exceptional values for both parameters (with special meanings).
114 *
115 * @var string
116 * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9.
117 */
118 public $edit_record;
119
120 /**
121 * QuickEdit: If set, this variable tells quick edit that the last edited record had
122 * this value as UID and we should look up the new, real uid value in sys_log.
123 *
124 * @var string
125 * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9.
126 */
127 public $new_unique_uid;
128
129 /**
130 * Page select perms clause
131 *
132 * @var string
133 */
134 public $perms_clause;
135
136 /**
137 * Module TSconfig
138 *
139 * @var array
140 */
141 public $modTSconfig;
142
143 /**
144 * Module shared TSconfig
145 *
146 * @var array
147 */
148 public $modSharedTSconfig;
149
150 /**
151 * Current ids page record
152 *
153 * @var array
154 */
155 public $pageinfo;
156
157 /**
158
159 * "Pseudo" Description -table name
160 *
161 * @var string
162 */
163 public $descrTable;
164
165 /**
166 * List of column-integers to edit. Is set from TSconfig, default is "1,0,2,3"
167 *
168 * @var string
169 */
170 public $colPosList;
171
172 /**
173 * Flag: If content can be edited or not.
174 *
175 * @var bool
176 */
177 public $EDIT_CONTENT;
178
179 /**
180 * Users permissions integer for this page.
181 *
182 * @var int
183 */
184 public $CALC_PERMS;
185
186 /**
187 * Currently selected language for editing content elements
188 *
189 * @var int
190 */
191 public $current_sys_language;
192
193 /**
194 * Module configuration
195 *
196 * @var array
197 */
198 public $MCONF = [];
199
200 /**
201 * Menu configuration
202 *
203 * @var array
204 */
205 public $MOD_MENU = [];
206
207 /**
208 * Module settings (session variable)
209 *
210 * @var array
211 */
212 public $MOD_SETTINGS = [];
213
214 /**
215 * Array of tables to be listed by the Web > Page module in addition to the default tables
216 *
217 * @var array
218 * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9.
219 */
220 public $externalTables = [];
221
222 /**
223 * Module output accumulation
224 *
225 * @var string
226 */
227 public $content;
228
229 /**
230 * List of column-integers accessible to the current BE user.
231 * Is set from TSconfig, default is $colPosList
232 *
233 * @var string
234 */
235 public $activeColPosList;
236
237 /**
238 * @var string
239 */
240 protected $editSelect;
241
242 /**
243 * Caches the available languages in a colPos
244 *
245 * @var array
246 */
247 protected $languagesInColumnCache = [];
248
249 /**
250 * @var IconFactory
251 */
252 protected $iconFactory;
253
254 /**
255 * The name of the module
256 *
257 * @var string
258 */
259 protected $moduleName = 'web_layout';
260
261 /**
262 * @var ModuleTemplate
263 */
264 protected $moduleTemplate;
265
266 /**
267 * @var ButtonBar
268 */
269 protected $buttonBar;
270
271 /**
272 * @var string
273 */
274 protected $searchContent;
275
276 /**
277 * Initializing the module
278 *
279 * @return void
280 */
281 public function init()
282 {
283 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
284 $this->iconFactory = $this->moduleTemplate->getIconFactory();
285 $this->buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
286 $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
287 // Setting module configuration / page select clause
288 $this->MCONF['name'] = $this->moduleName;
289 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
290 // Get session data
291 $sessionData = $this->getBackendUser()->getSessionData(RecordList::class);
292 $this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
293 // GPvars:
294 $this->id = (int)GeneralUtility::_GP('id');
295 $this->pointer = GeneralUtility::_GP('pointer');
296 $this->imagemode = GeneralUtility::_GP('imagemode');
297 $this->clear_cache = GeneralUtility::_GP('clear_cache');
298 $this->popView = GeneralUtility::_GP('popView');
299 $this->edit_record = GeneralUtility::_GP('edit_record');
300 $this->new_unique_uid = GeneralUtility::_GP('new_unique_uid');
301 $this->search_field = GeneralUtility::_GP('search_field');
302 $this->search_levels = GeneralUtility::_GP('search_levels');
303 $this->showLimit = GeneralUtility::_GP('showLimit');
304 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
305 $this->externalTables = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables'];
306 $sessionData['search_field'] = $this->search_field;
307 // Store session data
308 $this->getBackendUser()->setAndSaveSessionData(RecordList::class, $sessionData);
309 // Load page info array:
310 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
311 // Initialize menu
312 $this->menuConfig();
313 // Setting sys language from session var:
314 $this->current_sys_language = (int)$this->MOD_SETTINGS['language'];
315 // CSH / Descriptions:
316 $this->descrTable = '_MOD_' . $this->moduleName;
317 }
318
319 /**
320 * Initialize menu array
321 *
322 * @return void
323 */
324 public function menuConfig()
325 {
326 $lang = $this->getLanguageService();
327 // MENU-ITEMS:
328 $this->MOD_MENU = [
329 'tt_content_showHidden' => '',
330 'function' => [
331 1 => $lang->getLL('m_function_1'),
332 2 => $lang->getLL('m_function_2')
333 ],
334 'language' => [
335 0 => $lang->getLL('m_default')
336 ]
337 ];
338 // initialize page/be_user TSconfig settings
339 $this->modSharedTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.SHARED');
340 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
341 // example settings:
342 // $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables']['tx_myext'] =
343 // array ('default' => array(
344 // 'MENU' => 'LLL:EXT:tx_myext/locallang_db.xlf:menuDefault',
345 // 'fList' => 'title,description,image',
346 // 'icon' => TRUE));
347 if (is_array($this->externalTables)) {
348 if (!empty($this->externalTables)) {
349 GeneralUtility::deprecationLog('The rendering of records in the page module by using '
350 . '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'cms\'][\'db_layout\'][\'addTables\']'
351 . ' has been deprecated since TYPO3 CMS 8 and will be removed in TYPO3 CMS 9.'
352 );
353 }
354 foreach ($this->externalTables as $table => $tableSettings) {
355 // delete the default settings from above
356 if (is_array($this->MOD_MENU[$table])) {
357 unset($this->MOD_MENU[$table]);
358 }
359 if (is_array($tableSettings) && count($tableSettings) > 1) {
360 foreach ($tableSettings as $key => $settings) {
361 $this->MOD_MENU[$table][$key] = $lang->sL($settings['MENU']);
362 }
363 }
364 }
365 }
366 // First, select all pages_language_overlay records on the current page. Each represents a possibility for a language on the page. Add these to language selector.
367 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
368 $queryBuilder->getRestrictions()->removeAll();
369 if ($this->id) {
370 $queryBuilder->select('sys_language.uid AS uid', 'sys_language.title AS title')
371 ->from('sys_language')
372 ->join(
373 'sys_language',
374 'pages_language_overlay',
375 'pages_language_overlay',
376 $queryBuilder->expr()->eq(
377 'sys_language.uid',
378 $queryBuilder->quoteIdentifier('pages_language_overlay.sys_language_uid')
379 )
380 )
381 ->where(
382 $queryBuilder->expr()->eq(
383 'pages_language_overlay.deleted',
384 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
385 ),
386 $queryBuilder->expr()->eq(
387 'pages_language_overlay.pid',
388 $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
389 ),
390 $queryBuilder->expr()->orX(
391 $queryBuilder->expr()->gte(
392 'pages_language_overlay.t3ver_state',
393 $queryBuilder->createNamedParameter(
394 (string)new VersionState(VersionState::DEFAULT_STATE),
395 \PDO::PARAM_INT
396 )
397 ),
398 $queryBuilder->expr()->eq(
399 'pages_language_overlay.t3ver_wsid',
400 $queryBuilder->createNamedParameter($this->getBackendUser()->workspace, \PDO::PARAM_INT)
401 )
402 )
403 )
404 ->groupBy('pages_language_overlay.sys_language_uid', 'sys_language.uid', 'sys_language.pid',
405 'sys_language.tstamp', 'sys_language.hidden', 'sys_language.title',
406 'sys_language.language_isocode', 'sys_language.static_lang_isocode', 'sys_language.flag')
407 ->orderBy('sys_language.sorting');
408 if (!$this->getBackendUser()->isAdmin()) {
409 $queryBuilder->andWhere(
410 $queryBuilder->expr()->eq(
411 'sys_language.hidden',
412 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
413 )
414 );
415 }
416 $statement = $queryBuilder->execute();
417 } else {
418 $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(HiddenRestriction::class));
419 $statement = $queryBuilder->select('uid', 'title')
420 ->from('sys_language')
421 ->orderBy('sorting')
422 ->execute();
423 }
424 while ($lRow = $statement->fetch()) {
425 if ($this->getBackendUser()->checkLanguageAccess($lRow['uid'])) {
426 $this->MOD_MENU['language'][$lRow['uid']] = $lRow['title'];
427 }
428 }
429 // Setting alternative default label:
430 if (($this->modSharedTSconfig['properties']['defaultLanguageLabel'] || $this->modTSconfig['properties']['defaultLanguageLabel']) && isset($this->MOD_MENU['language'][0])) {
431 $this->MOD_MENU['language'][0] = $this->modTSconfig['properties']['defaultLanguageLabel'] ? $this->modTSconfig['properties']['defaultLanguageLabel'] : $this->modSharedTSconfig['properties']['defaultLanguageLabel'];
432 }
433 // Initialize the avaiable actions
434 $actions = $this->initActions();
435 // Clean up settings
436 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName);
437 // For all elements to be shown in draft workspaces & to also show hidden elements by default if user hasn't disabled the option
438 if ($this->getBackendUser()->workspace != 0 || $this->MOD_SETTINGS['tt_content_showHidden'] !== '0') {
439 $this->MOD_SETTINGS['tt_content_showHidden'] = 1;
440 }
441 // Make action menu from available actions
442 $this->makeActionMenu($actions);
443 }
444
445 /**
446 * Initializes the available actions this module provides
447 *
448 * @return array the available actions
449 */
450 protected function initActions()
451 {
452 $actions = [
453 1 => $this->getLanguageService()->getLL('m_function_1'),
454 2 => $this->getLanguageService()->getLL('m_function_2')
455 ];
456 // Find if there are ANY languages at all (and if not, remove the language option from function menu).
457 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
458 if ($this->getBackendUser()->isAdmin()) {
459 $queryBuilder->getRestrictions()->removeAll();
460 }
461
462 $count = $queryBuilder
463 ->count('uid')
464 ->from('sys_language')
465 ->execute()
466 ->fetchColumn(0);
467
468 if (!$count) {
469 unset($actions['2']);
470 }
471 // @internal: This is an internal hook for compatibility7 only, this hook will be removed without further notice
472 $initActionHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['initActionHook'];
473 if (is_array($initActionHook)) {
474 foreach ($initActionHook as $hook) {
475 $params = [
476 'actions' => &$actions
477 ];
478 GeneralUtility::callUserFunction($hook, $params, $this);
479 }
480 }
481 // page/be_user TSconfig blinding of menu-items
482 $actions = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $actions, 'menu.function');
483
484 return $actions;
485 }
486
487 /**
488 * This creates the dropdown menu with the different actions this module is able to provide.
489 * For now they are Columns, Quick Edit and Languages.
490 *
491 * @param array $actions array with the available actions
492 * @return void
493 */
494 protected function makeActionMenu(array $actions)
495 {
496 $actionMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
497 $actionMenu->setIdentifier('actionMenu');
498 $actionMenu->setLabel('');
499
500 $defaultKey = null;
501 $foundDefaultKey = false;
502 foreach ($actions as $key => $action) {
503 $menuItem = $actionMenu
504 ->makeMenuItem()
505 ->setTitle($action)
506 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&SET[function]=' . $key);
507
508 if (!$foundDefaultKey) {
509 $defaultKey = $key;
510 $foundDefaultKey = true;
511 }
512 if ((int)$this->MOD_SETTINGS['function'] === $key) {
513 $menuItem->setActive(true);
514 $defaultKey = null;
515 }
516 $actionMenu->addMenuItem($menuItem);
517 }
518 if (isset($defaultKey)) {
519 $this->MOD_SETTINGS['function'] = $defaultKey;
520 }
521 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($actionMenu);
522 }
523
524 /**
525 * Clears page cache for the current id, $this->id
526 *
527 * @return void
528 */
529 public function clearCache()
530 {
531 if ($this->clear_cache && !empty($this->pageinfo)) {
532 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
533 $dataHandler->start([], []);
534 $dataHandler->clear_cacheCmd($this->id);
535 }
536 }
537
538 /**
539 * Generate the flashmessages for current pid
540 *
541 * @return string HTML content with flashmessages
542 */
543 protected function getHeaderFlashMessagesForCurrentPid()
544 {
545 $content = '';
546 $lang = $this->getLanguageService();
547
548 $view = GeneralUtility::makeInstance(StandaloneView::class);
549 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
550
551 // If page is a folder
552 if ($this->pageinfo['doktype'] == PageRepository::DOKTYPE_SYSFOLDER) {
553 $moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
554 $moduleLoader->load($GLOBALS['TBE_MODULES']);
555 $modules = $moduleLoader->modules;
556 if (is_array($modules['web']['sub']['list'])) {
557 $title = $lang->getLL('goToListModule');
558 $message = '<p>' . $lang->getLL('goToListModuleMessage') . '</p>';
559 $message .= '<a class="btn btn-info" href="javascript:top.goToModule(\'web_list\',1);">' . $lang->getLL('goToListModule') . '</a>';
560 $view->assignMultiple([
561 'title' => $title,
562 'message' => $message,
563 'state' => InfoboxViewHelper::STATE_INFO
564 ]);
565 $content .= $view->render();
566 }
567 } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_SHORTCUT) {
568 $shortcutMode = (int)$this->pageinfo['shortcut_mode'];
569 $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
570 $targetPage = [];
571
572 if ($this->pageinfo['shortcut'] || $shortcutMode) {
573 switch ($shortcutMode) {
574 case PageRepository::SHORTCUT_MODE_NONE:
575 $targetPage = $pageRepository->getPage($this->pageinfo['shortcut']);
576 break;
577 case PageRepository::SHORTCUT_MODE_FIRST_SUBPAGE:
578 $targetPage = reset($pageRepository->getMenu($this->pageinfo['shortcut'] ?: $this->pageinfo['uid']));
579 break;
580 case PageRepository::SHORTCUT_MODE_PARENT_PAGE:
581 $targetPage = $pageRepository->getPage($this->pageinfo['pid']);
582 break;
583 }
584
585 $message = '';
586 if ($shortcutMode === PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
587 $message .= sprintf($lang->getLL('pageIsRandomInternalLinkMessage'));
588 } else {
589 $linkToPid = $this->local_linkThisScript(['id' => $targetPage['uid']]);
590 $path = BackendUtility::getRecordPath($targetPage['uid'], $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW), 1000);
591 $linkedPath = '<a href="' . $linkToPid . '">' . htmlspecialchars($path) . '</a>';
592 $message .= sprintf($lang->getLL('pageIsInternalLinkMessage'), $linkedPath);
593 }
594
595 $message .= ' (' . htmlspecialchars($lang->sL(BackendUtility::getLabelFromItemlist('pages', 'shortcut_mode', $shortcutMode))) . ')';
596
597 $view->assignMultiple([
598 'title' => $this->pageinfo['title'],
599 'message' => $message,
600 'state' => InfoboxViewHelper::STATE_INFO
601 ]);
602 $content .= $view->render();
603 } else {
604 if (empty($targetPage) && $shortcutMode !== PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
605 $view->assignMultiple([
606 'title' => $this->pageinfo['title'],
607 'message' => $lang->getLL('pageIsMisconfiguredInternalLinkMessage'),
608 'state' => InfoboxViewHelper::STATE_ERROR
609 ]);
610 $content .= $view->render();
611 }
612 }
613 } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_LINK) {
614 if (empty($this->pageinfo['url'])) {
615 $view->assignMultiple([
616 'title' => $this->pageinfo['title'],
617 'message' => $lang->getLL('pageIsMisconfiguredExternalLinkMessage'),
618 'state' => InfoboxViewHelper::STATE_ERROR
619 ]);
620 $content .= $view->render();
621 } else {
622 $externalUrl = htmlspecialchars(GeneralUtility::makeInstance(PageRepository::class)->getExtURL($this->pageinfo));
623 if ($externalUrl !== false) {
624 $externalUrlHtml = '<a href="' . $externalUrl . '" target="_blank" rel="noopener">' . $externalUrl . '</a>';
625 $view->assignMultiple([
626 'title' => $this->pageinfo['title'],
627 'message' => sprintf($lang->getLL('pageIsExternalLinkMessage'), $externalUrlHtml),
628 'state' => InfoboxViewHelper::STATE_INFO
629 ]);
630 $content .= $view->render();
631 }
632 }
633 }
634 // If content from different pid is displayed
635 if ($this->pageinfo['content_from_pid']) {
636 $contentPage = BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
637 $linkToPid = $this->local_linkThisScript(['id' => $this->pageinfo['content_from_pid']]);
638 $title = BackendUtility::getRecordTitle('pages', $contentPage);
639 $link = '<a href="' . $linkToPid . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
640 $message = sprintf($lang->getLL('content_from_pid_title'), $link);
641 $view->assignMultiple([
642 'title' => $title,
643 'message' => $message,
644 'state' => InfoboxViewHelper::STATE_INFO
645 ]);
646 $content .= $view->render();
647 }
648 return $content;
649 }
650
651 /**
652 *
653 * @return string $title
654 */
655 protected function getLocalizedPageTitle()
656 {
657 if ($this->current_sys_language > 0) {
658 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
659 ->getQueryBuilderForTable('pages_language_overlay');
660 $queryBuilder->getRestrictions()
661 ->removeAll()
662 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
663 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
664 $overlayRecord = $queryBuilder
665 ->select('title')
666 ->from('pages_language_overlay')
667 ->where(
668 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
669 $queryBuilder->expr()->eq(
670 'sys_language_uid',
671 $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
672 )
673 )
674 ->setMaxResults(1)
675 ->execute()
676 ->fetch();
677 return $overlayRecord['title'];
678 } else {
679 return $this->pageinfo['title'];
680 }
681 }
682
683 /**
684 * Injects the request object for the current request or subrequest
685 * As this controller goes only through the main() method, it is rather simple for now
686 *
687 * @param ServerRequestInterface $request the current request
688 * @param ResponseInterface $response
689 * @return ResponseInterface the response with the content
690 */
691 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
692 {
693 $GLOBALS['SOBE'] = $this;
694 $this->init();
695 $this->clearCache();
696 $this->main();
697 $response->getBody()->write($this->moduleTemplate->renderContent());
698 return $response;
699 }
700
701 /**
702 * Main function.
703 * Creates some general objects and calls other functions for the main rendering of module content.
704 *
705 * @return void
706 */
707 public function main()
708 {
709 $lang = $this->getLanguageService();
710 // Access check...
711 // The page will show only if there is a valid page and if this page may be viewed by the user
712 $access = is_array($this->pageinfo) ? 1 : 0;
713 // Content
714 $content = '';
715 if ($this->id && $access) {
716 // Initialize permission settings:
717 $this->CALC_PERMS = $this->getBackendUser()->calcPerms($this->pageinfo);
718 $this->EDIT_CONTENT = $this->contentIsNotLockedForEditors();
719
720 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
721
722 // override the default jumpToUrl
723 $this->moduleTemplate->addJavaScriptCode('jumpToUrl', '
724 function jumpToUrl(URL,formEl) {
725 if (document.editform && TBE_EDITOR.isFormChanged) { // Check if the function exists... (works in all browsers?)
726 if (!TBE_EDITOR.isFormChanged()) {
727 window.location.href = URL;
728 } else if (formEl) {
729 if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
730 }
731 } else {
732 window.location.href = URL;
733 }
734 }
735 ');
736 $this->moduleTemplate->addJavaScriptCode('mainJsFunctions', '
737 if (top.fsMod) {
738 top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
739 top.fsMod.navFrameHighlightedID["web"] = "pages' . (int)$this->id . '_"+top.fsMod.currentBank; ' . (int)$this->id . ';
740 }
741 ' . ($this->popView ? BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)) : '') . '
742 function deleteRecord(table,id,url) { //
743 window.location.href = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&cmd[')
744 . ' + table + "][" + id + "][delete]=1&redirect=" + encodeURIComponent(url) + "&prErr=1&uPT=1";
745 return false;
746 }
747 ');
748
749 // Find backend layout / columns
750 $backendLayout = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $this->id, $this);
751 if (!empty($backendLayout['__colPosList'])) {
752 $this->colPosList = implode(',', $backendLayout['__colPosList']);
753 }
754 // Removing duplicates, if any
755 $this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList));
756 // Accessible columns
757 if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
758 $this->activeColPosList = array_unique(GeneralUtility::intExplode(',', trim($this->modSharedTSconfig['properties']['colPos_list'])));
759 // Match with the list which is present in the colPosList for the current page
760 if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
761 $this->activeColPosList = array_unique(array_intersect(
762 $this->activeColPosList,
763 $this->colPosList
764 ));
765 }
766 } else {
767 $this->activeColPosList = $this->colPosList;
768 }
769 $this->activeColPosList = implode(',', $this->activeColPosList);
770 $this->colPosList = implode(',', $this->colPosList);
771
772 $content .= $this->getHeaderFlashMessagesForCurrentPid();
773
774 // Render the primary module content:
775 if ($this->MOD_SETTINGS['function'] == 1 || $this->MOD_SETTINGS['function'] == 2) {
776 $content .= '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl($this->moduleName, ['id' => $this->id, 'imagemode' => $this->imagemode])) . '" id="PageLayoutController" method="post">';
777 // Page title
778 $content .= '<h1 class="t3js-title-inlineedit">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>';
779 // All other listings
780 $content .= $this->renderContent();
781 }
782 $content .= '</form>';
783 $content .= $this->searchContent;
784 // Setting up the buttons for the docheader
785 $this->makeButtons();
786 // @internal: This is an internal hook for compatibility7 only, this hook will be removed without further notice
787 if ($this->MOD_SETTINGS['function'] != 1 && $this->MOD_SETTINGS['function'] != 2) {
788 $renderActionHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['renderActionHook'];
789 if (is_array($renderActionHook)) {
790 foreach ($renderActionHook as $hook) {
791 $params = [
792 'deleteButton' => $this->deleteButton,
793 ''
794 ];
795 $content .= GeneralUtility::callUserFunction($hook, $params, $this);
796 }
797 }
798 }
799 // Create LanguageMenu
800 $this->makeLanguageMenu();
801 } else {
802 $this->moduleTemplate->addJavaScriptCode(
803 'mainJsFunctions',
804 'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
805 );
806 $content .= '<h1>' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . '</h1>';
807 $view = GeneralUtility::makeInstance(StandaloneView::class);
808 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
809 $view->assignMultiple([
810 'title' => $lang->getLL('clickAPage_header'),
811 'message' => $lang->getLL('clickAPage_content'),
812 'state' => InfoboxViewHelper::STATE_INFO
813 ]);
814 $content .= $view->render();
815 }
816 // Set content
817 $this->moduleTemplate->setContent($content);
818 }
819
820 /**
821 * Rendering content
822 *
823 * @return string
824 */
825 public function renderContent()
826 {
827 $this->moduleTemplate->getPageRenderer()->loadJquery();
828 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
829 /** @var $dbList \TYPO3\CMS\Backend\View\PageLayoutView */
830 $dbList = GeneralUtility::makeInstance(PageLayoutView::class);
831 $dbList->thumbs = $this->imagemode;
832 $dbList->no_noWrap = 1;
833 $dbList->descrTable = $this->descrTable;
834 $this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
835 $dbList->script = BackendUtility::getModuleUrl($this->moduleName);
836 $dbList->showIcon = 0;
837 $dbList->setLMargin = 0;
838 $dbList->doEdit = $this->EDIT_CONTENT;
839 $dbList->ext_CALC_PERMS = $this->CALC_PERMS;
840 $dbList->agePrefixes = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears');
841 $dbList->id = $this->id;
842 $dbList->nextThree = MathUtility::forceIntegerInRange($this->modTSconfig['properties']['editFieldsAtATime'], 0, 10);
843 $dbList->option_newWizard = $this->modTSconfig['properties']['disableNewContentElementWizard'] ? 0 : 1;
844 $dbList->defLangBinding = $this->modTSconfig['properties']['defLangBinding'] ? 1 : 0;
845 if (!$dbList->nextThree) {
846 $dbList->nextThree = 1;
847 }
848 $dbList->externalTables = $this->externalTables;
849 // Create menu for selecting a table to jump to (this is, if more than just pages/tt_content elements are found on the page!)
850 // also fills $dbList->activeTables
851 $dbList->getTableMenu($this->id);
852 // Initialize other variables:
853 $tableOutput = [];
854 $tableJSOutput = [];
855 $CMcounter = 0;
856 // Traverse the list of table names which has records on this page (that array is populated
857 // by the $dblist object during the function getTableMenu()):
858 foreach ($dbList->activeTables as $table => $value) {
859 $h_func = '';
860 $h_func_b = '';
861 if (!isset($dbList->externalTables[$table])) {
862 // Toggle hidden ContentElements
863 $numberOfHiddenElements = $this->getNumberOfHiddenElements();
864 if ($numberOfHiddenElements > 0) {
865 $h_func_b = '
866 <div class="checkbox">
867 <label for="checkTt_content_showHidden">
868 <input type="checkbox" id="checkTt_content_showHidden" class="checkbox" name="SET[tt_content_showHidden]" value="1" ' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? 'checked="checked"' : '') . ' />
869 ' . htmlspecialchars($this->getLanguageService()->getLL('hiddenCE')) . ' (<span class="t3js-hidden-counter">' . $numberOfHiddenElements . '</span>)
870 </label>
871 </div>';
872 }
873
874 // Boolean: Display up/down arrows and edit icons for tt_content records
875 $dbList->tt_contentConfig['showCommands'] = 1;
876 // Boolean: Display info-marks or not
877 $dbList->tt_contentConfig['showInfo'] = 1;
878 // Setting up the tt_content columns to show:
879 if (is_array($GLOBALS['TCA']['tt_content']['columns']['colPos']['config']['items'])) {
880 $colList = [];
881 $tcaItems = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $this->id, $this);
882 foreach ($tcaItems as $temp) {
883 $colList[] = $temp[1];
884 }
885 } else {
886 // ... should be impossible that colPos has no array. But this is the fallback should it make any sense:
887 $colList = ['1', '0', '2', '3'];
888 }
889 if ($this->colPosList !== '') {
890 $colList = array_intersect(GeneralUtility::intExplode(',', $this->colPosList), $colList);
891 }
892 // The order of the rows: Default is left(1), Normal(0), right(2), margin(3)
893 $dbList->tt_contentConfig['cols'] = implode(',', $colList);
894 $dbList->tt_contentConfig['activeCols'] = $this->activeColPosList;
895 $dbList->tt_contentConfig['showHidden'] = $this->MOD_SETTINGS['tt_content_showHidden'];
896 $dbList->tt_contentConfig['sys_language_uid'] = (int)$this->current_sys_language;
897 // If the function menu is set to "Language":
898 if ($this->MOD_SETTINGS['function'] == 2) {
899 $dbList->tt_contentConfig['languageMode'] = 1;
900 $dbList->tt_contentConfig['languageCols'] = $this->MOD_MENU['language'];
901 $dbList->tt_contentConfig['languageColsPointer'] = $this->current_sys_language;
902 }
903 } else {
904 if (isset($this->MOD_SETTINGS) && isset($this->MOD_MENU)) {
905 $h_func = BackendUtility::getFuncMenu($this->id, 'SET[' . $table . ']', $this->MOD_SETTINGS[$table], $this->MOD_MENU[$table], '', '');
906 }
907 }
908 // Start the dblist object:
909 $dbList->itemsLimitSingleTable = 1000;
910 $dbList->start($this->id, $table, $this->pointer, $this->search_field, $this->search_levels, $this->showLimit);
911 $dbList->counter = $CMcounter;
912 $dbList->ext_function = $this->MOD_SETTINGS['function'];
913 // Render versioning selector:
914 $dbList->HTMLcode .= $this->moduleTemplate->getVersionSelector($this->id);
915 // Generate the list of elements here:
916 $dbList->generateList();
917 // Adding the list content to the tableOutput variable:
918 $tableOutput[$table] = $h_func . $dbList->HTMLcode . $h_func_b;
919 // ... and any accumulated JavaScript goes the same way!
920 $tableJSOutput[$table] = $dbList->JScode;
921 // Increase global counter:
922 $CMcounter += $dbList->counter;
923 // Reset variables after operation:
924 $dbList->HTMLcode = '';
925 $dbList->JScode = '';
926 }
927 // END: traverse tables
928 // For Context Sensitive Menus:
929 // Init the content
930 $content = '';
931 // Additional header content
932 $headerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'];
933 if (is_array($headerContentHook)) {
934 foreach ($headerContentHook as $hook) {
935 $params = [];
936 $content .= GeneralUtility::callUserFunction($hook, $params, $this);
937 }
938 }
939 // Add the content for each table we have rendered (traversing $tableOutput variable)
940 foreach ($tableOutput as $table => $output) {
941 $content .= $output;
942 }
943 // Making search form:
944 if (!$this->modTSconfig['properties']['disableSearchBox'] && ($dbList->counter > 0 || $this->currentPageHasSubPages())) {
945 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
946 $toggleSearchFormButton = $this->buttonBar->makeLinkButton()
947 ->setClasses('t3js-toggle-search-toolbox')
948 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
949 ->setIcon($this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL))
950 ->setHref('#');
951 $this->buttonBar->addButton($toggleSearchFormButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
952 $this->searchContent = $dbList->getSearchBox();
953 }
954 // Additional footer content
955 $footerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'];
956 if (is_array($footerContentHook)) {
957 foreach ($footerContentHook as $hook) {
958 $params = [];
959 $content .= GeneralUtility::callUserFunction($hook, $params, $this);
960 }
961 }
962 return $content;
963 }
964
965 /**
966 * @return ModuleTemplate
967 */
968 public function getModuleTemplate()
969 {
970 return $this->moduleTemplate;
971 }
972
973 /**
974 * Print accumulated content of module
975 *
976 * @return void
977 */
978 public function printContent()
979 {
980 echo $this->moduleTemplate->renderContent();
981 }
982
983 /***************************
984 *
985 * Sub-content functions, rendering specific parts of the module content.
986 *
987 ***************************/
988 /**
989 * This creates the buttons for die modules
990 *
991 * @return void
992 */
993 protected function makeButtons()
994 {
995 if ($this->MOD_SETTINGS['function'] == 1 || $this->MOD_SETTINGS['function'] == 2) {
996 // Add CSH (Context Sensitive Help) icon to tool bar
997 $contextSensitiveHelpButton = $this->buttonBar->makeHelpButton()
998 ->setModuleName($this->descrTable)
999 ->setFieldName('columns_' . $this->controller->MOD_SETTINGS['function']);
1000 $this->buttonBar->addButton($contextSensitiveHelpButton);
1001 }
1002 $lang = $this->getLanguageService();
1003 // View page
1004 if (!VersionState::cast($this->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
1005 $viewButton = $this->buttonBar->makeLinkButton()
1006 ->setOnClick(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid'])))
1007 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
1008 ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL))
1009 ->setHref('#');
1010
1011 $this->buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1012 }
1013 // Shortcut
1014 $shortcutButton = $this->buttonBar->makeShortcutButton()
1015 ->setModuleName($this->moduleName)
1016 ->setGetVariables([
1017 'id',
1018 'M',
1019 'edit_record',
1020 'pointer',
1021 'new_unique_uid',
1022 'search_field',
1023 'search_levels',
1024 'showLimit'
1025 ])
1026 ->setSetVariables(array_keys($this->MOD_MENU));
1027 $this->buttonBar->addButton($shortcutButton);
1028
1029 // Cache
1030 if (!$this->modTSconfig['properties']['disableAdvanced']) {
1031 $clearCacheButton = $this->buttonBar->makeLinkButton()
1032 ->setHref(BackendUtility::getModuleUrl($this->moduleName, ['id' => $this->pageinfo['uid'], 'clear_cache' => '1']))
1033 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
1034 ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL));
1035 $this->buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
1036 }
1037 if (!$this->modTSconfig['properties']['disableIconToolbar']) {
1038 // Edit page properties and page language overlay icons
1039 if ($this->pageIsNotLockedForEditors() && $this->getBackendUser()->checkLanguageAccess(0)) {
1040 // Edit localized page_language_overlay only when one specific language is selected
1041 if ($this->MOD_SETTINGS['function'] == 1 && $this->current_sys_language > 0) {
1042 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1043 ->getQueryBuilderForTable('pages_language_overlay');
1044 $queryBuilder->getRestrictions()
1045 ->removeAll()
1046 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1047 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1048 $overlayRecord = $queryBuilder
1049 ->select('uid')
1050 ->from('pages_language_overlay')
1051 ->where(
1052 $queryBuilder->expr()->eq(
1053 'pid',
1054 $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
1055 ),
1056 $queryBuilder->expr()->eq(
1057 'sys_language_uid',
1058 $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
1059 )
1060 )
1061 ->setMaxResults(1)
1062 ->execute()
1063 ->fetch();
1064 // Edit button
1065 $urlParameters = [
1066 'edit' => [
1067 'pages_language_overlay' => [
1068 $overlayRecord['uid'] => 'edit'
1069 ]
1070 ],
1071 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
1072 ];
1073 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
1074 $editLanguageButton = $this->buttonBar->makeLinkButton()
1075 ->setHref($url)
1076 ->setTitle($lang->getLL('editPageLanguageOverlayProperties'))
1077 ->setIcon($this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL));
1078 $this->buttonBar->addButton($editLanguageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1079 }
1080 $urlParameters = [
1081 'edit' => [
1082 'pages' => [
1083 $this->id => 'edit'
1084 ]
1085 ],
1086 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
1087 ];
1088 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
1089 $editPageButton = $this->buttonBar->makeLinkButton()
1090 ->setHref($url)
1091 ->setTitle($lang->getLL('editPageProperties'))
1092 ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL));
1093 $this->buttonBar->addButton($editPageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1094 }
1095 }
1096 }
1097
1098 /*******************************
1099 *
1100 * Other functions
1101 *
1102 ******************************/
1103 /**
1104 * Returns the number of hidden elements (including those hidden by start/end times)
1105 * on the current page (for the current sys_language)
1106 *
1107 * @return int
1108 */
1109 public function getNumberOfHiddenElements()
1110 {
1111 /** @var QueryBuilder $queryBuilder */
1112 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
1113 $queryBuilder->getRestrictions()
1114 ->removeAll()
1115 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1116 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1117
1118 $queryBuilder
1119 ->count('uid')
1120 ->from('tt_content')
1121 ->where(
1122 $queryBuilder->expr()->eq(
1123 'pid',
1124 $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
1125 ),
1126 $queryBuilder->expr()->eq(
1127 'sys_language_uid',
1128 $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
1129 )
1130 );
1131
1132 if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'])) {
1133 $andWhere[] = $queryBuilder->expr()->neq(
1134 'hidden',
1135 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1136 );
1137 }
1138
1139 if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'])) {
1140 $andWhere[] = $queryBuilder->expr()->andX(
1141 $queryBuilder->expr()->neq(
1142 'starttime',
1143 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1144 ),
1145 $queryBuilder->expr()->gt(
1146 'starttime',
1147 $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
1148 )
1149 );
1150 }
1151
1152 if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'])) {
1153 $andWhere[] = $queryBuilder->expr()->andX(
1154 $queryBuilder->expr()->neq(
1155 'endtime',
1156 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1157 ),
1158 $queryBuilder->expr()->lte(
1159 'endtime',
1160 $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
1161 )
1162 );
1163 }
1164
1165 if (!empty($andWhere)) {
1166 $queryBuilder->andWhere(
1167 $queryBuilder->expr()->orX(...$andWhere)
1168 );
1169 }
1170
1171 $count = $queryBuilder
1172 ->execute()
1173 ->fetchColumn(0);
1174
1175 return (int)$count;
1176 }
1177
1178 /**
1179 * Returns URL to the current script.
1180 * In particular the "popView" and "new_unique_uid" Get vars are unset.
1181 *
1182 * @param array $params Parameters array, merged with global GET vars.
1183 * @return string URL
1184 */
1185 public function local_linkThisScript($params)
1186 {
1187 $params['popView'] = '';
1188 $params['new_unique_uid'] = '';
1189 return GeneralUtility::linkThisScript($params);
1190 }
1191
1192 /**
1193 * Check if page can be edited by current user
1194 *
1195 * @return bool
1196 */
1197 public function pageIsNotLockedForEditors()
1198 {
1199 return $this->getBackendUser()->isAdmin() || ($this->CALC_PERMS & Permission::PAGE_EDIT) === Permission::PAGE_EDIT && !$this->pageinfo['editlock'];
1200 }
1201
1202 /**
1203 * Check if content can be edited by current user
1204 *
1205 * @return bool
1206 */
1207 public function contentIsNotLockedForEditors()
1208 {
1209 return $this->getBackendUser()->isAdmin() || ($this->CALC_PERMS & Permission::CONTENT_EDIT) === Permission::CONTENT_EDIT && !$this->pageinfo['editlock'];
1210 }
1211
1212 /**
1213 * Returns LanguageService
1214 *
1215 * @return \TYPO3\CMS\Lang\LanguageService
1216 */
1217 protected function getLanguageService()
1218 {
1219 return $GLOBALS['LANG'];
1220 }
1221
1222 /**
1223 * Returns the current BE user.
1224 *
1225 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1226 */
1227 protected function getBackendUser()
1228 {
1229 return $GLOBALS['BE_USER'];
1230 }
1231
1232 /**
1233 * Returns current PageRenderer
1234 *
1235 * @return PageRenderer
1236 */
1237 protected function getPageRenderer()
1238 {
1239 return GeneralUtility::makeInstance(PageRenderer::class);
1240 }
1241
1242 /**
1243 * Make the LanguageMenu
1244 *
1245 * @return void
1246 */
1247 protected function makeLanguageMenu()
1248 {
1249 if (count($this->MOD_MENU['language']) > 1) {
1250 $lang = $this->getLanguageService();
1251 $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
1252 $languageMenu->setIdentifier('languageMenu');
1253 $languageMenu->setLabel(htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.language')));
1254 foreach ($this->MOD_MENU['language'] as $key => $language) {
1255 $menuItem = $languageMenu
1256 ->makeMenuItem()
1257 ->setTitle($language)
1258 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&SET[language]=' . $key);
1259 if ((int)$this->current_sys_language === $key) {
1260 $menuItem->setActive(true);
1261 }
1262 $languageMenu->addMenuItem($menuItem);
1263 }
1264 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
1265 }
1266 }
1267
1268 /**
1269 * Checks whether the current page has sub pages
1270 *
1271 * @return bool
1272 */
1273 protected function currentPageHasSubPages()
1274 {
1275 /** @var QueryBuilder $queryBuilder */
1276 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1277 $queryBuilder->getRestrictions()
1278 ->removeAll()
1279 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1280 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1281
1282 // get workspace id
1283 $workspaceId = (int)$this->getBackendUser()->workspace;
1284 $comparisonExpression = $workspaceId === 0 ? 'neq' : 'eq';
1285
1286 $count = $queryBuilder
1287 ->count('uid')
1288 ->from('pages')
1289 ->where(
1290 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
1291 $queryBuilder->expr()->eq(
1292 't3ver_wsid',
1293 $queryBuilder->createNamedParameter($workspaceId, \PDO::PARAM_INT)
1294 ),
1295 $queryBuilder->expr()->{$comparisonExpression}(
1296 'pid',
1297 $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
1298 )
1299 )
1300 ->execute()
1301 ->fetchColumn(0);
1302
1303 return (bool)$count;
1304 }
1305 }