[CLEANUP] Use Permission constants consistently
[Packages/TYPO3.CMS.git] / typo3 / sysext / viewpage / Classes / Controller / ViewModuleController.php
1 <?php
2 namespace TYPO3\CMS\Viewpage\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Backend\View\BackendTemplateView;
20 use TYPO3\CMS\Core\Database\ConnectionPool;
21 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
22 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Page\PageRenderer;
26 use TYPO3\CMS\Core\Type\Bitmask\Permission;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
29 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
30
31 /**
32 * Controller for viewing the frontend
33 */
34 class ViewModuleController extends ActionController
35 {
36 /**
37 * @var string
38 */
39 protected $defaultViewObjectName = BackendTemplateView::class;
40
41 /**
42 * @var BackendTemplateView
43 */
44 protected $view;
45
46 /**
47 * Set up the doc header properly here
48 *
49 * @param ViewInterface $view
50 */
51 protected function initializeView(ViewInterface $view)
52 {
53 /** @var BackendTemplateView $view */
54 parent::initializeView($view);
55 $this->registerDocHeader();
56 }
57
58 /**
59 * Registers the docheader
60 */
61 protected function registerDocHeader()
62 {
63 $languages = $this->getPreviewLanguages();
64 if (count($languages) > 1) {
65 $languageMenu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
66 $languageMenu->setIdentifier('_langSelector');
67 $languageUid = $this->getCurrentLanguage();
68 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
69 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
70 foreach ($languages as $value => $label) {
71 $href = (string)$uriBuilder->buildUriFromRoute(
72 'web_ViewpageView',
73 [
74 'id' => (int)GeneralUtility::_GP('id'),
75 'language' => (int)$value
76 ]
77 );
78 $menuItem = $languageMenu->makeMenuItem()
79 ->setTitle($label)
80 ->setHref($href);
81 if ($languageUid === (int)$value) {
82 $menuItem->setActive(true);
83 }
84 $languageMenu->addMenuItem($menuItem);
85 }
86 $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu);
87 }
88
89 $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
90 $showButton = $buttonBar->makeLinkButton()
91 ->setHref($this->getTargetUrl())
92 ->setOnClick('window.open(this.href, \'newTYPO3frontendWindow\').focus();return false;')
93 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
94 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-page', Icon::SIZE_SMALL));
95 $buttonBar->addButton($showButton);
96
97 $refreshButton = $buttonBar->makeLinkButton()
98 ->setHref('javascript:document.getElementById(\'tx_viewpage_iframe\').contentWindow.location.reload(true);')
99 ->setTitle($this->getLanguageService()->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:refreshPage'))
100 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-refresh', Icon::SIZE_SMALL));
101 $buttonBar->addButton($refreshButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
102
103 $currentRequest = $this->request;
104 $moduleName = $currentRequest->getPluginName();
105 $getVars = $this->request->getArguments();
106 $extensionName = $currentRequest->getControllerExtensionName();
107 if (count($getVars) === 0) {
108 $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName);
109 $getVars = ['id', 'route', $modulePrefix];
110 }
111 $shortcutButton = $buttonBar->makeShortcutButton()
112 ->setModuleName($moduleName)
113 ->setGetVariables($getVars);
114 $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT, 2);
115 }
116
117 /**
118 * Gets called before each action
119 */
120 public function initializeAction()
121 {
122 $this->getLanguageService()->includeLLFile('EXT:viewpage/Resources/Private/Language/locallang.xlf');
123 $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
124 $pageRenderer->addInlineLanguageLabelFile('EXT:viewpage/Resources/Private/Language/locallang.xlf');
125 }
126
127 /**
128 * Show selected page from pagetree in iframe
129 */
130 public function showAction()
131 {
132 $this->view->getModuleTemplate()->setBodyTag('<body class="typo3-module-viewpage">');
133 $this->view->getModuleTemplate()->setModuleName('typo3-module-viewpage');
134 $this->view->getModuleTemplate()->setModuleId('typo3-module-viewpage');
135
136 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
137 $icons = [];
138 $icons['orientation'] = $iconFactory->getIcon('actions-device-orientation-change', Icon::SIZE_SMALL)->render('inline');
139 $icons['fullscreen'] = $iconFactory->getIcon('actions-fullscreen', Icon::SIZE_SMALL)->render('inline');
140 $icons['expand'] = $iconFactory->getIcon('actions-expand', Icon::SIZE_SMALL)->render('inline');
141 $icons['desktop'] = $iconFactory->getIcon('actions-device-desktop', Icon::SIZE_SMALL)->render('inline');
142 $icons['tablet'] = $iconFactory->getIcon('actions-device-tablet', Icon::SIZE_SMALL)->render('inline');
143 $icons['mobile'] = $iconFactory->getIcon('actions-device-mobile', Icon::SIZE_SMALL)->render('inline');
144 $icons['unidentified'] = $iconFactory->getIcon('actions-device-unidentified', Icon::SIZE_SMALL)->render('inline');
145
146 $current = ($this->getBackendUser()->uc['moduleData']['web_view']['States']['current'] ?: []);
147 $current['label'] = (isset($current['label']) ? $current['label'] : $this->getLanguageService()->sL('LLL:EXT:viewpage/Resources/Private/Language/locallang.xlf:custom'));
148 $current['width'] = (isset($current['width']) && (int) $current['width'] >= 300 ? (int) $current['width'] : 320);
149 $current['height'] = (isset($current['height']) && (int) $current['height'] >= 300 ? (int) $current['height'] : 480);
150
151 $custom = ($this->getBackendUser()->uc['moduleData']['web_view']['States']['custom'] ?: []);
152 $custom['width'] = (isset($current['custom']) && (int) $current['custom'] >= 300 ? (int) $current['custom'] : 320);
153 $custom['height'] = (isset($current['custom']) && (int) $current['custom'] >= 300 ? (int) $current['custom'] : 480);
154
155 $this->view->assign('icons', $icons);
156 $this->view->assign('current', $current);
157 $this->view->assign('custom', $custom);
158 $this->view->assign('presetGroups', $this->getPreviewPresets());
159 $this->view->assign('url', $this->getTargetUrl());
160 }
161
162 /**
163 * Determine the url to view
164 *
165 * @return string
166 */
167 protected function getTargetUrl()
168 {
169 $pageIdToShow = (int)GeneralUtility::_GP('id');
170
171 $permissionClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
172 $pageRecord = BackendUtility::readPageAccess($pageIdToShow, $permissionClause);
173 if ($pageRecord) {
174 $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
175
176 $adminCommand = $this->getAdminCommand($pageIdToShow);
177 $domainName = $this->getDomainName($pageIdToShow);
178 $languageParameter = $this->getLanguageParameter();
179 // Mount point overlay: Set new target page id and mp parameter
180 /** @var \TYPO3\CMS\Frontend\Page\PageRepository $sysPage */
181 $sysPage = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
182 $sysPage->init(false);
183 $mountPointMpParameter = '';
184 $finalPageIdToShow = $pageIdToShow;
185 $mountPointInformation = $sysPage->getMountPointInfo($pageIdToShow);
186 if ($mountPointInformation && $mountPointInformation['overlay']) {
187 // New page id
188 $finalPageIdToShow = $mountPointInformation['mount_pid'];
189 $mountPointMpParameter = '&MP=' . $mountPointInformation['MPvar'];
190 }
191 // Modify relative path to protocol with host if domain record is given
192 $protocolAndHost = '..';
193 if ($domainName) {
194 // TCEMAIN.previewDomain can contain the protocol, check prevents double protocol URLs
195 if (strpos($domainName, '://') !== false) {
196 $protocolAndHost = $domainName;
197 } else {
198 $protocol = GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https' : 'http';
199 $protocolAndHost = $protocol . '://' . $domainName;
200 }
201 }
202 return $protocolAndHost . '/index.php?id=' . $finalPageIdToShow . $this->getTypeParameterIfSet($finalPageIdToShow) . $mountPointMpParameter . $adminCommand . $languageParameter;
203 }
204 return '#';
205 }
206
207 /**
208 * Get admin command
209 *
210 * @param int $pageId
211 * @return string
212 */
213 protected function getAdminCommand($pageId)
214 {
215 // The page will show only if there is a valid page and if this page may be viewed by the user
216 $pageinfo = BackendUtility::readPageAccess($pageId, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
217 $addCommand = '';
218 if (is_array($pageinfo)) {
219 $addCommand = '&ADMCMD_editIcons=1' . BackendUtility::ADMCMD_previewCmds($pageinfo);
220 }
221 return $addCommand;
222 }
223
224 /**
225 * With page TS config it is possible to force a specific type id via mod.web_view.type
226 * for a page id or a page tree.
227 * The method checks if a type is set for the given id and returns the additional GET string.
228 *
229 * @param int $pageId
230 * @return string
231 */
232 protected function getTypeParameterIfSet($pageId)
233 {
234 $typeParameter = '';
235 $modTSconfig = BackendUtility::getModTSconfig($pageId, 'mod.web_view');
236 $typeId = (int)$modTSconfig['properties']['type'];
237 if ($typeId > 0) {
238 $typeParameter = '&type=' . $typeId;
239 }
240 return $typeParameter;
241 }
242
243 /**
244 * Get domain name for requested page id
245 *
246 * @param int $pageId
247 * @return string|null Domain name from first sys_domains-Record or from TCEMAIN.previewDomain, NULL if neither is configured
248 */
249 protected function getDomainName($pageId)
250 {
251 $previewDomainConfig = $this->getBackendUser()->getTSConfig('TCEMAIN.previewDomain', BackendUtility::getPagesTSconfig($pageId));
252 if ($previewDomainConfig['value']) {
253 $domain = $previewDomainConfig['value'];
254 } else {
255 $domain = BackendUtility::firstDomainRecord(BackendUtility::BEgetRootLine($pageId));
256 }
257 return $domain;
258 }
259
260 /**
261 * Get available presets for preview frame
262 *
263 * @return array
264 */
265 protected function getPreviewPresets()
266 {
267 $pageId = (int)GeneralUtility::_GP('id');
268 $modTSconfig = BackendUtility::getModTSconfig($pageId, 'mod.web_view');
269 $presetGroups = [
270 'desktop' => [],
271 'tablet' => [],
272 'mobile' => [],
273 'unidentified' => []
274 ];
275 if (is_array($modTSconfig['properties']['previewFrameWidths.'])) {
276 foreach ($modTSconfig['properties']['previewFrameWidths.'] as $item => $conf) {
277 $data = [
278 'key' => substr($item, 0, -1),
279 'label' => (isset($conf['label']) ? $conf['label'] : null),
280 'type' => (isset($conf['type']) ? $conf['type'] : 'unknown'),
281 'width' => ((isset($conf['width']) && (int) $conf['width'] > 0 && strpos($conf['width'], '%') === false) ? (int) $conf['width'] : null),
282 'height' => ((isset($conf['height']) && (int) $conf['height'] > 0 && strpos($conf['height'], '%') === false) ? (int) $conf['height'] : null),
283 ];
284 $width = (int) substr($item, 0, -1);
285 if (!isset($data['width']) && $width > 0) {
286 $data['width'] = $width;
287 }
288 if (!isset($data['label'])) {
289 $data['label'] = $data['key'];
290 } elseif (strpos($data['label'], 'LLL:') === 0) {
291 $data['label'] = $this->getLanguageService()->sL(trim($data['label']));
292 }
293
294 if (array_key_exists($data['type'], $presetGroups)) {
295 $presetGroups[$data['type']][$data['key']] = $data;
296 } else {
297 $presetGroups['unidentified'][$data['key']] = $data;
298 }
299 }
300 }
301
302 return $presetGroups;
303 }
304
305 /**
306 * Returns the preview languages
307 *
308 * @return array
309 */
310 protected function getPreviewLanguages()
311 {
312 $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'];
313 $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'];
314 $pageIdToShow = (int)GeneralUtility::_GP('id');
315 $modSharedTSconfig = BackendUtility::getModTSconfig($pageIdToShow, 'mod.SHARED');
316 if ($modSharedTSconfig['properties']['view.']['disableLanguageSelector'] === '1') {
317 return [];
318 }
319 $languages = [
320 0 => isset($modSharedTSconfig['properties']['defaultLanguageLabel'])
321 ? $modSharedTSconfig['properties']['defaultLanguageLabel'] . ' (' . $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_list.xlf:defaultLanguage') . ')'
322 : $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_list.xlf:defaultLanguage')
323 ];
324 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
325 $queryBuilder->getRestrictions()
326 ->removeAll()
327 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
328
329 if (!$this->getBackendUser()->isAdmin()) {
330 $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(HiddenRestriction::class));
331 }
332
333 $result = $queryBuilder->select('sys_language.uid', 'sys_language.title')
334 ->from('sys_language')
335 ->join(
336 'sys_language',
337 'pages',
338 'o',
339 $queryBuilder->expr()->eq('o.' . $languageField, $queryBuilder->quoteIdentifier('sys_language.uid'))
340 )
341 ->where(
342 $queryBuilder->expr()->eq(
343 'o.' . $localizationParentField,
344 $queryBuilder->createNamedParameter($pageIdToShow, \PDO::PARAM_INT)
345 )
346 )
347 ->groupBy('sys_language.uid', 'sys_language.title', 'sys_language.sorting')
348 ->orderBy('sys_language.sorting')
349 ->execute();
350
351 while ($row = $result->fetch()) {
352 if ($this->getBackendUser()->checkLanguageAccess($row['uid'])) {
353 $languages[$row['uid']] = $row['title'];
354 }
355 }
356 return $languages;
357 }
358
359 /**
360 * Returns the current language
361 *
362 * @return string
363 */
364 protected function getCurrentLanguage()
365 {
366 $languageUid = GeneralUtility::_GP('language');
367 if ($languageUid === null) {
368 $states = $this->getBackendUser()->uc['moduleData']['web_view']['States'];
369 $languages = $this->getPreviewLanguages();
370 if (isset($states['languageSelectorValue']) && isset($languages[$states['languageSelectorValue']])) {
371 $languageUid = $states['languageSelectorValue'];
372 }
373 } else {
374 $this->getBackendUser()->uc['moduleData']['web_view']['States']['languageSelectorValue'] = (int)$languageUid;
375 $this->getBackendUser()->writeUC($this->getBackendUser()->uc);
376 }
377 return (int)$languageUid;
378 }
379
380 /**
381 * Gets the L parameter from the user session
382 *
383 * @return string
384 */
385 protected function getLanguageParameter()
386 {
387 $languageParameter = '';
388 $languageUid = $this->getCurrentLanguage();
389 if ($languageUid) {
390 $languageParameter = '&L=' . $languageUid;
391 }
392 return $languageParameter;
393 }
394
395 /**
396 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
397 */
398 protected function getBackendUser()
399 {
400 return $GLOBALS['BE_USER'];
401 }
402
403 /**
404 * @return \TYPO3\CMS\Core\Localization\LanguageService
405 */
406 protected function getLanguageService()
407 {
408 return $GLOBALS['LANG'];
409 }
410 }