‪TYPO3CMS  ‪main
ViewModuleController.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\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
28 use TYPO3\CMS\Backend\Utility\BackendUtility;
34 use TYPO3\CMS\Core\Imaging\IconSize;
47 
53 #[Controller]
55 {
56  public function ‪__construct(
57  protected readonly ‪ModuleTemplateFactory $moduleTemplateFactory,
58  protected readonly ‪IconFactory $iconFactory,
59  protected readonly ‪UriBuilder $uriBuilder,
60  protected readonly ‪PageRepository $pageRepository,
61  protected readonly ‪SiteFinder $siteFinder,
62  protected readonly ‪PolicyRegistry $policyRegistry,
63  ) {}
64 
68  public function ‪handleRequest(ServerRequestInterface $request): ResponseInterface
69  {
70  $languageService = $this->‪getLanguageService();
71  $pageId = (int)($request->getQueryParams()['id'] ?? 0);
72  $moduleData = $request->getAttribute('moduleData');
73  $pageInfo = BackendUtility::readPageAccess($pageId, $this->‪getBackendUser()->getPagePermsClause(‪Permission::PAGE_SHOW));
74 
75  $view = $this->moduleTemplateFactory->create($request);
76  $view->setBodyTag('<body class="typo3-module-viewpage">');
77  $view->setModuleId('typo3-module-viewpage');
78  $view->setTitle(
79  $languageService->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'),
80  $pageInfo['title'] ?? ''
81  );
82 
83  if (!$this->‪isValidDoktype($pageId)) {
84  $view->addFlashMessage(
85  $languageService->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:noValidPageSelected'),
86  '',
87  ContextualFeedbackSeverity::INFO
88  );
89  return $view->renderResponse('Empty');
90  }
91 
92  $previewLanguages = $this->‪getPreviewLanguages($pageId);
93  if ($previewLanguages !== [] && $moduleData->clean('language', array_keys($previewLanguages))) {
94  $this->‪getBackendUser()->pushModuleData($moduleData->getModuleIdentifier(), $moduleData->toArray());
95  }
96  $languageId = (int)$moduleData->get('language');
97  $targetUri = ‪PreviewUriBuilder::create($pageId)
98  ->withAdditionalQueryParameters($this->‪getTypeParameterIfSet($pageId))
99  ->withLanguage($languageId)
100  ->buildUri();
101  ‪$targetUrl = (string)$targetUri;
102  if ($targetUri === null || ‪$targetUrl === '') {
103  $view->addFlashMessage(
104  $languageService->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:noSiteConfiguration'),
105  '',
106  ContextualFeedbackSeverity::WARNING
107  );
108  return $view->renderResponse('Empty');
109  }
110 
111  $this->‪registerDocHeader($view, $pageId, $languageId, ‪$targetUrl);
112  $current = $moduleData->get('States')['current'] ?? [];
113  $current['label'] = ($current['label'] ?? $languageService->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:custom'));
114  $current['width'] = ‪MathUtility::forceIntegerInRange($current['width'] ?? 320, 300);
115  $current['height'] = ‪MathUtility::forceIntegerInRange($current['height'] ?? 480, 300);
116 
117  $custom = $moduleData->get('States')['custom'] ?? [];
118  $custom['width'] = ‪MathUtility::forceIntegerInRange($custom['width'] ?? 320, 300);
119  $custom['height'] = ‪MathUtility::forceIntegerInRange($custom['height'] ?? 480, 300);
120 
121  $view->assignMultiple([
122  'current' => $current,
123  'custom' => $custom,
124  'presetGroups' => $this->‪getPreviewPresets($pageId),
125  'url' => ‪$targetUrl,
126  ]);
127 
128  if ($targetUri->getScheme() !== '' && $targetUri->getHost() !== '') {
129  // temporarily(!) extend the CSP `frame-src` directive with the URL to be shown in the `<iframe>`
130  $mutation = new ‪Mutation(MutationMode::Extend, Directive::FrameSrc, ‪UriValue::fromUri($targetUri));
131  $this->policyRegistry->appendMutationCollection(new ‪MutationCollection($mutation));
132  }
133  return $view->renderResponse('Show');
134  }
135 
136  protected function ‪registerDocHeader(‪ModuleTemplate $view, int $pageId, int $languageId, string ‪$targetUrl)
137  {
138  $languageService = $this->‪getLanguageService();
139  ‪$languages = $this->‪getPreviewLanguages($pageId);
140  if (count(‪$languages) > 1) {
141  $languageMenu = $view->‪getDocHeaderComponent()->getMenuRegistry()->makeMenu();
142  $languageMenu->setIdentifier('_langSelector');
143  foreach (‪$languages as $value => $label) {
144  $href = (string)$this->uriBuilder->buildUriFromRoute(
145  'page_preview',
146  [
147  'id' => $pageId,
148  'language' => (int)$value,
149  ]
150  );
151  $menuItem = $languageMenu->makeMenuItem()
152  ->setTitle($label)
153  ->setHref($href);
154  if ($languageId === (int)$value) {
155  $menuItem->setActive(true);
156  }
157  $languageMenu->addMenuItem($menuItem);
158  }
159  $view->‪getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
160  }
161 
162  $buttonBar = $view->‪getDocHeaderComponent()->getButtonBar();
163  $showButton = $buttonBar->makeLinkButton()
164  ->setHref(‪$targetUrl)
165  ->setDataAttributes([
166  'dispatch-action' => 'TYPO3.WindowManager.localOpen',
167  'dispatch-args' => GeneralUtility::jsonEncodeForHtmlAttribute([
169  true, // switchFocus
170  'newTYPO3frontendWindow', // windowName,
171  ]),
172  ])
173  ->setTitle($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
174  ->setShowLabelText(true)
175  ->setIcon($this->iconFactory->getIcon('actions-view-page', IconSize::SMALL));
176  $buttonBar->addButton($showButton);
177 
178  $refreshButton = $buttonBar->makeLinkButton()
179  ->setHref('#')
180  ->setClasses('t3js-viewpage-refresh')
181  ->setTitle($languageService->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:refreshPage'))
182  ->setIcon($this->iconFactory->getIcon('actions-refresh', IconSize::SMALL));
183  $buttonBar->addButton($refreshButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
184 
185  // Shortcut
186  $shortcutButton = $buttonBar->makeShortcutButton()
187  ->setRouteIdentifier('page_preview')
188  ->setDisplayName($this->‪getShortcutTitle($pageId))
189  ->setArguments(['id' => $pageId]);
190  $buttonBar->addButton($shortcutButton, ‪ButtonBar::BUTTON_POSITION_RIGHT);
191  }
192 
197  protected function ‪getTypeParameterIfSet(int $pageId): string
198  {
199  $typeParameter = '';
200  $typeId = (int)(BackendUtility::getPagesTSconfig($pageId)['mod.']['web_view.']['type'] ?? 0);
201  if ($typeId > 0) {
202  $typeParameter = '&type=' . $typeId;
203  }
204  return $typeParameter;
205  }
206 
210  protected function ‪getPreviewPresets(int $pageId): array
211  {
212  $presetGroups = [
213  'desktop' => [],
214  'tablet' => [],
215  'mobile' => [],
216  'unidentified' => [],
217  ];
218  $previewFrameWidthConfig = BackendUtility::getPagesTSconfig($pageId)['mod.']['web_view.']['previewFrameWidths.'] ?? [];
219  foreach ($previewFrameWidthConfig as $item => $conf) {
220  $data = [
221  'key' => substr($item, 0, -1),
222  'label' => $conf['label'] ?? null,
223  'type' => $conf['type'] ?? 'unknown',
224  'width' => (isset($conf['width']) && (int)$conf['width'] > 0 && !str_contains($conf['width'], '%')) ? (int)$conf['width'] : null,
225  'height' => (isset($conf['height']) && (int)$conf['height'] > 0 && !str_contains($conf['height'], '%')) ? (int)$conf['height'] : null,
226  ];
227  $width = (int)substr($item, 0, -1);
228  if (!isset($data['width']) && $width > 0) {
229  $data['width'] = $width;
230  }
231  if (!isset($data['label'])) {
232  $data['label'] = $data['key'];
233  } else {
234  $data['label'] = $this->‪getLanguageService()->sL(trim($data['label']));
235  }
236 
237  if (array_key_exists($data['type'], $presetGroups)) {
238  $presetGroups[$data['type']][$data['key']] = $data;
239  } else {
240  $presetGroups['unidentified'][$data['key']] = $data;
241  }
242  }
243 
244  return $presetGroups;
245  }
246 
250  protected function ‪getPreviewLanguages(int $pageId): array
251  {
252  ‪$languages = [];
253  $modSharedTSconfig = BackendUtility::getPagesTSconfig($pageId)['mod.']['SHARED.'] ?? [];
254  if (($modSharedTSconfig['view.']['disableLanguageSelector'] ?? false) === '1') {
255  return ‪$languages;
256  }
257 
258  try {
259  $site = $this->siteFinder->getSiteByPageId($pageId);
260  $siteLanguages = $site->getAvailableLanguages($this->‪getBackendUser(), false, $pageId);
261 
262  foreach ($siteLanguages as $siteLanguage) {
263  $languageAspectToTest = ‪LanguageAspectFactory::createFromSiteLanguage($siteLanguage);
264  $page = $this->pageRepository->getPageOverlay($this->pageRepository->getPage($pageId), $siteLanguage->getLanguageId());
265 
266  if ($this->pageRepository->isPageSuitableForLanguage($page, $languageAspectToTest)) {
267  ‪$languages[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle();
268  }
269  }
270  } catch (‪SiteNotFoundException $e) {
271  // do nothing
272  }
273  return ‪$languages;
274  }
275 
279  protected function ‪isValidDoktype(int $pageId = 0): bool
280  {
281  if ($pageId === 0) {
282  return false;
283  }
284  $page = BackendUtility::getRecord('pages', $pageId);
285  $pageType = (int)($page['doktype'] ?? 0);
286  return $pageType !== 0
287  && !in_array($pageType, [
290  ], true);
291  }
292 
296  protected function ‪getShortcutTitle(int $pageId): string
297  {
298  $pageTitle = '';
299  $pageRow = BackendUtility::getRecord('pages', $pageId) ?? [];
300  if ($pageRow !== []) {
301  $pageTitle = BackendUtility::getRecordTitle('pages', $pageRow);
302  }
303  return sprintf(
304  '%s: %s [%d]',
305  $this->‪getLanguageService()->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tablabel'),
306  $pageTitle,
307  $pageId
308  );
309  }
310 
312  {
313  return ‪$GLOBALS['BE_USER'];
314  }
315 
317  {
318  return ‪$GLOBALS['LANG'];
319  }
320 }
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive
‪Directive
Definition: Directive.php:25
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyRegistry
Definition: PolicyRegistry.php:28
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:33
‪TYPO3\CMS\Core\Context\LanguageAspectFactory
Definition: LanguageAspectFactory.php:27
‪TYPO3\CMS\Viewpage\Controller
Definition: ViewModuleController.php:18
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:33
‪$languages
‪$languages
Definition: updateIsoDatabase.php:104
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\registerDocHeader
‪registerDocHeader(ModuleTemplate $view, int $pageId, int $languageId, string $targetUrl)
Definition: ViewModuleController.php:136
‪TYPO3\CMS\Core\Context\LanguageAspectFactory\createFromSiteLanguage
‪static createFromSiteLanguage(SiteLanguage $language)
Definition: LanguageAspectFactory.php:31
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:25
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Backend\Attribute\Controller
Definition: Controller.php:25
‪TYPO3\CMS\Redirects\Message\$targetUrl
‪identifier readonly UriInterface $targetUrl
Definition: RedirectWasHitMessage.php:33
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\handleRequest
‪handleRequest(ServerRequestInterface $request)
Definition: ViewModuleController.php:68
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getPreviewPresets
‪getPreviewPresets(int $pageId)
Definition: ViewModuleController.php:210
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:46
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\isValidDoktype
‪isValidDoktype(int $pageId=0)
Definition: ViewModuleController.php:279
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationMode
‪MutationMode
Definition: MutationMode.php:24
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getShortcutTitle
‪getShortcutTitle(int $pageId)
Definition: ViewModuleController.php:296
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder\create
‪static static create(int $pageId)
Definition: PreviewUriBuilder.php:65
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:113
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:64
‪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:114
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getLanguageService
‪getLanguageService()
Definition: ViewModuleController.php:316
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getPreviewLanguages
‪getPreviewLanguages(int $pageId)
Definition: ViewModuleController.php:250
‪TYPO3\CMS\Backend\Template\ModuleTemplate\getDocHeaderComponent
‪getDocHeaderComponent()
Definition: ModuleTemplate.php:181
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getBackendUser
‪getBackendUser()
Definition: ViewModuleController.php:311
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder
Definition: PreviewUriBuilder.php:44
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue
Definition: UriValue.php:29
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:61
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Mutation
Definition: Mutation.php:26
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationCollection
Definition: MutationCollection.php:24
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:42
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController
Definition: ViewModuleController.php:55
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\getTypeParameterIfSet
‪getTypeParameterIfSet(int $pageId)
Definition: ViewModuleController.php:197
‪TYPO3\CMS\Viewpage\Controller\ViewModuleController\__construct
‪__construct(protected readonly ModuleTemplateFactory $moduleTemplateFactory, protected readonly IconFactory $iconFactory, protected readonly UriBuilder $uriBuilder, protected readonly PageRepository $pageRepository, protected readonly SiteFinder $siteFinder, protected readonly PolicyRegistry $policyRegistry,)
Definition: ViewModuleController.php:56
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue\fromUri
‪static fromUri(UriInterface $other)
Definition: UriValue.php:34