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