TYPO3 CMS  TYPO3_8-7
PageLayoutController.php
Go to the documentation of this file.
1 <?php
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 
42 
47 {
53  public $id;
54 
60  public $pointer;
61 
67  public $imagemode;
68 
74  public $search_field;
75 
82 
88  public $showLimit;
89 
95  public $returnUrl;
96 
102  public $clear_cache;
103 
109  public $popView;
110 
118  public $edit_record;
119 
128 
135 
141  public $modTSconfig;
142 
149 
155  public $pageinfo;
156 
162  public $descrTable;
163 
169  public $colPosList;
170 
177 
183  public $CALC_PERMS;
184 
191 
197  public $MCONF = [];
198 
204  public $MOD_MENU = [];
205 
211  public $MOD_SETTINGS = [];
212 
219  public $externalTables = [];
220 
226  public $content;
227 
235 
239  protected $editSelect;
240 
246  protected $languagesInColumnCache = [];
247 
251  protected $iconFactory;
252 
258  protected $moduleName = 'web_layout';
259 
263  protected $moduleTemplate;
264 
268  protected $buttonBar;
269 
273  protected $searchContent;
274 
278  public function init()
279  {
280  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
281  $this->iconFactory = $this->moduleTemplate->getIconFactory();
282  $this->buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
283  $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
284  // Setting module configuration / page select clause
285  $this->MCONF['name'] = $this->moduleName;
286  $this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
287  // Get session data
288  $sessionData = $this->getBackendUser()->getSessionData(RecordList::class);
289  $this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
290  // GPvars:
291  $this->id = (int)GeneralUtility::_GP('id');
292  $this->pointer = GeneralUtility::_GP('pointer');
293  $this->imagemode = GeneralUtility::_GP('imagemode');
294  $this->clear_cache = GeneralUtility::_GP('clear_cache');
295  $this->popView = GeneralUtility::_GP('popView');
296  $this->edit_record = GeneralUtility::_GP('edit_record');
297  $this->new_unique_uid = GeneralUtility::_GP('new_unique_uid');
298  $this->search_field = GeneralUtility::_GP('search_field');
299  $this->search_levels = GeneralUtility::_GP('search_levels');
300  $this->showLimit = GeneralUtility::_GP('showLimit');
301  $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
302  $this->externalTables = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables'];
303  $sessionData['search_field'] = $this->search_field;
304  // Store session data
305  $this->getBackendUser()->setAndSaveSessionData(RecordList::class, $sessionData);
306  // Load page info array:
307  $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
308  // Initialize menu
309  $this->menuConfig();
310  // Setting sys language from session var:
311  $this->current_sys_language = (int)$this->MOD_SETTINGS['language'];
312  // CSH / Descriptions:
313  $this->descrTable = '_MOD_' . $this->moduleName;
314  }
315 
319  public function menuConfig()
320  {
321  $lang = $this->getLanguageService();
322  // MENU-ITEMS:
323  $this->MOD_MENU = [
324  'tt_content_showHidden' => '',
325  'function' => [
326  1 => $lang->getLL('m_function_1'),
327  2 => $lang->getLL('m_function_2')
328  ],
329  'language' => [
330  0 => $lang->getLL('m_default')
331  ]
332  ];
333  // initialize page/be_user TSconfig settings
334  $this->modSharedTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.SHARED');
335  $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
336  // example settings:
337  // $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables']['tx_myext'] =
338  // array ('default' => array(
339  // 'MENU' => 'LLL:EXT:tx_myext/locallang_db.xlf:menuDefault',
340  // 'fList' => 'title,description,image',
341  // 'icon' => TRUE));
342  if (is_array($this->externalTables)) {
343  if (!empty($this->externalTables)) {
345  'The rendering of records in the page module by using '
346  . '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'cms\'][\'db_layout\'][\'addTables\']'
347  . ' has been deprecated since TYPO3 CMS 8 and will be removed in TYPO3 CMS 9.'
348  );
349  }
350  foreach ($this->externalTables as $table => $tableSettings) {
351  // delete the default settings from above
352  if (is_array($this->MOD_MENU[$table])) {
353  unset($this->MOD_MENU[$table]);
354  }
355  if (is_array($tableSettings) && count($tableSettings) > 1) {
356  foreach ($tableSettings as $key => $settings) {
357  $this->MOD_MENU[$table][$key] = $lang->sL($settings['MENU']);
358  }
359  }
360  }
361  }
362  // 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.
363  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
364  $queryBuilder->getRestrictions()->removeAll();
365  if ($this->id) {
366  $queryBuilder->select('sys_language.uid AS uid', 'sys_language.title AS title')
367  ->from('sys_language')
368  ->join(
369  'sys_language',
370  'pages_language_overlay',
371  'pages_language_overlay',
372  $queryBuilder->expr()->eq(
373  'sys_language.uid',
374  $queryBuilder->quoteIdentifier('pages_language_overlay.sys_language_uid')
375  )
376  )
377  ->where(
378  $queryBuilder->expr()->eq(
379  'pages_language_overlay.deleted',
380  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
381  ),
382  $queryBuilder->expr()->eq(
383  'pages_language_overlay.pid',
384  $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
385  ),
386  $queryBuilder->expr()->orX(
387  $queryBuilder->expr()->gte(
388  'pages_language_overlay.t3ver_state',
389  $queryBuilder->createNamedParameter(
391  \PDO::PARAM_INT
392  )
393  ),
394  $queryBuilder->expr()->eq(
395  'pages_language_overlay.t3ver_wsid',
396  $queryBuilder->createNamedParameter($this->getBackendUser()->workspace, \PDO::PARAM_INT)
397  )
398  )
399  )
400  ->groupBy(
401  'pages_language_overlay.sys_language_uid',
402  'sys_language.uid',
403  'sys_language.pid',
404  'sys_language.tstamp',
405  'sys_language.hidden',
406  'sys_language.title',
407  'sys_language.language_isocode',
408  'sys_language.static_lang_isocode',
409  'sys_language.flag',
410  'sys_language.sorting'
411  )
412  ->orderBy('sys_language.sorting');
413  if (!$this->getBackendUser()->isAdmin()) {
414  $queryBuilder->andWhere(
415  $queryBuilder->expr()->eq(
416  'sys_language.hidden',
417  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
418  )
419  );
420  }
421  $statement = $queryBuilder->execute();
422  } else {
423  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(HiddenRestriction::class));
424  $statement = $queryBuilder->select('uid', 'title')
425  ->from('sys_language')
426  ->orderBy('sorting')
427  ->execute();
428  }
429  while ($lRow = $statement->fetch()) {
430  if ($this->getBackendUser()->checkLanguageAccess($lRow['uid'])) {
431  $this->MOD_MENU['language'][$lRow['uid']] = $lRow['title'];
432  }
433  }
434  // Setting alternative default label:
435  if (($this->modSharedTSconfig['properties']['defaultLanguageLabel'] || $this->modTSconfig['properties']['defaultLanguageLabel']) && isset($this->MOD_MENU['language'][0])) {
436  $this->MOD_MENU['language'][0] = $this->modTSconfig['properties']['defaultLanguageLabel'] ? $this->modTSconfig['properties']['defaultLanguageLabel'] : $this->modSharedTSconfig['properties']['defaultLanguageLabel'];
437  }
438  // Initialize the avaiable actions
439  $actions = $this->initActions();
440  // Clean up settings
441  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName);
442  // For all elements to be shown in draft workspaces & to also show hidden elements by default if user hasn't disabled the option
443  if ($this->getBackendUser()->workspace != 0
444  || !isset($this->MOD_SETTINGS['tt_content_showHidden'])
445  || $this->MOD_SETTINGS['tt_content_showHidden'] !== '0'
446  ) {
447  $this->MOD_SETTINGS['tt_content_showHidden'] = 1;
448  }
449  // Make action menu from available actions
450  $this->makeActionMenu($actions);
451  }
452 
458  protected function initActions()
459  {
460  $actions = [
461  1 => $this->getLanguageService()->getLL('m_function_1'),
462  2 => $this->getLanguageService()->getLL('m_function_2')
463  ];
464  // Find if there are ANY languages at all (and if not, remove the language option from function menu).
465  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
466  if ($this->getBackendUser()->isAdmin()) {
467  $queryBuilder->getRestrictions()->removeAll();
468  }
469 
470  $count = $queryBuilder
471  ->count('uid')
472  ->from('sys_language')
473  ->execute()
474  ->fetchColumn(0);
475 
476  if (!$count) {
477  unset($actions['2']);
478  }
479  // @internal: This is an internal hook for compatibility7 only, this hook will be removed without further notice
480  $initActionHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['initActionHook'];
481  if (is_array($initActionHook)) {
482  foreach ($initActionHook as $hook) {
483  $params = [
484  'actions' => &$actions
485  ];
486  GeneralUtility::callUserFunction($hook, $params, $this);
487  }
488  }
489  // page/be_user TSconfig blinding of menu-items
490  $actions = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $actions, 'menu.function');
491 
492  return $actions;
493  }
494 
501  protected function makeActionMenu(array $actions)
502  {
503  $actionMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
504  $actionMenu->setIdentifier('actionMenu');
505  $actionMenu->setLabel('');
506 
507  $defaultKey = null;
508  $foundDefaultKey = false;
509  foreach ($actions as $key => $action) {
510  $menuItem = $actionMenu
511  ->makeMenuItem()
512  ->setTitle($action)
513  ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&SET[function]=' . $key);
514 
515  if (!$foundDefaultKey) {
516  $defaultKey = $key;
517  $foundDefaultKey = true;
518  }
519  if ((int)$this->MOD_SETTINGS['function'] === $key) {
520  $menuItem->setActive(true);
521  $defaultKey = null;
522  }
523  $actionMenu->addMenuItem($menuItem);
524  }
525  if (isset($defaultKey)) {
526  $this->MOD_SETTINGS['function'] = $defaultKey;
527  }
528  $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($actionMenu);
529  }
530 
534  public function clearCache()
535  {
536  if ($this->clear_cache && !empty($this->pageinfo)) {
537  $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
538  $dataHandler->start([], []);
539  $dataHandler->clear_cacheCmd($this->id);
540  }
541  }
542 
549  {
550  $content = '';
551  $lang = $this->getLanguageService();
552 
553  $view = GeneralUtility::makeInstance(StandaloneView::class);
554  $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
555 
556  // If page is a folder
557  if ($this->pageinfo['doktype'] == PageRepository::DOKTYPE_SYSFOLDER) {
558  $moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
559  $moduleLoader->load($GLOBALS['TBE_MODULES']);
560  $modules = $moduleLoader->modules;
561  if (is_array($modules['web']['sub']['list'])) {
562  $title = $lang->getLL('goToListModule');
563  $message = '<p>' . $lang->getLL('goToListModuleMessage') . '</p>';
564  $message .= '<a class="btn btn-info" href="javascript:top.goToModule(\'web_list\',1);">' . $lang->getLL('goToListModule') . '</a>';
565  $view->assignMultiple([
566  'title' => $title,
567  'message' => $message,
569  ]);
570  $content .= $view->render();
571  }
572  } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_SHORTCUT) {
573  $shortcutMode = (int)$this->pageinfo['shortcut_mode'];
574  $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
575  $targetPage = [];
576 
577  if ($this->pageinfo['shortcut'] || $shortcutMode) {
578  switch ($shortcutMode) {
580  $targetPage = $pageRepository->getPage($this->pageinfo['shortcut']);
581  break;
583  $targetPage = reset($pageRepository->getMenu($this->pageinfo['shortcut'] ?: $this->pageinfo['uid']));
584  break;
586  $targetPage = $pageRepository->getPage($this->pageinfo['pid']);
587  break;
588  }
589 
590  $message = '';
591  if ($shortcutMode === PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
592  $message .= sprintf($lang->getLL('pageIsRandomInternalLinkMessage'));
593  } else {
594  $linkToPid = $this->local_linkThisScript(['id' => $targetPage['uid']]);
595  $path = BackendUtility::getRecordPath($targetPage['uid'], $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW), 1000);
596  $linkedPath = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($path) . '</a>';
597  $message .= sprintf($lang->getLL('pageIsInternalLinkMessage'), $linkedPath);
598  }
599 
600  $message .= ' (' . htmlspecialchars($lang->sL(BackendUtility::getLabelFromItemlist('pages', 'shortcut_mode', $shortcutMode))) . ')';
601 
602  $view->assignMultiple([
603  'title' => $this->pageinfo['title'],
604  'message' => $message,
606  ]);
607  $content .= $view->render();
608  } else {
609  if (empty($targetPage) && $shortcutMode !== PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
610  $view->assignMultiple([
611  'title' => $this->pageinfo['title'],
612  'message' => $lang->getLL('pageIsMisconfiguredInternalLinkMessage'),
614  ]);
615  $content .= $view->render();
616  }
617  }
618  } elseif ($this->pageinfo['doktype'] === PageRepository::DOKTYPE_LINK) {
619  if (empty($this->pageinfo['url'])) {
620  $view->assignMultiple([
621  'title' => $this->pageinfo['title'],
622  'message' => $lang->getLL('pageIsMisconfiguredExternalLinkMessage'),
624  ]);
625  $content .= $view->render();
626  } else {
627  $externalUrl = htmlspecialchars(GeneralUtility::makeInstance(PageRepository::class)->getExtURL($this->pageinfo));
628  if ($externalUrl !== false) {
629  $externalUrlHtml = '<a href="' . $externalUrl . '" target="_blank" rel="noopener noreferrer">' . $externalUrl . '</a>';
630  $view->assignMultiple([
631  'title' => $this->pageinfo['title'],
632  'message' => sprintf($lang->getLL('pageIsExternalLinkMessage'), $externalUrlHtml),
634  ]);
635  $content .= $view->render();
636  }
637  }
638  }
639  // If content from different pid is displayed
640  if ($this->pageinfo['content_from_pid']) {
641  $contentPage = BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
642  $linkToPid = $this->local_linkThisScript(['id' => $this->pageinfo['content_from_pid']]);
643  $title = BackendUtility::getRecordTitle('pages', $contentPage);
644  $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
645  $message = sprintf($lang->getLL('content_from_pid_title'), $link);
646  $view->assignMultiple([
647  'title' => $title,
648  'message' => $message,
650  ]);
651  $content .= $view->render();
652  } else {
653  $links = $this->getPageLinksWhereContentIsAlsoShownOn($this->pageinfo['uid']);
654  if (!empty($links)) {
655  $message = sprintf($lang->getLL('content_on_pid_title'), $links);
656  $view->assignMultiple([
657  'title' => '',
658  'message' => $message,
660  ]);
661  $content .= $view->render();
662  }
663  }
664  return $content;
665  }
666 
673  protected function getPageLinksWhereContentIsAlsoShownOn($pageId)
674  {
675  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
676  $queryBuilder->getRestrictions()->removeAll();
677  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
678  $queryBuilder
679  ->select('*')
680  ->from('pages')
681  ->where($queryBuilder->expr()->eq('content_from_pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)));
682 
683  $links = [];
684  $rows = $queryBuilder->execute()->fetchAll();
685  if (!empty($rows)) {
686  foreach ($rows as $row) {
687  $linkToPid = $this->local_linkThisScript(['id' => $row['uid']]);
688  $title = BackendUtility::getRecordTitle('pages', $row);
689  $link = '<a href="' . htmlspecialchars($linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$row['uid'] . ')</a>';
690  $links[] = $link;
691  }
692  }
693  return implode(', ', $links);
694  }
695 
699  protected function getLocalizedPageTitle()
700  {
701  if ($this->current_sys_language > 0) {
702  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
703  ->getQueryBuilderForTable('pages_language_overlay');
704  $queryBuilder->getRestrictions()
705  ->removeAll()
706  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
707  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
708  $overlayRecord = $queryBuilder
709  ->select('*')
710  ->from('pages_language_overlay')
711  ->where(
712  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
713  $queryBuilder->expr()->eq(
714  'sys_language_uid',
715  $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
716  )
717  )
718  ->setMaxResults(1)
719  ->execute()
720  ->fetch();
721  BackendUtility::workspaceOL('pages_language_overlay', $overlayRecord);
722  return $overlayRecord['title'];
723  }
724  return $this->pageinfo['title'];
725  }
726 
735  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
736  {
737  $GLOBALS['SOBE'] = $this;
738  $this->init();
739  $this->clearCache();
740  $this->main();
741  $response->getBody()->write($this->moduleTemplate->renderContent());
742  return $response;
743  }
744 
749  public function main()
750  {
751  $lang = $this->getLanguageService();
752  // Access check...
753  // The page will show only if there is a valid page and if this page may be viewed by the user
754  $access = is_array($this->pageinfo) ? 1 : 0;
755  // Content
756  $content = '';
757  if ($this->id && $access) {
758  // Initialize permission settings:
759  $this->CALC_PERMS = $this->getBackendUser()->calcPerms($this->pageinfo);
760  $this->EDIT_CONTENT = $this->contentIsNotLockedForEditors();
761 
762  $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
763 
764  // override the default jumpToUrl
765  $this->moduleTemplate->addJavaScriptCode('jumpToUrl', '
766  function jumpToUrl(URL,formEl) {
767  if (document.editform && TBE_EDITOR.isFormChanged) { // Check if the function exists... (works in all browsers?)
768  if (!TBE_EDITOR.isFormChanged()) {
769  window.location.href = URL;
770  } else if (formEl) {
771  if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
772  }
773  } else {
774  window.location.href = URL;
775  }
776  }
777  ');
778  $this->moduleTemplate->addJavaScriptCode('mainJsFunctions', '
779  if (top.fsMod) {
780  top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
781  top.fsMod.navFrameHighlightedID["web"] = "pages' . (int)$this->id . '_"+top.fsMod.currentBank; ' . (int)$this->id . ';
782  }
783  ' . ($this->popView ? BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)) : '') . '
784  function deleteRecord(table,id,url) { //
785  window.location.href = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&cmd[')
786  . ' + table + "][" + id + "][delete]=1&redirect=" + encodeURIComponent(url) + "&prErr=1&uPT=1";
787  return false;
788  }
789  ');
790 
791  // Find backend layout / columns
792  $backendLayout = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $this->id, $this);
793  if (!empty($backendLayout['__colPosList'])) {
794  $this->colPosList = implode(',', $backendLayout['__colPosList']);
795  }
796  // Removing duplicates, if any
797  $this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList));
798  // Accessible columns
799  if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
800  $this->activeColPosList = array_unique(GeneralUtility::intExplode(',', trim($this->modSharedTSconfig['properties']['colPos_list'])));
801  // Match with the list which is present in the colPosList for the current page
802  if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
803  $this->activeColPosList = array_unique(array_intersect(
804  $this->activeColPosList,
805  $this->colPosList
806  ));
807  }
808  } else {
809  $this->activeColPosList = $this->colPosList;
810  }
811  $this->activeColPosList = implode(',', $this->activeColPosList);
812  $this->colPosList = implode(',', $this->colPosList);
813 
815 
816  // Render the primary module content:
817  if ($this->MOD_SETTINGS['function'] == 1 || $this->MOD_SETTINGS['function'] == 2) {
818  $content .= '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl($this->moduleName, ['id' => $this->id, 'imagemode' => $this->imagemode])) . '" id="PageLayoutController" method="post">';
819  // Page title
820  $content .= '<h1 class="t3js-title-inlineedit">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>';
821  // All other listings
822  $content .= $this->renderContent();
823  }
824  $content .= '</form>';
826  // Setting up the buttons for the docheader
827  $this->makeButtons();
828  // @internal: This is an internal hook for compatibility7 only, this hook will be removed without further notice
829  if ($this->MOD_SETTINGS['function'] != 1 && $this->MOD_SETTINGS['function'] != 2) {
830  $renderActionHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['renderActionHook'];
831  if (is_array($renderActionHook)) {
832  foreach ($renderActionHook as $hook) {
833  $params = [
834  'deleteButton' => $this->deleteButton,
835  ''
836  ];
837  $content .= GeneralUtility::callUserFunction($hook, $params, $this);
838  }
839  }
840  }
841  // Create LanguageMenu
842  $this->makeLanguageMenu();
843  } else {
844  $this->moduleTemplate->addJavaScriptCode(
845  'mainJsFunctions',
846  'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
847  );
848  $content .= '<h1>' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '</h1>';
849  $view = GeneralUtility::makeInstance(StandaloneView::class);
850  $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
851  $view->assignMultiple([
852  'title' => $lang->getLL('clickAPage_header'),
853  'message' => $lang->getLL('clickAPage_content'),
855  ]);
856  $content .= $view->render();
857  }
858  // Set content
859  $this->moduleTemplate->setContent($content);
860  }
861 
867  public function renderContent()
868  {
869  $this->moduleTemplate->getPageRenderer()->loadJquery();
870  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
872  $dbList = GeneralUtility::makeInstance(PageLayoutView::class);
873  $dbList->thumbs = $this->imagemode;
874  $dbList->no_noWrap = 1;
875  $dbList->descrTable = $this->descrTable;
876  $this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
877  $dbList->script = BackendUtility::getModuleUrl($this->moduleName);
878  $dbList->showIcon = 0;
879  $dbList->setLMargin = 0;
880  $dbList->doEdit = $this->EDIT_CONTENT;
881  $dbList->ext_CALC_PERMS = $this->CALC_PERMS;
882  $dbList->agePrefixes = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears');
883  $dbList->id = $this->id;
884  $dbList->nextThree = MathUtility::forceIntegerInRange($this->modTSconfig['properties']['editFieldsAtATime'], 0, 10);
885  $dbList->option_newWizard = $this->modTSconfig['properties']['disableNewContentElementWizard'] ? 0 : 1;
886  $dbList->defLangBinding = $this->modTSconfig['properties']['defLangBinding'] ? 1 : 0;
887  if (!$dbList->nextThree) {
888  $dbList->nextThree = 1;
889  }
890  $dbList->externalTables = $this->externalTables;
891  // Create menu for selecting a table to jump to (this is, if more than just pages/tt_content elements are found on the page!)
892  // also fills $dbList->activeTables
893  $dbList->getTableMenu($this->id);
894  // Initialize other variables:
895  $tableOutput = [];
896  $tableJSOutput = [];
897  $CMcounter = 0;
898  // Traverse the list of table names which has records on this page (that array is populated
899  // by the $dblist object during the function getTableMenu()):
900  foreach ($dbList->activeTables as $table => $value) {
901  $h_func = '';
902  $h_func_b = '';
903  if (!isset($dbList->externalTables[$table])) {
904  // Boolean: Display up/down arrows and edit icons for tt_content records
905  $dbList->tt_contentConfig['showCommands'] = 1;
906  // Boolean: Display info-marks or not
907  $dbList->tt_contentConfig['showInfo'] = 1;
908  // Setting up the tt_content columns to show:
909  if (is_array($GLOBALS['TCA']['tt_content']['columns']['colPos']['config']['items'])) {
910  $colList = [];
911  $tcaItems = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $this->id, $this);
912  foreach ($tcaItems as $temp) {
913  $colList[] = $temp[1];
914  }
915  } else {
916  // ... should be impossible that colPos has no array. But this is the fallback should it make any sense:
917  $colList = ['1', '0', '2', '3'];
918  }
919  if ($this->colPosList !== '') {
920  $colList = array_intersect(GeneralUtility::intExplode(',', $this->colPosList), $colList);
921  }
922  // The order of the rows: Default is left(1), Normal(0), right(2), margin(3)
923  $dbList->tt_contentConfig['cols'] = implode(',', $colList);
924  $dbList->tt_contentConfig['activeCols'] = $this->activeColPosList;
925  $dbList->tt_contentConfig['showHidden'] = $this->MOD_SETTINGS['tt_content_showHidden'];
926  $dbList->tt_contentConfig['sys_language_uid'] = (int)$this->current_sys_language;
927  // If the function menu is set to "Language":
928  if ($this->MOD_SETTINGS['function'] == 2) {
929  $dbList->tt_contentConfig['languageMode'] = 1;
930  $dbList->tt_contentConfig['languageCols'] = $this->MOD_MENU['language'];
931  $dbList->tt_contentConfig['languageColsPointer'] = $this->current_sys_language;
932  }
933  // Toggle hidden ContentElements
934  $numberOfHiddenElements = $this->getNumberOfHiddenElements($dbList->tt_contentConfig);
935  if ($numberOfHiddenElements > 0) {
936  $h_func_b = '
937  <div class="checkbox">
938  <label for="checkTt_content_showHidden">
939  <input type="checkbox" id="checkTt_content_showHidden" class="checkbox" name="SET[tt_content_showHidden]" value="1" ' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? 'checked="checked"' : '') . ' />
940  ' . htmlspecialchars($this->getLanguageService()->getLL('hiddenCE')) . ' (<span class="t3js-hidden-counter">' . $numberOfHiddenElements . '</span>)
941  </label>
942  </div>';
943  }
944  } else {
945  if (isset($this->MOD_SETTINGS) && isset($this->MOD_MENU)) {
946  $h_func = BackendUtility::getFuncMenu($this->id, 'SET[' . $table . ']', $this->MOD_SETTINGS[$table], $this->MOD_MENU[$table], '', '');
947  }
948  }
949  // Start the dblist object:
950  $dbList->itemsLimitSingleTable = 1000;
951  $dbList->start($this->id, $table, $this->pointer, $this->search_field, $this->search_levels, $this->showLimit);
952  $dbList->counter = $CMcounter;
953  $dbList->ext_function = $this->MOD_SETTINGS['function'];
954  // Render versioning selector:
955  $dbList->HTMLcode .= $this->moduleTemplate->getVersionSelector($this->id);
956  // Generate the list of elements here:
957  $dbList->generateList();
958  // Adding the list content to the tableOutput variable:
959  $tableOutput[$table] = $h_func . $dbList->HTMLcode . $h_func_b;
960  // ... and any accumulated JavaScript goes the same way!
961  $tableJSOutput[$table] = $dbList->JScode;
962  // Increase global counter:
963  $CMcounter += $dbList->counter;
964  // Reset variables after operation:
965  $dbList->HTMLcode = '';
966  $dbList->JScode = '';
967  }
968  // END: traverse tables
969  // For Context Sensitive Menus:
970  // Init the content
971  $content = '';
972  // Additional header content
973  $headerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'];
974  if (is_array($headerContentHook)) {
975  foreach ($headerContentHook as $hook) {
976  $params = [];
977  $content .= GeneralUtility::callUserFunction($hook, $params, $this);
978  }
979  }
980  // Add the content for each table we have rendered (traversing $tableOutput variable)
981  foreach ($tableOutput as $table => $output) {
982  $content .= $output;
983  }
984  // Making search form:
985  if (!$this->modTSconfig['properties']['disableSearchBox'] && ($dbList->counter > 0 || $this->currentPageHasSubPages())) {
986  $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
987  $toggleSearchFormButton = $this->buttonBar->makeLinkButton()
988  ->setClasses('t3js-toggle-search-toolbox')
989  ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.searchIcon'))
990  ->setIcon($this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL))
991  ->setHref('#');
992  $this->buttonBar->addButton($toggleSearchFormButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
993  $this->searchContent = $dbList->getSearchBox();
994  }
995  // Additional footer content
996  $footerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'];
997  if (is_array($footerContentHook)) {
998  foreach ($footerContentHook as $hook) {
999  $params = [];
1000  $content .= GeneralUtility::callUserFunction($hook, $params, $this);
1001  }
1002  }
1003  return $content;
1004  }
1005 
1009  public function getModuleTemplate()
1010  {
1011  return $this->moduleTemplate;
1012  }
1013 
1019  public function printContent()
1020  {
1022  echo $this->moduleTemplate->renderContent();
1023  }
1024 
1025  /***************************
1026  *
1027  * Sub-content functions, rendering specific parts of the module content.
1028  *
1029  ***************************/
1033  protected function makeButtons()
1034  {
1035  if ($this->MOD_SETTINGS['function'] == 1 || $this->MOD_SETTINGS['function'] == 2) {
1036  // Add CSH (Context Sensitive Help) icon to tool bar
1037  $contextSensitiveHelpButton = $this->buttonBar->makeHelpButton()
1038  ->setModuleName($this->descrTable)
1039  ->setFieldName('columns_' . $this->MOD_SETTINGS['function']);
1040  $this->buttonBar->addButton($contextSensitiveHelpButton);
1041  }
1042  $lang = $this->getLanguageService();
1043  // View page
1044  if (!VersionState::cast($this->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
1045  $viewButton = $this->buttonBar->makeLinkButton()
1046  ->setOnClick(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid'])))
1047  ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
1048  ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL))
1049  ->setHref('#');
1050 
1051  $this->buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1052  }
1053  // Shortcut
1054  $shortcutButton = $this->buttonBar->makeShortcutButton()
1055  ->setModuleName($this->moduleName)
1056  ->setGetVariables([
1057  'id',
1058  'M',
1059  'edit_record',
1060  'pointer',
1061  'new_unique_uid',
1062  'search_field',
1063  'search_levels',
1064  'showLimit'
1065  ])
1066  ->setSetVariables(array_keys($this->MOD_MENU));
1067  $this->buttonBar->addButton($shortcutButton);
1068 
1069  // Cache
1070  if (empty($this->modTSconfig['properties']['disableAdvanced'])) {
1071  $clearCacheButton = $this->buttonBar->makeLinkButton()
1072  ->setHref(BackendUtility::getModuleUrl($this->moduleName, ['id' => $this->pageinfo['uid'], 'clear_cache' => '1']))
1073  ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
1074  ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', Icon::SIZE_SMALL));
1075  $this->buttonBar->addButton($clearCacheButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
1076  }
1077  if (empty($this->modTSconfig['properties']['disableIconToolbar'])) {
1078  // Edit page properties and page language overlay icons
1079  if ($this->pageIsNotLockedForEditors() && $this->getBackendUser()->checkLanguageAccess(0)) {
1080  // Edit localized page_language_overlay only when one specific language is selected
1081  if ($this->MOD_SETTINGS['function'] == 1 && $this->current_sys_language > 0) {
1082  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1083  ->getQueryBuilderForTable('pages_language_overlay');
1084  $queryBuilder->getRestrictions()
1085  ->removeAll()
1086  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1087  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1088  $overlayRecord = $queryBuilder
1089  ->select('uid')
1090  ->from('pages_language_overlay')
1091  ->where(
1092  $queryBuilder->expr()->eq(
1093  'pid',
1094  $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
1095  ),
1096  $queryBuilder->expr()->eq(
1097  'sys_language_uid',
1098  $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
1099  )
1100  )
1101  ->setMaxResults(1)
1102  ->execute()
1103  ->fetch();
1104  // Edit button
1105  $urlParameters = [
1106  'edit' => [
1107  'pages_language_overlay' => [
1108  $overlayRecord['uid'] => 'edit'
1109  ]
1110  ],
1111  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
1112  ];
1113  $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
1114  $editLanguageButton = $this->buttonBar->makeLinkButton()
1115  ->setHref($url)
1116  ->setTitle($lang->getLL('editPageLanguageOverlayProperties'))
1117  ->setIcon($this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL));
1118  $this->buttonBar->addButton($editLanguageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1119  }
1120  $urlParameters = [
1121  'edit' => [
1122  'pages' => [
1123  $this->id => 'edit'
1124  ]
1125  ],
1126  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
1127  ];
1128  $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
1129  $editPageButton = $this->buttonBar->makeLinkButton()
1130  ->setHref($url)
1131  ->setTitle($lang->getLL('editPageProperties'))
1132  ->setIcon($this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL));
1133  $this->buttonBar->addButton($editPageButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
1134  }
1135  }
1136  }
1137 
1138  /*******************************
1139  *
1140  * Other functions
1141  *
1142  ******************************/
1150  public function getNumberOfHiddenElements(array $contentConfig = [])
1151  {
1153  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
1154  $queryBuilder->getRestrictions()
1155  ->removeAll()
1156  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1157  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1158 
1159  $queryBuilder
1160  ->count('uid')
1161  ->from('tt_content')
1162  ->where(
1163  $queryBuilder->expr()->eq(
1164  'pid',
1165  $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
1166  )
1167  );
1168 
1169  if (!empty($contentConfig['languageCols']) && is_array($contentConfig['languageCols'])) {
1170  // Multi-language view is active
1171  if ($this->current_sys_language > 0) {
1172  $queryBuilder->andWhere(
1173  $queryBuilder->expr()->in(
1174  'sys_language_uid',
1175  [0, $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)]
1176  )
1177  );
1178  }
1179  } else {
1180  $queryBuilder->andWhere(
1181  $queryBuilder->expr()->eq(
1182  'sys_language_uid',
1183  $queryBuilder->createNamedParameter($this->current_sys_language, \PDO::PARAM_INT)
1184  )
1185  );
1186  }
1187 
1188  if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'])) {
1189  $andWhere[] = $queryBuilder->expr()->neq(
1190  'hidden',
1191  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1192  );
1193  }
1194 
1195  if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'])) {
1196  $andWhere[] = $queryBuilder->expr()->andX(
1197  $queryBuilder->expr()->neq(
1198  'starttime',
1199  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1200  ),
1201  $queryBuilder->expr()->gt(
1202  'starttime',
1203  $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
1204  )
1205  );
1206  }
1207 
1208  if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'])) {
1209  $andWhere[] = $queryBuilder->expr()->andX(
1210  $queryBuilder->expr()->neq(
1211  'endtime',
1212  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1213  ),
1214  $queryBuilder->expr()->lte(
1215  'endtime',
1216  $queryBuilder->createNamedParameter($GLOBALS['SIM_ACCESS_TIME'], \PDO::PARAM_INT)
1217  )
1218  );
1219  }
1220 
1221  if (!empty($andWhere)) {
1222  $queryBuilder->andWhere(
1223  $queryBuilder->expr()->orX(...$andWhere)
1224  );
1225  }
1226 
1227  $count = $queryBuilder
1228  ->execute()
1229  ->fetchColumn(0);
1230 
1231  return (int)$count;
1232  }
1233 
1241  public function local_linkThisScript($params)
1242  {
1243  $params['popView'] = '';
1244  $params['new_unique_uid'] = '';
1245  return GeneralUtility::linkThisScript($params);
1246  }
1247 
1253  public function pageIsNotLockedForEditors()
1254  {
1255  return $this->getBackendUser()->isAdmin() || ($this->CALC_PERMS & Permission::PAGE_EDIT) === Permission::PAGE_EDIT && !$this->pageinfo['editlock'];
1256  }
1257 
1264  {
1265  return $this->getBackendUser()->isAdmin() || ($this->CALC_PERMS & Permission::CONTENT_EDIT) === Permission::CONTENT_EDIT && !$this->pageinfo['editlock'];
1266  }
1267 
1273  protected function getLanguageService()
1274  {
1275  return $GLOBALS['LANG'];
1276  }
1277 
1283  protected function getBackendUser()
1284  {
1285  return $GLOBALS['BE_USER'];
1286  }
1287 
1293  protected function getPageRenderer()
1294  {
1295  return GeneralUtility::makeInstance(PageRenderer::class);
1296  }
1297 
1301  protected function makeLanguageMenu()
1302  {
1303  if (count($this->MOD_MENU['language']) > 1) {
1304  $lang = $this->getLanguageService();
1305  $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
1306  $languageMenu->setIdentifier('languageMenu');
1307  foreach ($this->MOD_MENU['language'] as $key => $language) {
1308  $menuItem = $languageMenu
1309  ->makeMenuItem()
1310  ->setTitle($language)
1311  ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&SET[language]=' . $key);
1312  if ((int)$this->current_sys_language === $key) {
1313  $menuItem->setActive(true);
1314  }
1315  $languageMenu->addMenuItem($menuItem);
1316  }
1317  $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
1318  }
1319  }
1320 
1326  protected function currentPageHasSubPages()
1327  {
1329  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1330  $queryBuilder->getRestrictions()
1331  ->removeAll()
1332  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1333  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1334 
1335  // get workspace id
1336  $workspaceId = (int)$this->getBackendUser()->workspace;
1337  $comparisonExpression = $workspaceId === 0 ? 'neq' : 'eq';
1338 
1339  $count = $queryBuilder
1340  ->count('uid')
1341  ->from('pages')
1342  ->where(
1343  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)),
1344  $queryBuilder->expr()->eq(
1345  't3ver_wsid',
1346  $queryBuilder->createNamedParameter($workspaceId, \PDO::PARAM_INT)
1347  ),
1348  $queryBuilder->expr()->{$comparisonExpression}(
1349  'pid',
1350  $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
1351  )
1352  )
1353  ->execute()
1354  ->fetchColumn(0);
1355 
1356  return (bool)$count;
1357  }
1358 }
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static readPageAccess($id, $perms_clause)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static getModuleData( $MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
static viewOnClick( $pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static getFileAbsFileName($filename, $_=null, $_2=null)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static linkThisScript(array $getParams=[])
static makeInstance($className,... $constructorArguments)
mainAction(ServerRequestInterface $request, ResponseInterface $response)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static unsetMenuItems($modTSconfig, $itemArray, $TSref)
static getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static getFuncMenu( $mainParams, $elementName, $currentValue, $menuItems, $script='', $addParams='')
static getLabelFromItemlist($table, $col, $key)