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