[CLEANUP] Use Permission constants consistently
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateModuleController.php
1 <?php
2 namespace TYPO3\CMS\Tstemplate\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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\BaseScriptClass;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
25 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
26 use TYPO3\CMS\Core\DataHandling\DataHandler;
27 use TYPO3\CMS\Core\Imaging\Icon;
28 use TYPO3\CMS\Core\Type\Bitmask\Permission;
29 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use TYPO3\CMS\Core\Utility\MathUtility;
32 use TYPO3\CMS\Fluid\View\StandaloneView;
33 use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
34
35 /**
36 * Module: TypoScript Tools
37 */
38 class TypoScriptTemplateModuleController extends BaseScriptClass
39 {
40 /**
41 * @var string
42 */
43 public $perms_clause;
44
45 /**
46 * @var string
47 */
48 public $sObj;
49
50 /**
51 * @var string
52 */
53 public $edit;
54
55 /**
56 * @var string
57 */
58 public $textExtensions = 'html,htm,txt,css,tmpl,inc,js';
59
60 /**
61 * @var string
62 */
63 public $modMenu_type = '';
64
65 /**
66 * @var string
67 */
68 public $modMenu_dontValidateList = '';
69
70 /**
71 * @var string
72 */
73 public $modMenu_setDefaultList = '';
74
75 /**
76 * @var array
77 */
78 public $pageinfo = [];
79
80 /**
81 * @var bool
82 */
83 public $access = false;
84
85 /**
86 * The name of the module
87 *
88 * @var string
89 */
90 protected $moduleName = 'web_ts';
91
92 /**
93 * ModuleTemplate Container
94 *
95 * @var ModuleTemplate
96 */
97 protected $moduleTemplate;
98
99 /**
100 * @var ExtendedTemplateService
101 */
102 protected $templateService;
103
104 /**
105 * Constructor
106 */
107 public function __construct()
108 {
109 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
110 $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
111
112 $this->MCONF = [
113 'name' => $this->moduleName
114 ];
115 $this->moduleTemplate->addJavaScriptCode(
116 'jumpToUrl',
117 '
118 function jumpToUrl(URL) {
119 window.location.href = URL;
120 return false;
121 }
122 '
123 );
124 }
125
126 /**
127 * Init
128 */
129 public function init()
130 {
131 parent::init();
132 $this->id = (int)GeneralUtility::_GP('id');
133 $this->sObj = GeneralUtility::_GP('sObj');
134 $this->edit = GeneralUtility::_GP('edit');
135 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
136 }
137
138 /**
139 * Clear cache
140 */
141 public function clearCache()
142 {
143 if (GeneralUtility::_GP('clear_all_cache')) {
144 /** @var DataHandler $tce */
145 $tce = GeneralUtility::makeInstance(DataHandler::class);
146 $tce->start([], []);
147 $tce->clear_cacheCmd('all');
148 }
149 }
150
151 /**
152 * Main
153 */
154 public function main()
155 {
156 // Access check...
157 // The page will show only if there is a valid page and if this page may be viewed by the user
158 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
159 $this->access = is_array($this->pageinfo);
160 $view = $this->getFluidTemplateObject('tstemplate');
161 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
162 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
163 if ($this->id && $this->access) {
164 $urlParameters = [
165 'id' => $this->id,
166 'template' => 'all'
167 ];
168 $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
169
170 // JavaScript
171 $this->moduleTemplate->addJavaScriptCode(
172 'TSTemplateInlineJS',
173 'function uFormUrl(aname) {
174 document.forms[0].action = ' . GeneralUtility::quoteJSvalue($aHref . '#') . '+aname;
175 }
176 function brPoint(lnumber,t) {
177 window.location.href = '
178 . GeneralUtility::quoteJSvalue(
179 $aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\'
180 . 'TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='
181 ) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
182 return false;
183 }
184 if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';'
185 );
186 $this->moduleTemplate->getPageRenderer()->addCssInlineBlock(
187 'TSTemplateInlineStyle',
188 'TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
189 TABLE#typo3-objectBrowser A { text-decoration: none; }
190 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
191 .ts-typoscript { width: 100%; }
192 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
193 .tst-analyzer-options { margin:5px 0; }'
194 );
195 // Setting up the context sensitive menu:
196 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
197 // Build the module content
198 $view->assign('actionName', $aHref);
199 $view->assign('typoscriptTemplateModuleContent', $this->getExtObjContent());
200 // Setting up the buttons and markers for docheader
201 $this->getButtons();
202 $this->generateMenu();
203 } else {
204 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
205 $queryBuilder->getRestrictions()
206 ->removeAll()
207 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
208 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
209
210 $result = $queryBuilder->select('pages.uid')
211 ->addSelectLiteral(
212 $queryBuilder->expr()->count('*', 'count'),
213 $queryBuilder->expr()->max('sys_template.root', 'root_max_val'),
214 $queryBuilder->expr()->min('sys_template.root', 'root_min_val')
215 )
216 ->from('pages')
217 ->from('sys_template')
218 ->where($queryBuilder->expr()->eq('pages.uid', $queryBuilder->quoteIdentifier('sys_template.pid')))
219 ->groupBy('pages.uid')
220 ->orderBy('pages.pid')
221 ->addOrderBy('pages.sorting')
222 ->execute();
223
224 $pArray = [];
225 while ($record = $result->fetch()) {
226 $this->setInPageArray($pArray, BackendUtility::BEgetRootLine($record['uid'], 'AND 1=1'), $record);
227 }
228
229 $view->getRenderingContext()->setControllerAction('PageZero');
230 $view->assign('templateList', $this->renderList($pArray));
231
232 // RENDER LIST of pages with templates, END
233 // Setting up the buttons and markers for docheader
234 $this->getButtons();
235 }
236 $this->content = $view->render();
237 }
238
239 /**
240 * Generates the menu based on $this->MOD_MENU
241 *
242 * @throws \InvalidArgumentException
243 */
244 protected function generateMenu()
245 {
246 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
247 $menu->setIdentifier('WebFuncJumpMenu');
248 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
249 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
250 foreach ($this->MOD_MENU['function'] as $controller => $title) {
251 $item = $menu
252 ->makeMenuItem()
253 ->setHref(
254 (string)$uriBuilder->buildUriFromRoute(
255 $this->moduleName,
256 [
257 'id' => $this->id,
258 'SET' => [
259 'function' => $controller
260 ]
261 ]
262 )
263 )
264 ->setTitle($title);
265 if ($controller === $this->MOD_SETTINGS['function']) {
266 $item->setActive(true);
267 }
268 $menu->addMenuItem($item);
269 }
270 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
271 }
272
273 /**
274 * Injects the request object for the current request or subrequest
275 * Then checks for module functions that have hooked in, and renders menu etc.
276 *
277 * @param ServerRequestInterface $request the current request
278 * @param ResponseInterface $response
279 * @return ResponseInterface the response with the content
280 */
281 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
282 {
283 $GLOBALS['SOBE'] = $this;
284 $this->init();
285
286 // Checking for first level external objects
287 $this->checkExtObj();
288
289 $this->clearCache();
290 $this->main();
291
292 $this->moduleTemplate->setContent($this->content);
293 $response->getBody()->write($this->moduleTemplate->renderContent());
294 return $response;
295 }
296
297 /**
298 * Create the panel of buttons for submitting the form or otherwise perform operations.
299 */
300 protected function getButtons()
301 {
302 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
303 $lang = $this->getLanguageService();
304
305 if ($this->id && $this->access) {
306 // View page
307 $viewButton = $buttonBar->makeLinkButton()
308 ->setHref('#')
309 ->setOnClick(BackendUtility::viewOnClick(
310 $this->pageinfo['uid'],
311 '',
312 BackendUtility::BEgetRootLine($this->pageinfo['uid'])
313 ))
314 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
315 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-page', Icon::SIZE_SMALL));
316 $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
317
318 if ($this->extClassConf['name'] === TypoScriptTemplateInformationModuleFunctionController::class) {
319 // NEW button
320 $urlParameters = [
321 'id' => $this->id,
322 'template' => 'all',
323 'createExtension' => 'new'
324 ];
325 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
326 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
327 $newButton = $buttonBar->makeLinkButton()
328 ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
329 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:db_new.php.pagetitle'))
330 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
331 'actions-add',
332 Icon::SIZE_SMALL
333 ));
334 $buttonBar->addButton($newButton);
335 } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class
336 && !empty($this->MOD_MENU['constant_editor_cat'])) {
337 // SAVE button
338 $saveButton = $buttonBar->makeInputButton()
339 ->setName('_savedok')
340 ->setValue('1')
341 ->setForm('TypoScriptTemplateModuleController')
342 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
343 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
344 'actions-document-save',
345 Icon::SIZE_SMALL
346 ))
347 ->setShowLabelText(true);
348 $buttonBar->addButton($saveButton);
349 } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
350 if (!empty($this->sObj)) {
351 // BACK
352 $urlParameters = [
353 'id' => $this->id
354 ];
355 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
356 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
357 $backButton = $buttonBar->makeLinkButton()
358 ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
359 ->setClasses('typo3-goBack')
360 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
361 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
362 'actions-view-go-back',
363 Icon::SIZE_SMALL
364 ));
365 $buttonBar->addButton($backButton);
366 }
367 }
368 }
369 // Shortcut
370 $shortcutButton = $buttonBar->makeShortcutButton()
371 ->setModuleName($this->MCONF['name'])
372 ->setGetVariables(['id', 'route']);
373 $buttonBar->addButton($shortcutButton);
374 }
375
376 // OTHER FUNCTIONS:
377 /**
378 * Wrap title for link in template
379 *
380 * @param string $title
381 * @param string $onlyKey
382 * @return string
383 */
384 public function linkWrapTemplateTitle($title, $onlyKey = '')
385 {
386 $urlParameters = [
387 'id' => $this->id
388 ];
389 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
390 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
391 $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
392 if ($onlyKey) {
393 $title = '<a href="' . htmlspecialchars(($aHref . '&e[' . $onlyKey . ']=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
394 } else {
395 $title = '<a href="' . htmlspecialchars(($aHref . '&e[constants]=1&e[config]=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
396 }
397 return $title;
398 }
399
400 /**
401 * No template
402 *
403 * @param int $newStandardTemplate
404 * @return string
405 */
406 public function noTemplate($newStandardTemplate = 0)
407 {
408 $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
409 $this->templateService->init();
410
411 $moduleContent['state'] = InfoboxViewHelper::STATE_INFO;
412
413 // New standard?
414 if ($newStandardTemplate) {
415 $selector = '';
416 $staticsText = '';
417 // Hook to change output, implemented for statictemplates
418 $hookObject = $this->getHookObjectForAction('newStandardTemplateView');
419 if (!empty($hookObject)) {
420 $reference = [
421 'selectorHtml' => &$selector,
422 'staticsText' => &$staticsText
423 ];
424 GeneralUtility::callUserFunction(
425 $hookObject,
426 $reference,
427 $this
428 );
429 $selector = $reference['selectorHtml'];
430 $staticsText = $reference['staticsText'];
431 }
432 // Extension?
433 $moduleContent['staticsText'] = $staticsText;
434 $moduleContent['selector'] = $selector;
435 }
436 // Go to previous Page with Template...
437 $previousPage = $this->templateService->ext_prevPageWithTemplate($this->id, $this->perms_clause);
438 if ($previousPage) {
439 $urlParameters = [
440 'id' => $previousPage['uid']
441 ];
442 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
443 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
444 $previousPage['aHref'] = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
445 $moduleContent['previousPage'] = $previousPage;
446 }
447 $view = $this->getFluidTemplateObject('tstemplate', 'NoTemplate');
448 $view->assign('content', $moduleContent);
449 return $view->render();
450 }
451
452 /**
453 * Render template menu
454 *
455 * @return string
456 */
457 public function templateMenu()
458 {
459 $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
460 $this->templateService->init();
461
462 $all = $this->templateService->ext_getAllTemplates($this->id);
463 if (count($all) > 1) {
464 $this->MOD_MENU['templatesOnPage'] = [];
465 foreach ($all as $d) {
466 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
467 }
468 }
469 $this->MOD_SETTINGS = BackendUtility::getModuleData(
470 $this->MOD_MENU,
471 GeneralUtility::_GP('SET'),
472 $this->MCONF['name'],
473 $this->modMenu_type,
474 $this->modMenu_dontValidateList,
475 $this->modMenu_setDefaultList
476 );
477 return BackendUtility::getFuncMenu(
478 $this->id,
479 'SET[templatesOnPage]',
480 $this->MOD_SETTINGS['templatesOnPage'],
481 $this->MOD_MENU['templatesOnPage']
482 );
483 }
484
485 /**
486 * Create template
487 *
488 * @param int $id
489 * @param int $actTemplateId
490 * @return string
491 */
492 public function createTemplate($id, $actTemplateId = 0)
493 {
494 $recData = [];
495 /** @var DataHandler $tce */
496 $tce = GeneralUtility::makeInstance(DataHandler::class);
497
498 if (GeneralUtility::_GP('createExtension')) {
499 $recData['sys_template']['NEW'] = [
500 'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
501 'title' => '+ext'
502 ];
503 $tce->start($recData, []);
504 $tce->process_datamap();
505 } elseif (GeneralUtility::_GP('newWebsite')) {
506 // Hook to handle row data, implemented for statictemplates
507 $hookObject = $this->getHookObjectForAction('newStandardTemplateHandler');
508 if (!empty($hookObject)) {
509 $reference = [
510 'recData' => &$recData,
511 'id' => $id,
512 ];
513 GeneralUtility::callUserFunction(
514 $hookObject,
515 $reference,
516 $this
517 );
518 $recData = $reference['recData'];
519 } else {
520 $recData['sys_template']['NEW'] = [
521 'pid' => $id,
522 'title' => $this->getLanguageService()->getLL('titleNewSite'),
523 'sorting' => 0,
524 'root' => 1,
525 'clear' => 3,
526 'config' => '
527 # Default PAGE object:
528 page = PAGE
529 page.10 = TEXT
530 page.10.value = HELLO WORLD!
531 '
532 ];
533 }
534 $tce->start($recData, []);
535 $tce->process_datamap();
536 $tce->clear_cacheCmd('all');
537 }
538 return $tce->substNEWwithIDs['NEW'];
539 }
540
541 // RENDER LIST of pages with templates, BEGIN
542 /**
543 * Set page in array
544 *
545 * @param array $pArray
546 * @param array $rlArr
547 * @param array $row
548 */
549 public function setInPageArray(&$pArray, $rlArr, $row)
550 {
551 ksort($rlArr);
552 reset($rlArr);
553 if (!$rlArr[0]['uid']) {
554 array_shift($rlArr);
555 }
556 $cEl = current($rlArr);
557 $pArray[$cEl['uid']] = $cEl['title'];
558 array_shift($rlArr);
559 if (!empty($rlArr)) {
560 $key = $cEl['uid'] . '.';
561 if (empty($pArray[$key])) {
562 $pArray[$key] = [];
563 }
564 $this->setInPageArray($pArray[$key], $rlArr, $row);
565 } else {
566 $key = $cEl['uid'] . '_';
567 $pArray[$key] = $row;
568 }
569 }
570
571 /**
572 * Get the list
573 *
574 * @param array $pArray
575 * @param array $lines
576 * @param int $c
577 * @return array
578 */
579 public function renderList($pArray, $lines = [], $c = 0)
580 {
581 if (!is_array($pArray)) {
582 return $lines;
583 }
584
585 $statusCheckedIcon = $this->moduleTemplate->getIconFactory()
586 ->getIcon('status-status-checked', Icon::SIZE_SMALL)->render();
587 $i = 0;
588 foreach ($pArray as $k => $v) {
589 if (MathUtility::canBeInterpretedAsInteger($k)) {
590 $line = [];
591 $key = $k . '_';
592 $line['marginLeft'] = $c * 20;
593 $line['class'] = ($i++ % 2 === 0 ? 'bgColor4' : 'bgColor6');
594 $line['pageTitle'] = GeneralUtility::fixed_lgd_cs($pArray[$k], 30);
595 $line['icon'] = $this->moduleTemplate->getIconFactory()
596 ->getIconForRecord(
597 'pages',
598 BackendUtility::getRecordWSOL('pages', $k),
599 Icon::SIZE_SMALL
600 )->render();
601 if (!empty($pArray[$key])) {
602 $line['href'] = GeneralUtility::linkThisScript(['id' => (int)$k]);
603 $line['title'] = 'ID: ' . (int)$k;
604 $line['count'] = $pArray[$k . '_']['count'];
605 $line['root_max_val'] = ($pArray[$key]['root_max_val'] > 0 ? $statusCheckedIcon : '&nbsp;');
606 $line['root_min_val'] = ($pArray[$key]['root_min_val'] === 0 ? $statusCheckedIcon : '&nbsp;');
607 } else {
608 $line['href'] = '';
609 $line['title'] = '';
610 $line['count'] = '';
611 $line['root_max_val'] = '';
612 $line['root_min_val'] = '';
613 }
614 $lines[] = $line;
615 $lines = $this->renderList($pArray[$k . '.'], $lines, $c + 1);
616 }
617 }
618 return $lines;
619 }
620
621 /**
622 * Returns a new standalone view, shorthand function
623 *
624 * @param string $extensionName
625 * @param string $templateName
626 * @return StandaloneView
627 */
628 protected function getFluidTemplateObject($extensionName, $templateName = 'Main')
629 {
630 /** @var StandaloneView $view */
631 $view = GeneralUtility::makeInstance(StandaloneView::class);
632 $view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName($extensionName);
633 $view->getRenderingContext()->setControllerAction($templateName);
634 $view->getRequest()->setControllerExtensionName('tstemplate');
635 return $view;
636 }
637
638 /**
639 * @param string $action
640 * @return string
641 */
642 protected function getHookObjectForAction($action)
643 {
644 if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action])) {
645 return $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action];
646 }
647 return null;
648 }
649 }