[TASK] BACK_PATH DocumentTemplate
[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->setModuleTemplate('EXT:tstemplate/Resources/Private/Templates/tstemplate.html');
155 $this->doc->addStyleSheet('module', 'sysext/tstemplate/Resources/Public/Css/styles.css');
156
157 $lang = $this->getLanguageService();
158
159 if ($this->id && $this->access) {
160 $urlParameters = array(
161 'id' => $this->id,
162 'template' => 'all'
163 );
164 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
165 $this->doc->form = '<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" name="editForm" class="form">';
166
167 // JavaScript
168 $this->doc->JScode = '
169 <script language="javascript" type="text/javascript">
170 function uFormUrl(aname) {
171 document.forms[0].action = ' . GeneralUtility::quoteJSvalue(($aHref . '#'), TRUE) . '+aname;
172 }
173 function brPoint(lnumber,t) {
174 window.location.href = ' . GeneralUtility::quoteJSvalue(($aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='), TRUE) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
175 return false;
176 }
177 </script>
178 ';
179 $this->doc->postCode = '
180 <script language="javascript" type="text/javascript">
181 if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
182 </script>
183 ';
184 $this->doc->inDocStylesArray[] = '
185 TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
186 TABLE#typo3-objectBrowser A { text-decoration: none; }
187 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
188 .ts-typoscript { width: 100%; }
189 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
190 .tst-analyzer-options { margin:5px 0; }
191 ';
192 // Setting up the context sensitive menu:
193 $this->doc->getContextMenuCode();
194 // Build the modulle content
195 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
196 $this->extObjContent();
197 // Setting up the buttons and markers for docheader
198 $docHeaderButtons = $this->getButtons();
199 $markers['FUNC_MENU'] = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
200 $markers['CONTENT'] = $this->content;
201 } else {
202 // Template pages:
203 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
204 'pages.uid, count(*) AS count, max(sys_template.root) AS root_max_val, min(sys_template.root) AS root_min_val',
205 'pages,sys_template',
206 'pages.uid=sys_template.pid'
207 . BackendUtility::deleteClause('pages')
208 . BackendUtility::versioningPlaceholderClause('pages')
209 . BackendUtility::deleteClause('sys_template')
210 . BackendUtility::versioningPlaceholderClause('sys_template'),
211 'pages.uid',
212 'pages.pid, pages.sorting'
213 );
214 $pArray = array();
215 foreach ($records as $record) {
216 $this->setInPageArray($pArray, BackendUtility::BEgetRootLine($record['uid'], 'AND 1=1'), $record);
217 }
218
219 $table = '<div class="table-fit"><table class="table table-striped table-hover" id="ts-overview">' .
220 '<thead>' .
221 '<tr>' .
222 '<th>' . $lang->getLL('pageName') . '</th>' .
223 '<th>' . $lang->getLL('templates') . '</th>' .
224 '<th>' . $lang->getLL('isRoot') . '</th>' .
225 '<th>' . $lang->getLL('isExt') . '</th>' .
226 '</tr>' .
227 '</thead>' .
228 '<tbody>' . implode('', $this->renderList($pArray)) . '</tbody>' .
229 '</table></div>';
230
231 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
232 $this->content .= $this->doc->section('', '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table);
233
234 // RENDER LIST of pages with templates, END
235 // Setting up the buttons and markers for docheader
236 $docHeaderButtons = $this->getButtons();
237 $markers['CONTENT'] = $this->content;
238 }
239
240 // Build the <body> for the module
241 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
242 // Renders the module page
243 $this->content = $this->doc->render('Template Tools', $this->content);
244 }
245
246 /**
247 * Print content
248 *
249 * @return void
250 */
251 public function printContent() {
252 echo $this->content;
253 }
254
255 /**
256 * Create the panel of buttons for submitting the form or otherwise perform operations.
257 *
258 * @return array All available buttons as an assoc. array
259 */
260 protected function getButtons() {
261 $buttons = array(
262 'back' => '',
263 'close' => '',
264 'new' => '',
265 'save' => '',
266 'save_close' => '',
267 'view' => '',
268 'shortcut' => ''
269 );
270
271 $lang = $this->getLanguageService();
272
273 if ($this->id && $this->access) {
274 // View page
275 $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>';
276 if ($this->extClassConf['name'] == TypoScriptTemplateInformationModuleFunctionController::class) {
277 // NEW button
278 $urlParameters = array(
279 'id' => $this->id,
280 'template' => 'all',
281 'createExtension' => 'new'
282 );
283 $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>';
284 if (!empty($this->e) && !GeneralUtility::_POST('saveclose')) {
285 // no NEW-button while edit
286 $buttons['new'] = '';
287 // SAVE button
288 $buttons['save'] = '<button type="submit" class="c-inputButton" name="submit">'
289 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
290 . '</button>';
291 // SAVE AND CLOSE button
292 $buttons['save_close'] = '<button class="c-inputButton" name="saveclose">'
293 . IconUtility::getSpriteIcon('actions-document-save-close', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', TRUE)))
294 . '</button>';
295 // CLOSE button
296 $url = BackendUtility::getModuleUrl('web_ts', array('id' => $this->id));
297 $buttons['close'] = '<a href="' . htmlspecialchars($url) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-close') .'</a>';
298 }
299 } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class && !empty($this->MOD_MENU['constant_editor_cat'])) {
300 // SAVE button
301 $buttons['save'] = '<button class="c-inputButton" name="submit">'
302 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
303 . '</button>';
304 } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
305 if (!empty($this->sObj)) {
306 // BACK
307 $urlParameters = array(
308 'id' => $this->id
309 );
310 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
311 $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>';
312 }
313 }
314 // Shortcut
315 if ($this->getBackendUser()->mayMakeShortcut()) {
316 $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']);
317 }
318 } else {
319 // Shortcut
320 if ($this->getBackendUser()->mayMakeShortcut()) {
321 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id', '', $this->MCONF['name']);
322 }
323 }
324 return $buttons;
325 }
326
327 // OTHER FUNCTIONS:
328 /**
329 * Wrap title for link in template
330 *
331 * @param string $title
332 * @param string $onlyKey
333 * @return string
334 */
335 public function linkWrapTemplateTitle($title, $onlyKey = '') {
336 $urlParameters = array(
337 'id' => $this->id
338 );
339 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
340 if ($onlyKey) {
341 $title = '<a href="' . htmlspecialchars(($aHref . '&e[' . $onlyKey . ']=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
342 } else {
343 $title = '<a href="' . htmlspecialchars(($aHref . '&e[constants]=1&e[config]=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
344 }
345 return $title;
346 }
347
348 /**
349 * No template
350 *
351 * @param int $newStandardTemplate
352 * @return string
353 */
354 public function noTemplate($newStandardTemplate = 0) {
355 // Defined global here!
356 /** @var ExtendedTemplateService $tmpl */
357 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
358 $GLOBALS['tmpl'] = $tmpl;
359
360 // Do not log time-performance information
361 $tmpl->tt_track = FALSE;
362 $tmpl->init();
363
364 $lang = $this->getLanguageService();
365
366 $title = $lang->getLL('noTemplate');
367 $message = '<p>' . $lang->getLL('noTemplateDescription') . '<br />' . $lang->getLL('createTemplateToEditConfiguration') . '</p>';
368
369 $view = GeneralUtility::makeInstance(StandaloneView::class);
370 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:tstemplate/Resources/Private/Templates/InfoBox.html'));
371 $view->assignMultiple(array(
372 'title' => $title,
373 'message' => $message,
374 'state' => InfoboxViewHelper::STATE_INFO
375 ));
376 $theOutput = $view->render();
377
378 // New standard?
379 if ($newStandardTemplate) {
380 // Hook to change output, implemented for statictemplates
381 if (isset(
382 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView']
383 )) {
384 $selector = '';
385 $staticsText = '';
386 $reference = array(
387 'selectorHtml' => &$selector,
388 'staticsText' => &$staticsText
389 );
390 GeneralUtility::callUserFunction(
391 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView'],
392 $reference,
393 $this
394 );
395 $selector = $reference['selectorHtml'];
396 $staticsText = $reference['staticsText'];
397 } else {
398 $selector = '<input type="hidden" name="createStandard" value="" />';
399 $staticsText = '';
400 }
401 // Extension?
402 $theOutput .= $this->doc->section(
403 $lang->getLL('newWebsite') . $staticsText,
404 '<p>' . $lang->getLL('newWebsiteDescription') . '</p>' . $selector . '<input class="btn btn-primary" type="submit" name="newWebsite" value="' . $lang->getLL('newWebsiteAction') . '" />',
405 0, 1);
406 }
407 // Extension?
408 $theOutput .= $this->doc->section(
409 $lang->getLL('extTemplate'),
410 '<p>' . $lang->getLL('extTemplateDescription') . '</p>' . '<input class="btn btn-default" type="submit" name="createExtension" value="' . $lang->getLL('extTemplateAction') . '" />',
411 0, 1);
412 // Go to first appearing...
413 $first = $tmpl->ext_prevPageWithTemplate($this->id, $this->perms_clause);
414 if ($first) {
415 $urlParameters = array(
416 'id' => $first['uid']
417 );
418 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
419 $theOutput .= $this->doc->section(
420 $lang->getLL('goToClosest'),
421 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>'),
422 0, 1);
423 }
424 return $theOutput;
425 }
426
427 /**
428 * Render template menu
429 *
430 * @return string
431 */
432 public function templateMenu() {
433 /** @var ExtendedTemplateService $tmpl */
434 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
435 $GLOBALS['tmpl'] = $tmpl;
436
437 // Do not log time-performance information
438 $tmpl->tt_track = FALSE;
439 $tmpl->init();
440
441 $all = $tmpl->ext_getAllTemplates($this->id, $this->perms_clause);
442 if (count($all) > 1) {
443 $this->MOD_MENU['templatesOnPage'] = array();
444 foreach ($all as $d) {
445 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
446 }
447 }
448 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
449 return BackendUtility::getFuncMenu($this->id, 'SET[templatesOnPage]', $this->MOD_SETTINGS['templatesOnPage'], $this->MOD_MENU['templatesOnPage']);
450 }
451
452 /**
453 * Create template
454 *
455 * @param int $id
456 * @param int $actTemplateId
457 * @return string
458 */
459 public function createTemplate($id, $actTemplateId = 0) {
460 $recData = array();
461 /** @var DataHandler $tce */
462 $tce = GeneralUtility::makeInstance(DataHandler::class);
463 $tce->stripslashes_values = FALSE;
464
465 if (GeneralUtility::_GP('createExtension') || GeneralUtility::_GP('createExtension_x')) {
466 $recData['sys_template']['NEW'] = array(
467 'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
468 'title' => '+ext'
469 );
470 $tce->start($recData, array());
471 $tce->process_datamap();
472 } elseif (GeneralUtility::_GP('newWebsite')) {
473 // Hook to handle row data, implemented for statictemplates
474 if (isset(
475 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler']
476 )) {
477 $reference = array(
478 'recData' => &$recData,
479 'id' => $id,
480 );
481 GeneralUtility::callUserFunction(
482 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler'],
483 $reference,
484 $this
485 );
486 $recData = $reference['recData'];
487 } else {
488 $recData['sys_template']['NEW'] = array(
489 'pid' => $id,
490 'title' => $this->getLanguageService()->getLL('titleNewSite'),
491 'sorting' => 0,
492 'root' => 1,
493 'clear' => 3,
494 'config' => '
495 # Default PAGE object:
496 page = PAGE
497 page.10 = TEXT
498 page.10.value = HELLO WORLD!
499 '
500 );
501 }
502 $tce->start($recData, array());
503 $tce->process_datamap();
504 $tce->clear_cacheCmd('all');
505 }
506 return $tce->substNEWwithIDs['NEW'];
507 }
508
509 // RENDER LIST of pages with templates, BEGIN
510 /**
511 * Set page in array
512 *
513 * @param array $pArray
514 * @param array $rlArr
515 * @param array $row
516 * @return void
517 */
518 public function setInPageArray(&$pArray, $rlArr, $row) {
519 ksort($rlArr);
520 reset($rlArr);
521 if (!$rlArr[0]['uid']) {
522 array_shift($rlArr);
523 }
524 $cEl = current($rlArr);
525 $pArray[$cEl['uid']] = htmlspecialchars($cEl['title']);
526 array_shift($rlArr);
527 if (!empty($rlArr)) {
528 if (!isset($pArray[($cEl['uid'] . '.')])) {
529 $pArray[$cEl['uid'] . '.'] = array();
530 }
531 $this->setInPageArray($pArray[$cEl['uid'] . '.'], $rlArr, $row);
532 } else {
533 $pArray[$cEl['uid'] . '_'] = $row;
534 }
535 }
536
537 /**
538 * Render the list
539 *
540 * @param array $pArray
541 * @param array $lines
542 * @param int $c
543 * @return array
544 */
545 public function renderList($pArray, $lines = array(), $c = 0) {
546 static $i;
547
548 if (!is_array($pArray)) {
549 return $lines;
550 }
551
552 foreach ($pArray as $k => $v) {
553 if (MathUtility::canBeInterpretedAsInteger($k)) {
554 if (isset($pArray[$k . '_'])) {
555 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
556 <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>
557 <td>' . $pArray[($k . '_')]['count'] . '</td>
558 <td>' . ($pArray[$k . '_']['root_max_val'] > 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
559 <td>' . ($pArray[$k . '_']['root_min_val'] == 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
560 </tr>';
561 } else {
562 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
563 <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>
564 <td></td>
565 <td></td>
566 <td></td>
567 </tr>';
568 }
569 $lines = $this->renderList($pArray[$k . '.'], $lines, $c + 1);
570 }
571 }
572 return $lines;
573 }
574
575 }