‪TYPO3CMS  ‪main
PageLayoutController.php
Go to the documentation of this file.
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 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
36 use TYPO3\CMS\Backend\Utility\BackendUtility;
49 use TYPO3\CMS\Core\Imaging\IconSize;
58 
62 #[AsController]
64 {
68  protected int ‪$id = 0;
69 
73  protected array|bool ‪$pageinfo = false;
74 
76  protected array ‪$MOD_MENU;
77 
81  protected array ‪$availableLanguages = [];
82 
83  protected ?‪ModuleData ‪$moduleData = null;
84 
85  public function ‪__construct(
86  protected readonly ‪IconFactory $iconFactory,
87  protected readonly ‪PageRenderer $pageRenderer,
88  protected readonly ‪UriBuilder $uriBuilder,
89  protected readonly ‪PageRepository $pageRepository,
90  protected readonly ‪ModuleTemplateFactory $moduleTemplateFactory,
91  protected readonly EventDispatcherInterface $eventDispatcher,
92  protected readonly ‪ModuleProvider $moduleProvider,
93  protected readonly ‪BackendLayoutRenderer $backendLayoutRenderer,
94  protected readonly ‪BackendLayoutView $backendLayoutView,
95  ) {}
96 
97  protected function ‪initialize(ServerRequestInterface $request): void
98  {
99  $backendUser = $this->‪getBackendUser();
100  $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
101  $this->moduleData = $request->getAttribute('moduleData');
102  $this->pageinfo = BackendUtility::readPageAccess($this->id, $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW));
103  $this->availableLanguages = $request->getAttribute('site')->getAvailableLanguages($backendUser, false, $this->id);
104  $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
105  }
106 
111  public function ‪mainAction(ServerRequestInterface $request): ResponseInterface
112  {
113  $this->‪initialize($request);
114  $languageService = $this->‪getLanguageService();
115 
116  $view = $this->moduleTemplateFactory->create($request);
117  if ($this->id === 0 || $this->pageinfo === false) {
118  // Page uid 0 or no access.
119  $view->setTitle($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'));
120  $view->assignMultiple([
121  'pageId' => $this->id,
122  'siteName' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?? '',
123  ]);
124  return $view->renderResponse('PageLayout/PageModuleNoAccess');
125  }
126 
127  $tsConfig = BackendUtility::getPagesTSconfig($this->id);
128  $this->‪menuConfig();
129  $this->currentSelectedLanguage = (int)$this->moduleData->get('language');
131  $this->‪makeActionMenu($view, $tsConfig);
132  $this->‪makeButtons($view, $request, $tsConfig);
133  $this->‪initializeClipboard($request);
134  $event = $this->eventDispatcher->dispatch(new ‪ModifyPageLayoutContentEvent($request, $view));
135 
136  $pageLayoutContext = $this->‪createPageLayoutContext($request, $tsConfig);
137  $mainLayoutHtml = $this->backendLayoutRenderer->drawContent($request, $pageLayoutContext);
138  $numberOfHiddenElements = $this->‪getNumberOfHiddenElements($pageLayoutContext->getDrawingConfiguration());
139 
140  $pageLocalizationRecord = $this->‪getLocalizedPageRecord($this->currentSelectedLanguage);
141 
142  $view->setTitle($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'), $this->pageinfo['title']);
143  $view->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
144  $view->assignMultiple([
145  'pageId' => $this->id,
146  'localizedPageId' => $pageLocalizationRecord['uid'] ?? 0,
147  'pageLayoutContext' => $pageLayoutContext,
148  'infoBoxes' => $this->‪generateMessagesForCurrentPage($request),
149  'isPageEditable' => $this->‪isPageEditable($this->currentSelectedLanguage),
150  'localizedPageTitle' => $pageLocalizationRecord['title'] ?? $this->pageinfo['title'] ?? '',
151  'eventContentHtmlTop' => $event->getHeaderContent(),
152  'mainContentHtml' => $mainLayoutHtml,
153  'hiddenElementsShowToggle' => ($this->getBackendUser()->check('tables_select', 'tt_content') && ($numberOfHiddenElements > 0)),
154  'hiddenElementsCount' => $numberOfHiddenElements,
155  'eventContentHtmlBottom' => $event->getFooterContent(),
156  ]);
157  return $view->renderResponse('PageLayout/PageModule');
158  }
159 
160  protected function ‪createPageLayoutContext(ServerRequestInterface $request, array $tsConfig): ‪PageLayoutContext
161  {
162  $backendLayout = $this->backendLayoutView->getBackendLayoutForPage($this->id);
163  $viewMode = (int)$this->moduleData->get('function') === 2 ? ‪PageViewMode::LanguageComparisonView : PageViewMode::LayoutView;
164  $configuration = ‪DrawingConfiguration::create($backendLayout, $tsConfig, $viewMode);
165  $configuration->setShowHidden((bool)$this->moduleData->get('showHidden'));
166  $configuration->setLanguageColumns($this->MOD_MENU['language']);
167  $configuration->setSelectedLanguageId($this->currentSelectedLanguage);
168  return GeneralUtility::makeInstance(PageLayoutContext::class, $this->pageinfo, $backendLayout, $request->getAttribute('site'), $configuration, $request);
169  }
170 
174  protected function ‪menuConfig(): void
175  {
176  $backendUser = $this->‪getBackendUser();
177  $languageService = $this->‪getLanguageService();
178 
179  // MENU-ITEMS:
180  $this->MOD_MENU = [
181  'function' => [
182  1 => $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.layout'),
183  2 => $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.language_comparison'),
184  ],
185  'language' => [
186  0 => isset($this->availableLanguages[0]) ? $this->availableLanguages[0]->getTitle() : $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:m_default'),
187  ],
188  ];
189 
190  // First, select all localized page records on the current page.
191  // Each represents a possibility for a language on the page. Add these to language selector.
192  if ($this->id) {
193  // Compile language data for pid != 0 only. The language drop-down is not shown on pid 0
194  // since pid 0 can't be localized.
195  $pageTranslations = BackendUtility::getExistingPageTranslations($this->id);
196  foreach ($pageTranslations as $pageTranslation) {
197  $languageId = $pageTranslation[‪$GLOBALS['TCA']['pages']['ctrl']['languageField']];
198  if (isset($this->availableLanguages[$languageId])) {
199  $this->MOD_MENU['language'][$languageId] = $this->availableLanguages[$languageId]->getTitle();
200  }
201  }
202 
203  // Add special "-1" in case translations of the current page exist
204  if (count($this->MOD_MENU['language']) > 1) {
205  // We need to add -1 (all) here so a possible -1 value will be allowed when calling
206  // moduleData->cleanUp(). Actually, this is only relevant if we are dealing with the
207  // "languages" mode, which however can only be safely determined, after the moduleData
208  // have been cleaned up => chicken and egg problem. We therefore remove the -1 item from
209  // the menu again, as soon as we are able to determine the requested mode.
210  // @todo Replace the whole "mode" handling with some more robust solution
211  $this->MOD_MENU['language'][-1] = $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:multipleLanguages');
212  }
213  }
214  // Clean up settings
215  if ($this->moduleData->cleanUp($this->MOD_MENU)) {
216  $backendUser->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
217  }
218  if ($backendUser->workspace !== 0) {
219  // Show all elements in draft workspaces
220  $this->moduleData->set('showHidden', true);
221  }
222  if ((int)$this->moduleData->get('function') !== 2) {
223  // Remove -1 (all) from the module menu if not "languages" mode
224  unset($this->MOD_MENU['language'][-1]);
225  // In case -1 (all) is still set as language, but we are no longer in
226  // "languages" mode, we fall back to the default, preventing an empty grid.
227  if ((int)$this->moduleData->get('language') === -1) {
228  $this->moduleData->set('language', 0);
229  }
230  }
231  }
232 
233  protected function ‪getLocalizedPageRecord(int $languageId): ?array
234  {
235  if ($languageId === 0) {
236  return null;
237  }
238  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
239  $queryBuilder->getRestrictions()
240  ->removeAll()
241  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
242  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace));
243  $overlayRecord = $queryBuilder
244  ->select('*')
245  ->from('pages')
246  ->where(
247  $queryBuilder->expr()->eq(
248  ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
249  $queryBuilder->createNamedParameter($this->id, ‪Connection::PARAM_INT)
250  ),
251  $queryBuilder->expr()->eq(
252  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
253  $queryBuilder->createNamedParameter($languageId, ‪Connection::PARAM_INT)
254  )
255  )
256  ->setMaxResults(1)
257  ->executeQuery()
258  ->fetchAssociative();
259  if ($overlayRecord) {
260  BackendUtility::workspaceOL('pages', $overlayRecord, $this->‪getBackendUser()->workspace);
261  }
262  return is_array($overlayRecord) ? $overlayRecord : null;
263  }
264 
269  protected function ‪makeActionMenu(‪ModuleTemplate $view, array $tsConfig): void
270  {
271  $languageService = $this->‪getLanguageService();
272  $actions = [
273  1 => $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.layout'),
274  ];
275  // Find if there are ANY languages at all (and if not, do not show the language option from function menu).
276  // The second check is for an edge case: Only two languages in the site and the default is not allowed.
277  if (count($this->availableLanguages) > 1 || (int)array_key_first($this->availableLanguages) > 0) {
278  $actions[2] = $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view.language_comparison');
279  }
280  // Page / user TSconfig blinding of menu-items
281  $blindActions = $tsConfig['mod.']['web_layout.']['menu.']['functions.'] ?? [];
282  foreach ($blindActions as $key => $value) {
283  if (!$value && array_key_exists($key, $actions)) {
284  unset($actions[$key]);
285  }
286  }
287 
288  $actionMenu = $view->‪getDocHeaderComponent()->getMenuRegistry()->makeMenu();
289  $actionMenu->setIdentifier('actionMenu');
290  $actionMenu->setLabel(
291  $languageService->sL(
292  'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:pagelayout.moduleMenu.dropdown.label'
293  )
294  );
295  $defaultKey = null;
296  $foundDefaultKey = false;
297  foreach ($actions as $key => $action) {
298  $menuItem = $actionMenu
299  ->makeMenuItem()
300  ->setTitle($action)
301  ->setHref((string)$this->uriBuilder->buildUriFromRoute('web_layout', ['id' => $this->id, 'function' => $key]));
302  if (!$foundDefaultKey) {
303  $defaultKey = $key;
304  $foundDefaultKey = true;
305  }
306  if ((int)$this->moduleData->get('function') === $key) {
307  $menuItem->setActive(true);
308  $defaultKey = null;
309  }
310  $actionMenu->addMenuItem($menuItem);
311  }
312  if (isset($defaultKey)) {
313  $this->moduleData->set('function', $defaultKey);
314  }
315  $view->‪getDocHeaderComponent()->getMenuRegistry()->addMenu($actionMenu);
316  }
317 
322  protected function ‪generateMessagesForCurrentPage(ServerRequestInterface $request): array
323  {
324  $languageService = $this->‪getLanguageService();
325  $backendUser = $this->‪getBackendUser();
326 
327  $infoBoxes = [];
328  $currentDocumentType = (int)$this->pageinfo['doktype'];
329  if ($currentDocumentType === ‪PageRepository::DOKTYPE_SYSFOLDER && $this->moduleProvider->accessGranted('web_list', $backendUser)) {
330  $infoBoxes[] = [
331  'title' => $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:goToListModule'),
332  'message' => '<p>' . $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:goToListModuleMessage') . '</p>'
333  . '<a class="btn btn-primary" data-dispatch-action="TYPO3.ModuleMenu.showModule" data-dispatch-args-list="web_list">'
334  . $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:goToListModule')
335  . '</a>',
337  ];
338  }
339  if ($currentDocumentType === ‪PageRepository::DOKTYPE_SHORTCUT) {
340  $shortcutMode = (int)$this->pageinfo['shortcut_mode'];
341  $targetPage = [];
342  $message = '';
344  if ($shortcutMode || $this->pageinfo['shortcut']) {
345  switch ($shortcutMode) {
347  $targetPage = $this->‪getTargetPageIfVisible($this->pageRepository->getPage((int)$this->pageinfo['shortcut'], true));
348  $message = $targetPage === [] ? $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredOrNotAccessibleInternalLinkMessage') : '';
349  break;
351  $menuOfPages = $this->pageRepository->getMenu($this->pageinfo['uid'], '*', 'sorting', 'AND hidden = 0', true, true);
352  $targetPage = reset($menuOfPages) ?: [];
353  $message = $targetPage === [] ? $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredFirstSubpageMessage') : '';
354  break;
356  $targetPage = $this->‪getTargetPageIfVisible($this->pageRepository->getPage((int)$this->pageinfo['pid'], true));
357  $message = $targetPage === [] ? $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredParentPageMessage') : '';
358  break;
360  $possibleTargetPages = $this->pageRepository->getMenu($this->pageinfo['uid'], '*', 'sorting', 'AND hidden = 0', true, true);
361  if ($possibleTargetPages === []) {
362  $message = $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredOrNotAccessibleRandomInternalLinkMessage');
363  } else {
364  $message = $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsRandomInternalLinkMessage');
366  }
367  break;
368  }
369  $message = htmlspecialchars($message);
370  if ($targetPage !== [] && $shortcutMode !== ‪PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
371  $linkToPid = $this->uriBuilder->buildUriFromRoute('web_layout', ['id' => $targetPage['uid']]);
372  $path = BackendUtility::getRecordPath($targetPage['uid'], $backendUser->getPagePermsClause(‪Permission::PAGE_SHOW), 1000);
373  $linkedPath = '<a href="' . htmlspecialchars((string)$linkToPid) . '">' . htmlspecialchars($path) . '</a>';
374  $message .= sprintf(htmlspecialchars($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsInternalLinkMessage')), $linkedPath);
375  $message .= ' (' . htmlspecialchars($languageService->sL(BackendUtility::getLabelFromItemlist('pages', 'shortcut_mode', (string)$shortcutMode, $this->pageinfo))) . ')';
377  }
378  } else {
379  $message = htmlspecialchars($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredInternalLinkMessage'));
381  }
382  $infoBoxes[] = [
383  'message' => $message,
384  'state' => $state,
385  ];
386  }
387  if ($currentDocumentType === ‪PageRepository::DOKTYPE_LINK) {
388  if (empty($this->pageinfo['url'])) {
389  $infoBoxes[] = [
390  'message' => $languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsMisconfiguredExternalLinkMessage'),
392  ];
393  } else {
394  $externalUrl = $this->‪resolveExternalUrl($this->pageinfo, $request);
395  if ($externalUrl !== '') {
396  $externalUrl = htmlspecialchars($externalUrl);
397  $externalUrlHtml = '<a href="' . $externalUrl . '" target="_blank" rel="noreferrer">' . $externalUrl . '</a>';
398  $infoBoxes[] = [
399  'message' => sprintf($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:pageIsExternalLinkMessage'), $externalUrlHtml),
401  ];
402  }
403  }
404  }
405  if ($this->pageinfo['content_from_pid']) {
406  // If content from different pid is displayed
407  $contentPage = BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
408  if ($contentPage === null) {
409  $infoBoxes[] = [
410  'message' => sprintf($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content_from_pid_invalid_title'), $this->pageinfo['content_from_pid']),
412  ];
413  } else {
414  $linkToPid = $this->uriBuilder->buildUriFromRoute('web_layout', ['id' => $this->pageinfo['content_from_pid']]);
415  $title = BackendUtility::getRecordTitle('pages', $contentPage);
416  $link = '<a href="' . htmlspecialchars((string)$linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
417  $infoBoxes[] = [
418  'message' => sprintf($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content_from_pid_title'), $link),
420  ];
421  }
422  } else {
423  $links = $this->‪getPageLinksWhereContentIsAlsoShownOn((int)$this->pageinfo['uid']);
424  if (!empty($links)) {
425  $infoBoxes[] = [
426  'message' => sprintf($languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content_on_pid_title'), $links),
428  ];
429  }
430  }
431  return $infoBoxes;
432  }
433 
434  protected function ‪addJavaScriptModuleInstructions(): void
435  {
436  $this->pageRenderer->getJavaScriptRenderer()->addJavaScriptModuleInstruction(
437  ‪JavaScriptModuleInstruction::create('@typo3/backend/page-actions.js')
438  );
439  }
440 
444  protected function ‪getPageLinksWhereContentIsAlsoShownOn(int $pageId): string
445  {
446  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
447  $queryBuilder->getRestrictions()->removeAll();
448  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
449  $queryBuilder->select('*')
450  ->from('pages')
451  ->where($queryBuilder->expr()->eq('content_from_pid', $queryBuilder->createNamedParameter($pageId, ‪Connection::PARAM_INT)));
452  $links = [];
453  $rows = $queryBuilder->executeQuery()->fetchAllAssociative();
454  if (!empty($rows)) {
455  foreach ($rows as $row) {
456  $linkToPid = $this->uriBuilder->buildUriFromRoute('web_layout', ['id' => $row['uid']]);
457  $title = BackendUtility::getRecordTitle('pages', $row);
458  $link = '<a href="' . htmlspecialchars((string)$linkToPid) . '">' . htmlspecialchars($title) . ' (PID ' . (int)$row['uid'] . ')</a>';
459  $links[] = $link;
460  }
461  }
462  return implode(', ', $links);
463  }
464 
468  protected function ‪initializeClipboard(ServerRequestInterface $request): void
469  {
470  $clipboard = GeneralUtility::makeInstance(Clipboard::class);
471  $clipboard->initializeClipboard($request);
472  $clipboard->lockToNormal();
473  $clipboard->cleanCurrent();
474  $clipboard->endClipboard();
475  $elFromTable = $clipboard->elFromTable('tt_content');
476  if (!empty($elFromTable) && $this->‪isContentEditable($this->currentSelectedLanguage)) {
477  $pasteItem = (int)substr((string)key($elFromTable), 11);
478  $pasteRecord = BackendUtility::getRecordWSOL('tt_content', $pasteItem);
479  $pasteTitle = BackendUtility::getRecordTitle('tt_content', $pasteRecord);
480  $this->pageRenderer->getJavaScriptRenderer()->addJavaScriptModuleInstruction(
481  ‪JavaScriptModuleInstruction::create('@typo3/backend/layout-module/paste.js')
482  ->instance([
483  'itemOnClipboardUid' => $pasteItem,
484  'itemOnClipboardTitle' => $pasteTitle,
485  'copyMode' => $clipboard->clipData['normal']['mode'] ?? '',
486  ])
487  );
488  }
489  }
490 
494  protected function ‪makeButtons(‪ModuleTemplate $view, ServerRequestInterface $request, array $tsConfig): void
495  {
496  $languageService = $this->‪getLanguageService();
497  $buttonBar = $view->‪getDocHeaderComponent()->getButtonBar();
498 
499  // Language
500  if ($languageButton = $this->‪makeLanguageSwitchButton($buttonBar)) {
501  $buttonBar->addButton($languageButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 0);
502  }
503 
504  // View
505  if ($viewButton = $this->‪makeViewButton($buttonBar, $tsConfig)) {
506  $buttonBar->addButton($viewButton);
507  }
508 
509  // Edit
510  if ($editButton = $this->‪makeEditButton($buttonBar, $request)) {
511  $buttonBar->addButton($editButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 2);
512  }
513 
514  // Shortcut
515  $shortcutButton = $buttonBar->makeShortcutButton()
516  ->setRouteIdentifier('web_layout')
517  ->setDisplayName($this->‪getShortcutTitle())
518  ->setArguments([
519  'id' => $this->id,
520  'showHidden' => (bool)$this->moduleData->get('showHidden'),
521  'function' => (int)$this->moduleData->get('function'),
522  'language' => $this->currentSelectedLanguage,
523  ]);
524  $buttonBar->addButton($shortcutButton);
525 
526  // Cache
527  $clearCacheButton = $buttonBar->makeLinkButton()
528  ->setHref('#')
529  ->setDataAttributes(['id' => $this->pageinfo['uid']])
530  ->setClasses('t3js-clear-page-cache')
531  ->setTitle($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.clear_cache'))
532  ->setIcon($this->iconFactory->getIcon('actions-system-cache-clear', IconSize::SMALL));
533  $buttonBar->addButton($clearCacheButton, ‪ButtonBar::BUTTON_POSITION_RIGHT, 1);
534 
535  // Reload
536  $reloadButton = $buttonBar->makeLinkButton()
537  ->setHref($request->getAttribute('normalizedParams')->getRequestUri())
538  ->setTitle($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
539  ->setIcon($this->iconFactory->getIcon('actions-refresh', IconSize::SMALL));
540  $buttonBar->addButton($reloadButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
541  }
542 
546  protected function ‪makeViewButton(‪ButtonBar $buttonBar, array $tsConfig): ?‪ButtonInterface
547  {
548  // Do not create a "View webpage" button if
549  // * "All languages" is selected
550  // * not in "Columns" view,
551  // * record is a placeholder
552  if (
553  $this->currentSelectedLanguage === -1
554  || (int)$this->moduleData->get('function') !== 1
555  || VersionState::tryFrom($this->pageinfo['t3ver_state'] ?? 0) === VersionState::DELETE_PLACEHOLDER
556  ) {
557  return null;
558  }
559 
560  if (isset($tsConfig['TCEMAIN.']['preview.']['disableButtonForDokType'])) {
561  // Exclude doktypes, set via tsConfig
562  $excludeDokTypes = ‪GeneralUtility::intExplode(',', (string)($tsConfig['TCEMAIN.']['preview.']['disableButtonForDokType'] ?? ''), true);
563  } else {
564  // Exclude default doktypes: sysfolders and spacers
565  $excludeDokTypes = [
568  ];
569  }
570 
571  if (in_array((int)$this->pageinfo['doktype'], $excludeDokTypes, true)) {
572  return null;
573  }
574 
575  $previewDataAttributes = ‪PreviewUriBuilder::create((int)$this->pageinfo['uid'])
576  ->withRootLine(BackendUtility::BEgetRootLine($this->pageinfo['uid']))
577  ->withLanguage($this->currentSelectedLanguage)
578  ->buildDispatcherDataAttributes();
579 
580  return $buttonBar->‪makeLinkButton()
581  ->‪setHref('#')
582  ->‪setDataAttributes($previewDataAttributes ?? [])
583  ->setDisabled(!$previewDataAttributes)
584  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
585  ->setIcon($this->iconFactory->getIcon('actions-view-page', IconSize::SMALL))
586  ->setShowLabelText(true);
587  }
588 
592  protected function ‪makeEditButton(‪ButtonBar $buttonBar, ServerRequestInterface $request): ?‪ButtonInterface
593  {
594  if ((int)$this->moduleData->get('function') !== 1
595  || !$this->isPageEditable($this->currentSelectedLanguage)
596  ) {
597  return null;
598  }
599 
600  $pageUid = ‪$this->id;
601  if ($this->currentSelectedLanguage > 0) {
602  $overlayRecord = $this->‪getLocalizedPageRecord($this->currentSelectedLanguage);
603  $pageUid = $overlayRecord['uid'];
604  }
605  $params = [
606  'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
607  'edit' => [
608  'pages' => [
609  $pageUid => 'edit',
610  ],
611  ],
612  ];
613 
614  return $buttonBar->‪makeLinkButton()
615  ->‪setHref((string)$this->uriBuilder->buildUriFromRoute('record_edit', $params))
616  ->‪setTitle($this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:editPageProperties'))
617  ->setShowLabelText(true)
618  ->setIcon($this->iconFactory->getIcon('actions-page-open', IconSize::SMALL));
619  }
620 
625  {
626  // Early return if less than 2 languages are available
627  if (count($this->MOD_MENU['language']) < 2) {
628  return null;
629  }
630 
631  $languageService = $this->‪getLanguageService();
632 
633  $languageDropDownButton = $buttonbar->‪makeDropDownButton()
634  ->‪setLabel($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.language'))
635  ->setShowLabelText(true);
636 
637  foreach ($this->MOD_MENU['language'] as $key => $language) {
638  $siteLanguage = $this->availableLanguages[$key] ?? null;
639  if (!$siteLanguage instanceof ‪SiteLanguage) {
640  // Skip invalid language keys, e.g. "-1" for "all languages"
641  continue;
642  }
644  $languageItem = GeneralUtility::makeInstance(DropDownRadio::class)
645  ->setActive($this->currentSelectedLanguage === $siteLanguage->getLanguageId())
646  ->setIcon($this->iconFactory->getIcon($siteLanguage->getFlagIdentifier()))
647  ->setHref((string)$this->uriBuilder->buildUriFromRoute('web_layout', [
648  'id' => $this->id,
649  'function' => (int)$this->moduleData->get('function'),
650  'language' => $siteLanguage->getLanguageId(),
651  ]))
652  ->setLabel($siteLanguage->getTitle());
653  $languageDropDownButton->addItem($languageItem);
654  }
655 
656  if ((int)$this->moduleData->get('function') !== 1) {
658  $allLanguagesItem = GeneralUtility::makeInstance(DropDownRadio::class)
659  ->setActive($this->currentSelectedLanguage === -1)
660  ->setIcon($this->iconFactory->getIcon('flags-multiple'))
661  ->setHref((string)$this->uriBuilder->buildUriFromRoute('web_layout', [
662  'id' => $this->id,
663  'function' => (int)$this->moduleData->get('function'),
664  'language' => -1,
665  ]))
666  ->setLabel($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:multipleLanguages'));
667  $languageDropDownButton->addItem($allLanguagesItem);
668  }
669 
670  return $languageDropDownButton;
671  }
672 
677  protected function ‪getNumberOfHiddenElements(‪DrawingConfiguration $drawingConfiguration): int
678  {
679  $isLanguageComparisonModeActive = $drawingConfiguration->‪isLanguageComparisonMode();
680  $andWhere = [];
681  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
682  $queryBuilder->getRestrictions()
683  ->removeAll()
684  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
685  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace));
686  $queryBuilder
687  ->count('uid')
688  ->from('tt_content')
689  ->where(
690  $queryBuilder->expr()->eq(
691  'pid',
692  $queryBuilder->createNamedParameter($this->id, ‪Connection::PARAM_INT)
693  )
694  );
695 
696  if ($this->currentSelectedLanguage === 0) {
697  // Default language is active (in columns or language mode) - consider "all languages" and the default
698  $queryBuilder->andWhere(
699  $queryBuilder->expr()->in(
700  ‪$GLOBALS['TCA']['tt_content']['ctrl']['languageField'],
701  [-1, 0]
702  )
703  );
704  } elseif ($isLanguageComparisonModeActive && $this->currentSelectedLanguage !== -1) {
705  // Multi-language view with any translation is active -
706  // consider "all languages", the default and the translation
707  $queryBuilder->andWhere(
708  $queryBuilder->expr()->in(
709  ‪$GLOBALS['TCA']['tt_content']['ctrl']['languageField'],
710  [-1, 0, $queryBuilder->createNamedParameter($this->currentSelectedLanguage, ‪Connection::PARAM_INT)]
711  )
712  );
713  } elseif ($this->currentSelectedLanguage > 0) {
714  // Columns mode with any translation is active - consider "all languages" and the translation
715  $queryBuilder->andWhere(
716  $queryBuilder->expr()->in(
717  ‪$GLOBALS['TCA']['tt_content']['ctrl']['languageField'],
718  [-1, $queryBuilder->createNamedParameter($this->currentSelectedLanguage, ‪Connection::PARAM_INT)]
719  )
720  );
721  }
722 
723  if (!empty(‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'])) {
724  $andWhere[] = $queryBuilder->expr()->neq(
725  ‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'],
726  $queryBuilder->createNamedParameter(0, ‪Connection::PARAM_INT)
727  );
728  }
729  if (!empty(‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'])) {
730  $starttimeField = ‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['starttime'];
731  $andWhere[] = $queryBuilder->expr()->and(
732  $queryBuilder->expr()->neq(
733  $starttimeField,
734  $queryBuilder->createNamedParameter(0, ‪Connection::PARAM_INT)
735  ),
736  $queryBuilder->expr()->gt(
737  $starttimeField,
738  $queryBuilder->createNamedParameter(‪$GLOBALS['SIM_ACCESS_TIME'], ‪Connection::PARAM_INT)
739  )
740  );
741  }
742  if (!empty(‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'])) {
743  $endtimeField = ‪$GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['endtime'];
744  $andWhere[] = $queryBuilder->expr()->and(
745  $queryBuilder->expr()->neq(
746  $endtimeField,
747  $queryBuilder->createNamedParameter(0, ‪Connection::PARAM_INT)
748  ),
749  $queryBuilder->expr()->lte(
750  $endtimeField,
751  $queryBuilder->createNamedParameter(‪$GLOBALS['SIM_ACCESS_TIME'], ‪Connection::PARAM_INT)
752  )
753  );
754  }
755  if (!empty($andWhere)) {
756  $queryBuilder->andWhere(
757  $queryBuilder->expr()->or(...$andWhere)
758  );
759  }
760  $count = $queryBuilder
761  ->executeQuery()
762  ->fetchOne();
763  return (int)$count;
764  }
765 
769  protected function ‪isPageEditable(int $languageId): bool
770  {
771  if (‪$GLOBALS['TCA']['pages']['ctrl']['readOnly'] ?? false) {
772  return false;
773  }
774  $backendUser = $this->‪getBackendUser();
775  if ($backendUser->isAdmin()) {
776  return true;
777  }
778  if (‪$GLOBALS['TCA']['pages']['ctrl']['adminOnly'] ?? false) {
779  return false;
780  }
781  return is_array($this->pageinfo)
782  && $this->pageinfo !== []
783  && !(bool)($this->pageinfo[‪$GLOBALS['TCA']['pages']['ctrl']['editlock'] ?? null] ?? false)
784  && $backendUser->doesUserHaveAccess($this->pageinfo, ‪Permission::PAGE_EDIT)
785  && $backendUser->checkLanguageAccess($languageId)
786  && $backendUser->check('tables_modify', 'pages');
787  }
788 
792  protected function ‪isContentEditable(int $languageId): bool
793  {
794  if ($this->‪getBackendUser()->isAdmin()) {
795  return true;
796  }
797  return !($this->pageinfo['editlock'] ?? false)
798  && $this->‪getBackendUser()->doesUserHaveAccess($this->pageinfo, ‪Permission::CONTENT_EDIT)
799  && $this->‪getBackendUser()->check('tables_modify', 'tt_content')
800  && $this->‪getBackendUser()->checkLanguageAccess($languageId);
801  }
802 
806  protected function ‪getTargetPageIfVisible(array $targetPage): array
807  {
808  return !($targetPage['hidden'] ?? false) ? $targetPage : [];
809  }
810 
814  protected function ‪getShortcutTitle(): string
815  {
816  return sprintf(
817  '%s: %s [%d]',
818  $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tablabel'),
819  BackendUtility::getRecordTitle('pages', (array)$this->pageinfo),
820  $this->id
821  );
822  }
823 
827  protected function ‪resolveExternalUrl(array $pagerow, ServerRequestInterface $request): string
828  {
829  $redirectTo = (string)($pagerow['url'] ?? '');
830  if ($redirectTo === '') {
831  return '';
832  }
833  $urlInformation = parse_url($redirectTo);
834  // If relative path, prefix Site URL
835  // If it's a valid email without protocol, add "mailto:"
836  if (!($urlInformation['scheme'] ?? false)) {
837  if (GeneralUtility::validEmail($redirectTo)) {
838  $redirectTo = 'mailto:' . $redirectTo;
839  } elseif ($redirectTo[0] !== '/') {
840  $redirectTo = $request->getAttribute('normalizedParams')->getSiteUrl() . $redirectTo;
841  }
842  }
843  return $redirectTo;
844  }
845 
847  {
848  return ‪$GLOBALS['LANG'];
849  }
850 
852  {
853  return ‪$GLOBALS['BE_USER'];
854  }
855 }
‪TYPO3\CMS\Backend\Controller\PageLayoutController\isPageEditable
‪isPageEditable(int $languageId)
Definition: PageLayoutController.php:769
‪TYPO3\CMS\Backend\View\LanguageComparisonView
‪@ LanguageComparisonView
Definition: PageViewMode.php:34
‪TYPO3\CMS\Backend\Controller\PageLayoutController\menuConfig
‪menuConfig()
Definition: PageLayoutController.php:174
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_LEFT
‪const BUTTON_POSITION_LEFT
Definition: ButtonBar.php:37
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:33
‪TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration\isLanguageComparisonMode
‪isLanguageComparisonMode()
Definition: DrawingConfiguration.php:125
‪TYPO3\CMS\Backend\Clipboard\Clipboard
Definition: Clipboard.php:48
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\makeDropDownButton
‪DropDownButton makeDropDownButton()
Definition: ButtonBar.php:122
‪TYPO3\CMS\Backend\Controller\PageLayoutController\initializeClipboard
‪initializeClipboard(ServerRequestInterface $request)
Definition: PageLayoutController.php:468
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:33
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$availableLanguages
‪array $availableLanguages
Definition: PageLayoutController.php:81
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getLocalizedPageRecord
‪getLocalizedPageRecord(int $languageId)
Definition: PageLayoutController.php:233
‪TYPO3\CMS\Core\Versioning\VersionState
‪VersionState
Definition: VersionState.php:22
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_INFO
‪const STATE_INFO
Definition: InfoboxViewHelper.php:68
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getLanguageService
‪getLanguageService()
Definition: PageLayoutController.php:846
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SHORTCUT
‪const DOKTYPE_SHORTCUT
Definition: PageRepository.php:100
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_LINK
‪const DOKTYPE_LINK
Definition: PageRepository.php:99
‪TYPO3\CMS\Backend\Module\ModuleData
Definition: ModuleData.php:30
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_ERROR
‪const STATE_ERROR
Definition: InfoboxViewHelper.php:71
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getTargetPageIfVisible
‪getTargetPageIfVisible(array $targetPage)
Definition: PageLayoutController.php:806
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Controller\Event\ModifyPageLayoutContentEvent
Definition: ModifyPageLayoutContentEvent.php:27
‪TYPO3\CMS\Backend\Controller\PageLayoutController\makeButtons
‪makeButtons(ModuleTemplate $view, ServerRequestInterface $request, array $tsConfig)
Definition: PageLayoutController.php:494
‪TYPO3\CMS\Backend\Module\ModuleProvider
Definition: ModuleProvider.php:29
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_RANDOM_SUBPAGE
‪const SHORTCUT_MODE_RANDOM_SUBPAGE
Definition: PageRepository.php:111
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:46
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_FIRST_SUBPAGE
‪const SHORTCUT_MODE_FIRST_SUBPAGE
Definition: PageRepository.php:110
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Backend\Controller\PageLayoutController\createPageLayoutContext
‪createPageLayoutContext(ServerRequestInterface $request, array $tsConfig)
Definition: PageLayoutController.php:160
‪TYPO3\CMS\Backend\Controller\PageLayoutController\mainAction
‪mainAction(ServerRequestInterface $request)
Definition: PageLayoutController.php:111
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:27
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getShortcutTitle
‪getShortcutTitle()
Definition: PageLayoutController.php:814
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$currentSelectedLanguage
‪int $currentSelectedLanguage
Definition: PageLayoutController.php:75
‪TYPO3\CMS\Backend\Controller\PageLayoutController\makeViewButton
‪makeViewButton(ButtonBar $buttonBar, array $tsConfig)
Definition: PageLayoutController.php:546
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:44
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownRadio
Definition: DropDownRadio.php:54
‪TYPO3\CMS\Backend\Controller\PageLayoutController
Definition: PageLayoutController.php:64
‪TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration\create
‪static create(BackendLayout $backendLayout, array $pageTsConfig, PageViewMode $pageViewMode)
Definition: DrawingConfiguration.php:84
‪TYPO3\CMS\Backend\Controller\PageLayoutController\__construct
‪__construct(protected readonly IconFactory $iconFactory, protected readonly PageRenderer $pageRenderer, protected readonly UriBuilder $uriBuilder, protected readonly PageRepository $pageRepository, protected readonly ModuleTemplateFactory $moduleTemplateFactory, protected readonly EventDispatcherInterface $eventDispatcher, protected readonly ModuleProvider $moduleProvider, protected readonly BackendLayoutRenderer $backendLayoutRenderer, protected readonly BackendLayoutView $backendLayoutView,)
Definition: PageLayoutController.php:85
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDown\DropDownItemInterface
Definition: DropDownItemInterface.php:19
‪TYPO3\CMS\Backend\Controller\PageLayoutController\initialize
‪initialize(ServerRequestInterface $request)
Definition: PageLayoutController.php:97
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$moduleData
‪ModuleData $moduleData
Definition: PageLayoutController.php:83
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder\create
‪static static create(int $pageId)
Definition: PreviewUriBuilder.php:65
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$pageinfo
‪array bool $pageinfo
Definition: PageLayoutController.php:73
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:103
‪TYPO3\CMS\Backend\Controller\PageLayoutController\resolveExternalUrl
‪resolveExternalUrl(array $pagerow, ServerRequestInterface $request)
Definition: PageLayoutController.php:827
‪TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer
Definition: BackendLayoutRenderer.php:47
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:35
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:104
‪TYPO3\CMS\Backend\Template\Components\Buttons\DropDownButton\setLabel
‪setLabel(string $label)
Definition: DropDownButton.php:72
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getNumberOfHiddenElements
‪getNumberOfHiddenElements(DrawingConfiguration $drawingConfiguration)
Definition: PageLayoutController.php:677
‪TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration
Definition: DrawingConfiguration.php:37
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\makeLinkButton
‪LinkButton makeLinkButton()
Definition: ButtonBar.php:132
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_PARENT_PAGE
‪const SHORTCUT_MODE_PARENT_PAGE
Definition: PageRepository.php:112
‪TYPO3\CMS\Backend\Controller\PageLayoutController\generateMessagesForCurrentPage
‪generateMessagesForCurrentPage(ServerRequestInterface $request)
Definition: PageLayoutController.php:322
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Backend\Controller\PageLayoutController\makeActionMenu
‪makeActionMenu(ModuleTemplate $view, array $tsConfig)
Definition: PageLayoutController.php:269
‪TYPO3\CMS\Backend\Template\ModuleTemplate\getDocHeaderComponent
‪getDocHeaderComponent()
Definition: ModuleTemplate.php:181
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$MOD_MENU
‪array $MOD_MENU
Definition: PageLayoutController.php:76
‪TYPO3\CMS\Core\Type\Bitmask\Permission\CONTENT_EDIT
‪const CONTENT_EDIT
Definition: Permission.php:55
‪TYPO3\CMS\Backend\View\PageViewMode
‪PageViewMode
Definition: PageViewMode.php:27
‪TYPO3\CMS\Backend\View\BackendLayoutView
Definition: BackendLayoutView.php:37
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_NONE
‪const SHORTCUT_MODE_NONE
Definition: PageRepository.php:109
‪TYPO3\CMS\Backend\View\PageLayoutContext
Definition: PageLayoutContext.php:42
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder
Definition: PreviewUriBuilder.php:44
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_EDIT
‪const PAGE_EDIT
Definition: Permission.php:40
‪TYPO3\CMS\Backend\Attribute\AsController
Definition: AsController.php:25
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper
Definition: InfoboxViewHelper.php:65
‪TYPO3\CMS\Backend\Controller\PageLayoutController\$id
‪int $id
Definition: PageLayoutController.php:68
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:69
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getPageLinksWhereContentIsAlsoShownOn
‪getPageLinksWhereContentIsAlsoShownOn(int $pageId)
Definition: PageLayoutController.php:444
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Controller\PageLayoutController\makeEditButton
‪makeEditButton(ButtonBar $buttonBar, ServerRequestInterface $request)
Definition: PageLayoutController.php:592
‪TYPO3\CMS\Backend\Template\Components\AbstractControl\setDataAttributes
‪$this setDataAttributes(array $dataAttributes)
Definition: AbstractControl.php:105
‪TYPO3\CMS\Backend\Template\Components\AbstractControl\setTitle
‪$this setTitle($title)
Definition: AbstractControl.php:92
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:18
‪TYPO3\CMS\Backend\Controller\PageLayoutController\makeLanguageSwitchButton
‪makeLanguageSwitchButton(ButtonBar $buttonbar)
Definition: PageLayoutController.php:624
‪TYPO3\CMS\Backend\Controller\PageLayoutController\addJavaScriptModuleInstructions
‪addJavaScriptModuleInstructions()
Definition: PageLayoutController.php:434
‪TYPO3\CMS\Backend\Controller\PageLayoutController\isContentEditable
‪isContentEditable(int $languageId)
Definition: PageLayoutController.php:792
‪TYPO3\CMS\Backend\Template\Components\Buttons\ButtonInterface
Definition: ButtonInterface.php:22
‪TYPO3\CMS\Backend\Controller\PageLayoutController\getBackendUser
‪getBackendUser()
Definition: PageLayoutController.php:851
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39