1a4c7742ad185c8ef2a4a0b7605bc738a366d1a1
[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 TYPO3\CMS\Backend\Module\BaseScriptClass;
18 use TYPO3\CMS\Backend\Template\DocumentTemplate;
19 use TYPO3\CMS\Core\DataHandling\DataHandler;
20 use TYPO3\CMS\Core\Messaging\FlashMessage;
21 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Backend\Utility\IconUtility;
25 use TYPO3\CMS\Core\Utility\MathUtility;
26 use TYPO3\CMS\Extbase\Object\ObjectManager;
27 use TYPO3\CMS\Fluid\View\StandaloneView;
28 use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
29
30 /**
31 * Module: TypoScript Tools
32 *
33 * $TYPO3_CONF_VARS["MODS"]["web_ts"]["onlineResourceDir"] = Directory of default resources. Eg. "fileadmin/res/" or so.
34 */
35 class TypoScriptTemplateModuleController extends BaseScriptClass {
36
37 /**
38 * @var string
39 */
40 public $perms_clause;
41
42 /**
43 * @var string
44 */
45 public $e;
46
47 /**
48 * @var string
49 */
50 public $sObj;
51
52 /**
53 * @var string
54 */
55 public $edit;
56
57 /**
58 * @var string
59 */
60 public $textExtensions = 'html,htm,txt,css,tmpl,inc,js';
61
62 /**
63 * @var string
64 */
65 public $modMenu_type = '';
66
67 /**
68 * @var string
69 */
70 public $modMenu_dontValidateList = '';
71
72 /**
73 * @var string
74 */
75 public $modMenu_setDefaultList = '';
76
77 /**
78 * @var array
79 */
80 public $pageinfo = array();
81
82 /**
83 * @var bool
84 */
85 public $access = FALSE;
86
87 /**
88 * The name of the module
89 *
90 * @var string
91 */
92 protected $moduleName = 'web_ts';
93
94 /**
95 * Constructor
96 */
97 public function __construct() {
98 $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
99
100 $this->MCONF = array(
101 'name' => $this->moduleName
102 );
103 }
104
105 /**
106 * Init
107 *
108 * @return void
109 */
110 public function init() {
111 parent::init();
112 $this->id = (int)GeneralUtility::_GP('id');
113 $this->e = GeneralUtility::_GP('e');
114 $this->sObj = GeneralUtility::_GP('sObj');
115 $this->edit = GeneralUtility::_GP('edit');
116 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
117 }
118
119 /**
120 * Clear cache
121 *
122 * @return void
123 */
124 public function clearCache() {
125 if (GeneralUtility::_GP('clear_all_cache')) {
126 /** @var DataHandler $tce */
127 $tce = GeneralUtility::makeInstance(DataHandler::class);
128 $tce->stripslashes_values = FALSE;
129 $tce->start(array(), array());
130 $tce->clear_cacheCmd('all');
131 }
132 }
133
134 /**
135 * Main
136 *
137 * @return void
138 */
139 public function main() {
140 // Template markers
141 $markers = array(
142 'CSH' => '',
143 'FUNC_MENU' => '',
144 'CONTENT' => ''
145 );
146
147 // Access check...
148 // The page will show only if there is a valid page and if this page may be viewed by the user
149 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
150 $this->access = is_array($this->pageinfo);
151
152 /** @var DocumentTemplate doc */
153 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
154 $this->doc->backPath = $GLOBALS['BACK_PATH'];
155 $this->doc->setModuleTemplate('EXT:tstemplate/Resources/Private/Templates/tstemplate.html');
156 $this->doc->addStyleSheet('module', 'sysext/tstemplate/Resources/Public/Css/styles.css');
157
158 $lang = $this->getLanguageService();
159
160 if ($this->id && $this->access) {
161 $urlParameters = array(
162 'id' => $this->id,
163 'template' => 'all'
164 );
165 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
166 $this->doc->form = '<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" name="editForm" class="form">';
167
168 // JavaScript
169 $this->doc->JScode = '
170 <script language="javascript" type="text/javascript">
171 function uFormUrl(aname) {
172 document.forms[0].action = ' . GeneralUtility::quoteJSvalue(($aHref . '#'), TRUE) . '+aname;
173 }
174 function brPoint(lnumber,t) {
175 window.location.href = ' . GeneralUtility::quoteJSvalue(($aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='), TRUE) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
176 return false;
177 }
178 </script>
179 ';
180 $this->doc->postCode = '
181 <script language="javascript" type="text/javascript">
182 if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
183 </script>
184 ';
185 $this->doc->inDocStylesArray[] = '
186 TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
187 TABLE#typo3-objectBrowser A { text-decoration: none; }
188 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
189 .ts-typoscript { width: 100%; }
190 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
191 .tst-analyzer-options { margin:5px 0; }
192 ';
193 // Setting up the context sensitive menu:
194 $this->doc->getContextMenuCode();
195 // Build the modulle content
196 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
197 $this->extObjContent();
198 // Setting up the buttons and markers for docheader
199 $docHeaderButtons = $this->getButtons();
200 $markers['FUNC_MENU'] = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
201 $markers['CONTENT'] = $this->content;
202 } else {
203 // Template pages:
204 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
205 'pages.uid, count(*) AS count, max(sys_template.root) AS root_max_val, min(sys_template.root) AS root_min_val',
206 'pages,sys_template',
207 'pages.uid=sys_template.pid'
208 . BackendUtility::deleteClause('pages')
209 . BackendUtility::versioningPlaceholderClause('pages')
210 . BackendUtility::deleteClause('sys_template')
211 . BackendUtility::versioningPlaceholderClause('sys_template'),
212 'pages.uid',
213 'pages.pid, pages.sorting'
214 );
215 $pArray = array();
216 foreach ($records as $record) {
217 $this->setInPageArray($pArray, BackendUtility::BEgetRootLine($record['uid'], 'AND 1=1'), $record);
218 }
219
220 $table = '<div class="table-fit"><table class="table table-striped table-hover" id="ts-overview">' .
221 '<thead>' .
222 '<tr>' .
223 '<th>' . $lang->getLL('pageName') . '</th>' .
224 '<th>' . $lang->getLL('templates') . '</th>' .
225 '<th>' . $lang->getLL('isRoot') . '</th>' .
226 '<th>' . $lang->getLL('isExt') . '</th>' .
227 '</tr>' .
228 '</thead>' .
229 '<tbody>' . implode('', $this->renderList($pArray)) . '</tbody>' .
230 '</table></div>';
231
232 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
233 $this->content .= $this->doc->section('', '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table);
234
235 // RENDER LIST of pages with templates, END
236 // Setting up the buttons and markers for docheader
237 $docHeaderButtons = $this->getButtons();
238 $markers['CONTENT'] = $this->content;
239 }
240
241 // Build the <body> for the module
242 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
243 // Renders the module page
244 $this->content = $this->doc->render('Template Tools', $this->content);
245 }
246
247 /**
248 * Print content
249 *
250 * @return void
251 */
252 public function printContent() {
253 echo $this->content;
254 }
255
256 /**
257 * Create the panel of buttons for submitting the form or otherwise perform operations.
258 *
259 * @return array All available buttons as an assoc. array
260 */
261 protected function getButtons() {
262 $buttons = array(
263 'back' => '',
264 'close' => '',
265 'new' => '',
266 'save' => '',
267 'save_close' => '',
268 'view' => '',
269 'shortcut' => ''
270 );
271
272 $lang = $this->getLanguageService();
273
274 if ($this->id && $this->access) {
275 // View page
276 $buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($this->pageinfo['uid'], $GLOBALS['BACK_PATH'], BackendUtility::BEgetRootLine($this->pageinfo['uid']))) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
277 if ($this->extClassConf['name'] == TypoScriptTemplateInformationModuleFunctionController::class) {
278 // NEW button
279 $urlParameters = array(
280 'id' => $this->id,
281 'template' => 'all',
282 'createExtension' => 'new'
283 );
284 $buttons['new'] = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_ts', $urlParameters)) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a>';
285 if (!empty($this->e) && !GeneralUtility::_POST('saveclose')) {
286 // no NEW-button while edit
287 $buttons['new'] = '';
288 // SAVE button
289 $buttons['save'] = '<button type="submit" class="c-inputButton" name="submit">'
290 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
291 . '</button>';
292 // SAVE AND CLOSE button
293 $buttons['save_close'] = '<button class="c-inputButton" name="saveclose">'
294 . IconUtility::getSpriteIcon('actions-document-save-close', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', TRUE)))
295 . '</button>';
296 // CLOSE button
297 $url = BackendUtility::getModuleUrl('web_ts', array('id' => $this->id));
298 $buttons['close'] = '<a href="' . htmlspecialchars($url) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-close') .'</a>';
299 }
300 } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class && !empty($this->MOD_MENU['constant_editor_cat'])) {
301 // SAVE button
302 $buttons['save'] = '<button class="c-inputButton" name="submit">'
303 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
304 . '</button>';
305 } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
306 if (!empty($this->sObj)) {
307 // BACK
308 $urlParameters = array(
309 'id' => $this->id
310 );
311 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
312 $buttons['back'] = '<a href="' . htmlspecialchars($aHref) . '" class="typo3-goBack" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', TRUE) . '">' . IconUtility::getSpriteIcon('actions-view-go-back') . '</a>';
313 }
314 }
315 // Shortcut
316 if ($this->getBackendUser()->mayMakeShortcut()) {
317 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id, edit_record, pointer, new_unique_uid, search_field, search_levels, showLimit', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
318 }
319 } else {
320 // Shortcut
321 if ($this->getBackendUser()->mayMakeShortcut()) {
322 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id', '', $this->MCONF['name']);
323 }
324 }
325 return $buttons;
326 }
327
328 // OTHER FUNCTIONS:
329 /**
330 * Wrap title for link in template
331 *
332 * @param string $title
333 * @param string $onlyKey
334 * @return string
335 */
336 public function linkWrapTemplateTitle($title, $onlyKey = '') {
337 $urlParameters = array(
338 'id' => $this->id
339 );
340 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
341 if ($onlyKey) {
342 $title = '<a href="' . htmlspecialchars(($aHref . '&e[' . $onlyKey . ']=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
343 } else {
344 $title = '<a href="' . htmlspecialchars(($aHref . '&e[constants]=1&e[config]=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
345 }
346 return $title;
347 }
348
349 /**
350 * No template
351 *
352 * @param int $newStandardTemplate
353 * @return string
354 */
355 public function noTemplate($newStandardTemplate = 0) {
356 // Defined global here!
357 /** @var ExtendedTemplateService $tmpl */
358 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
359 $GLOBALS['tmpl'] = $tmpl;
360
361 // Do not log time-performance information
362 $tmpl->tt_track = FALSE;
363 $tmpl->init();
364
365 $lang = $this->getLanguageService();
366
367 $title = $lang->getLL('noTemplate');
368 $message = '<p>' . $lang->getLL('noTemplateDescription') . '<br />' . $lang->getLL('createTemplateToEditConfiguration') . '</p>';
369
370 $view = GeneralUtility::makeInstance(StandaloneView::class);
371 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:tstemplate/Resources/Private/Templates/InfoBox.html'));
372 $view->assignMultiple(array(
373 'title' => $title,
374 'message' => $message,
375 'state' => InfoboxViewHelper::STATE_INFO
376 ));
377 $theOutput = $view->render();
378
379 // New standard?
380 if ($newStandardTemplate) {
381 // Hook to change output, implemented for statictemplates
382 if (isset(
383 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView']
384 )) {
385 $selector = '';
386 $staticsText = '';
387 $reference = array(
388 'selectorHtml' => &$selector,
389 'staticsText' => &$staticsText
390 );
391 GeneralUtility::callUserFunction(
392 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView'],
393 $reference,
394 $this
395 );
396 $selector = $reference['selectorHtml'];
397 $staticsText = $reference['staticsText'];
398 } else {
399 $selector = '<input type="hidden" name="createStandard" value="" />';
400 $staticsText = '';
401 }
402 // Extension?
403 $theOutput .= $this->doc->section(
404 $lang->getLL('newWebsite') . $staticsText,
405 '<p>' . $lang->getLL('newWebsiteDescription') . '</p>' . $selector . '<input class="btn btn-primary" type="submit" name="newWebsite" value="' . $lang->getLL('newWebsiteAction') . '" />',
406 0, 1);
407 }
408 // Extension?
409 $theOutput .= $this->doc->section(
410 $lang->getLL('extTemplate'),
411 '<p>' . $lang->getLL('extTemplateDescription') . '</p>' . '<input class="btn btn-default" type="submit" name="createExtension" value="' . $lang->getLL('extTemplateAction') . '" />',
412 0, 1);
413 // Go to first appearing...
414 $first = $tmpl->ext_prevPageWithTemplate($this->id, $this->perms_clause);
415 if ($first) {
416 $urlParameters = array(
417 'id' => $first['uid']
418 );
419 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
420 $theOutput .= $this->doc->section(
421 $lang->getLL('goToClosest'),
422 sprintf('<p>' . $lang->getLL('goToClosestDescription') . '</p>%s' . $lang->getLL('goToClosestAction') . '%s', htmlspecialchars($first['title']), $first['uid'], '<a class="btn btn-default" href="' . htmlspecialchars($aHref) . '">', '</a>'),
423 0, 1);
424 }
425 return $theOutput;
426 }
427
428 /**
429 * Render template menu
430 *
431 * @return string
432 */
433 public function templateMenu() {
434 /** @var ExtendedTemplateService $tmpl */
435 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
436 $GLOBALS['tmpl'] = $tmpl;
437
438 // Do not log time-performance information
439 $tmpl->tt_track = FALSE;
440 $tmpl->init();
441
442 $all = $tmpl->ext_getAllTemplates($this->id, $this->perms_clause);
443 if (count($all) > 1) {
444 $this->MOD_MENU['templatesOnPage'] = array();
445 foreach ($all as $d) {
446 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
447 }
448 }
449 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
450 return BackendUtility::getFuncMenu($this->id, 'SET[templatesOnPage]', $this->MOD_SETTINGS['templatesOnPage'], $this->MOD_MENU['templatesOnPage']);
451 }
452
453 /**
454 * Create template
455 *
456 * @param int $id
457 * @param int $actTemplateId
458 * @return string
459 */
460 public function createTemplate($id, $actTemplateId = 0) {
461 $recData = array();
462 /** @var DataHandler $tce */
463 $tce = GeneralUtility::makeInstance(DataHandler::class);
464 $tce->stripslashes_values = FALSE;
465
466 if (GeneralUtility::_GP('createExtension') || GeneralUtility::_GP('createExtension_x')) {
467 $recData['sys_template']['NEW'] = array(
468 'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
469 'title' => '+ext'
470 );
471 $tce->start($recData, array());
472 $tce->process_datamap();
473 } elseif (GeneralUtility::_GP('newWebsite')) {
474 // Hook to handle row data, implemented for statictemplates
475 if (isset(
476 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler']
477 )) {
478 $reference = array(
479 'recData' => &$recData,
480 'id' => $id,
481 );
482 GeneralUtility::callUserFunction(
483 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler'],
484 $reference,
485 $this
486 );
487 $recData = $reference['recData'];
488 } else {
489 $recData['sys_template']['NEW'] = array(
490 'pid' => $id,
491 'title' => $this->getLanguageService()->getLL('titleNewSite'),
492 'sorting' => 0,
493 'root' => 1,
494 'clear' => 3,
495 'config' => '
496 # Default PAGE object:
497 page = PAGE
498 page.10 = TEXT
499 page.10.value = HELLO WORLD!
500 '
501 );
502 }
503 $tce->start($recData, array());
504 $tce->process_datamap();
505 $tce->clear_cacheCmd('all');
506 }
507 return $tce->substNEWwithIDs['NEW'];
508 }
509
510 // RENDER LIST of pages with templates, BEGIN
511 /**
512 * Set page in array
513 *
514 * @param array $pArray
515 * @param array $rlArr
516 * @param array $row
517 * @return void
518 */
519 public function setInPageArray(&$pArray, $rlArr, $row) {
520 ksort($rlArr);
521 reset($rlArr);
522 if (!$rlArr[0]['uid']) {
523 array_shift($rlArr);
524 }
525 $cEl = current($rlArr);
526 $pArray[$cEl['uid']] = htmlspecialchars($cEl['title']);
527 array_shift($rlArr);
528 if (!empty($rlArr)) {
529 if (!isset($pArray[($cEl['uid'] . '.')])) {
530 $pArray[$cEl['uid'] . '.'] = array();
531 }
532 $this->setInPageArray($pArray[$cEl['uid'] . '.'], $rlArr, $row);
533 } else {
534 $pArray[$cEl['uid'] . '_'] = $row;
535 }
536 }
537
538 /**
539 * Render the list
540 *
541 * @param array $pArray
542 * @param array $lines
543 * @param int $c
544 * @return array
545 */
546 public function renderList($pArray, $lines = array(), $c = 0) {
547 static $i;
548
549 if (!is_array($pArray)) {
550 return $lines;
551 }
552
553 foreach ($pArray as $k => $v) {
554 if (MathUtility::canBeInterpretedAsInteger($k)) {
555 if (isset($pArray[$k . '_'])) {
556 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
557 <td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('id' => $k))) . '">' . IconUtility::getSpriteIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k), array('title' => ('ID: ' . $k))) . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</a></td>
558 <td>' . $pArray[($k . '_')]['count'] . '</td>
559 <td>' . ($pArray[$k . '_']['root_max_val'] > 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
560 <td>' . ($pArray[$k . '_']['root_min_val'] == 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
561 </tr>';
562 } else {
563 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
564 <td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . IconUtility::getSpriteIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k)) . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</td>
565 <td></td>
566 <td></td>
567 <td></td>
568 </tr>';
569 }
570 $lines = $this->renderList($pArray[$k . '.'], $lines, $c + 1);
571 }
572 }
573 return $lines;
574 }
575
576 }