53df4a064dbb8d4de162924a2e7dfc495c59da27
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateInformationModuleFunctionController.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\Core\DataHandling\DataHandler;
18 use TYPO3\CMS\Core\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
21 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Core\Utility\HttpUtility;
24 use TYPO3\CMS\Backend\Module\AbstractFunctionModule;
25 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 use TYPO3\CMS\Lang\LanguageService;
27
28 /**
29 * This class displays the Info/Modify screen of the Web > Template module
30 */
31 class TypoScriptTemplateInformationModuleFunctionController extends AbstractFunctionModule
32 {
33 /**
34 * Indicator for t3editor, whether data is stored
35 *
36 * @var bool
37 */
38 public $tce_processed = false;
39
40 /**
41 * @var TypoScriptTemplateModuleController
42 */
43 public $pObj;
44
45 /**
46 * @var IconFactory
47 */
48 protected $iconFactory;
49
50 /**
51 * Constructor
52 */
53 public function __construct()
54 {
55 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
56 }
57
58 /**
59 * Creates a row for a HTML table
60 *
61 * @param string $label The label to be shown (e.g. 'Title:', 'Sitetitle:')
62 * @param string $data The data/information to be shown (e.g. 'Template for my site')
63 * @param string $field The field/variable to be sent on clicking the edit icon (e.g. 'title', 'sitetitle')
64 * @param int $id The field/variable to be sent on clicking the edit icon (e.g. 'title', 'sitetitle')
65 * @return string A row for a HTML table
66 */
67 public function tableRow($label, $data, $field, $id)
68 {
69 $lang = $this->getLanguageService();
70 if ($field === 'config' || $field === 'constants') {
71 $urlParameters = [
72 'id' => $this->pObj->id,
73 'e' => [
74 $field => 1
75 ]
76 ];
77 $url = BackendUtility::getModuleUrl('web_ts', $urlParameters);
78 } else {
79 $urlParameters = [
80 'edit' => [
81 'sys_template' => [
82 $id => 'edit'
83 ]
84 ],
85 'columnsOnly' => $field,
86 'createExtension' => 0,
87 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
88 ];
89 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
90 }
91 $title = $lang->sL('LLL:EXT:lang/locallang_common.xlf:editField', true);
92 $startAnchor = '<a href="' . htmlspecialchars($url) . '" title="' . $title . '">';
93 $icon = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
94 $ret = '<tr><td>';
95 $ret .= $startAnchor . '<strong>' . $label . '</strong></a>';
96 $ret .= '</td><td width="80%">' . $data . '</td><td>' . $startAnchor . '<span class="btn btn-default">' . $icon . '</span></a></td></tr>';
97 return $ret;
98 }
99
100 /**
101 * Create an instance of \TYPO3\CMS\Core\TypoScript\ExtendedTemplateService in
102 * $GLOBALS['tmpl'] and looks for the first (visible) template
103 * record. If $template_uid was given and greater than zero, this record will be checked.
104 *
105 * Initializes the module. Done in this function because we may need to re-initialize if data is submitted!
106 *
107 * @param int $pageId The uid of the current page
108 * @param int $template_uid: The uid of the template record to be rendered (only if more than one template on the current page)
109 * @return bool Returns TRUE if a template record was found, otherwise FALSE
110 */
111 public function initialize_editor($pageId, $template_uid = 0)
112 {
113 /** @var ExtendedTemplateService $tmpl */
114 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
115 $GLOBALS['tmpl'] = $tmpl;
116
117 // Do not log time-performance information
118 $tmpl->tt_track = false;
119 $tmpl->init();
120
121 // Get the row of the first VISIBLE template of the page. where clause like the frontend.
122 $GLOBALS['tplRow'] = $tmpl->ext_getFirstTemplate($pageId, $template_uid);
123 if (is_array($GLOBALS['tplRow'])) {
124 $GLOBALS['tplRow'] = $this->processTemplateRowAfterLoading($GLOBALS['tplRow']);
125 return true;
126 }
127 return false;
128 }
129
130 /**
131 * Process template row after loading
132 *
133 * @param array $tplRow Template row
134 * @return array Preprocessed template row
135 */
136 public function processTemplateRowAfterLoading(array $tplRow)
137 {
138 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
139 // Let the recursion detection counter start at 91, so that only 10 recursive calls will be resolved
140 // Otherwise the editor will be bloated with way to many lines making it hard the break the cyclic recursion.
141 $tplRow['config'] = TypoScriptParser::checkIncludeLines($tplRow['config'], 91);
142 $tplRow['constants'] = TypoScriptParser::checkIncludeLines($tplRow['constants'], 91);
143 }
144 return $tplRow;
145 }
146
147 /**
148 * Process template row before saving
149 *
150 * @param array $tplRow Template row
151 * @return array Preprocessed template row
152 */
153 public function processTemplateRowBeforeSaving(array $tplRow)
154 {
155 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
156 $tplRow = TypoScriptParser::extractIncludes_array($tplRow);
157 }
158 return $tplRow;
159 }
160
161 /**
162 * @return LanguageService
163 */
164 protected function getLanguageService()
165 {
166 return $GLOBALS['LANG'];
167 }
168
169 /**
170 * The main processing method if this class
171 *
172 * @return string Information of the template status or the taken actions as HTML string
173 */
174 public function main()
175 {
176 $lang = $this->getLanguageService();
177 $lang->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang_info.xlf');
178 $this->pObj->MOD_MENU['includeTypoScriptFileContent'] = true;
179 $e = $this->pObj->e;
180 // Checking for more than one template an if, set a menu...
181 $manyTemplatesMenu = $this->pObj->templateMenu();
182 $template_uid = 0;
183 if ($manyTemplatesMenu) {
184 $template_uid = $this->pObj->MOD_SETTINGS['templatesOnPage'];
185 }
186 // Initialize
187 $existTemplate = $this->initialize_editor($this->pObj->id, $template_uid);
188 $tplRow = $GLOBALS['tplRow'];
189 $saveId = 0;
190 if ($existTemplate) {
191 $saveId = $tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid'];
192 }
193 // Create extension template
194 $newId = $this->pObj->createTemplate($this->pObj->id, $saveId);
195 if ($newId) {
196 // Switch to new template
197 $urlParameters = [
198 'id' => $this->pObj->id,
199 'SET[templatesOnPage]' => $newId
200 ];
201 $url = BackendUtility::getModuleUrl('web_ts', $urlParameters);
202 HttpUtility::redirect($url);
203 }
204 $tce = null;
205 $theOutput = '';
206 if ($existTemplate) {
207 // Update template ?
208 $POST = GeneralUtility::_POST();
209 if (
210 isset($POST['_savedok'])
211 || isset($POST['_saveandclosedok'])
212 ) {
213 // Set the data to be saved
214 $recData = array();
215 $alternativeFileName = array();
216 if (is_array($POST['data'])) {
217 foreach ($POST['data'] as $field => $val) {
218 switch ($field) {
219 case 'constants':
220 case 'config':
221 $recData['sys_template'][$saveId][$field] = $val;
222 break;
223 }
224 }
225 }
226 if (!empty($recData)) {
227 $recData['sys_template'][$saveId] = $this->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]);
228 // Create new tce-object
229 $tce = GeneralUtility::makeInstance(DataHandler::class);
230 $tce->stripslashes_values = false;
231 $tce->alternativeFileName = $alternativeFileName;
232 // Initialize
233 $tce->start($recData, array());
234 // Saved the stuff
235 $tce->process_datamap();
236 // Clear the cache (note: currently only admin-users can clear the cache in tce_main.php)
237 $tce->clear_cacheCmd('all');
238 // tce were processed successfully
239 $this->tce_processed = true;
240 // re-read the template ...
241 $this->initialize_editor($this->pObj->id, $template_uid);
242 $tplRow = $GLOBALS['tplRow'];
243 // reload template menu
244 $manyTemplatesMenu = $this->pObj->templateMenu();
245 }
246 }
247 // Hook post updating template/TCE processing
248 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'])) {
249 $postTCEProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'];
250 if (is_array($postTCEProcessingHook)) {
251 $hookParameters = array(
252 'POST' => $POST,
253 'tce' => $tce
254 );
255 foreach ($postTCEProcessingHook as $hookFunction) {
256 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
257 }
258 }
259 }
260 $content = '<a href="#" class="t3-js-clickmenutrigger" data-table="sys_template" data-uid="' . $tplRow['uid'] . '" data-listframe="1">' . $this->iconFactory->getIconForRecord('sys_template', $tplRow, Icon::SIZE_SMALL)->render() . '</a><strong>' . htmlspecialchars($tplRow['title']) . '</strong>' . (trim($tplRow['sitetitle']) ? htmlspecialchars(' (' . $tplRow['sitetitle'] . ')') : '');
261 $theOutput .= $this->pObj->doc->section($lang->getLL('templateInformation'), $content, 0, 1);
262 if ($manyTemplatesMenu) {
263 $theOutput .= $this->pObj->doc->section('', $manyTemplatesMenu);
264 }
265 $theOutput .= '<div style="padding-top: 10px;"></div>';
266 $numberOfRows = 35;
267 // If abort pressed, nothing should be edited:
268 if (isset($POST['_saveandclosedok'])) {
269 unset($e);
270 }
271 if (isset($e['constants'])) {
272 $outCode = '<textarea name="data[constants]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab"' . $this->pObj->doc->formWidth(48, true, 'width:98%;height:70%') . ' class="text-monospace">' . htmlspecialchars($tplRow['constants']) . '</textarea>';
273 $outCode .= '<input type="hidden" name="e[constants]" value="1">';
274 // Display "Include TypoScript file content?" checkbox
275 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[constants]=1', 'id="checkIncludeTypoScriptFileContent"');
276 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
277 $theOutput .= '<div style="padding-top: 15px;"></div>';
278 $theOutput .= $this->pObj->doc->section($lang->getLL('constants'), '', true);
279 $theOutput .= $this->pObj->doc->sectionEnd() . $outCode;
280 }
281 if (isset($e['config'])) {
282 $outCode = '<textarea name="data[config]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab"' . $this->pObj->doc->formWidth(48, true, 'width:98%;height:70%') . ' class="text-monospace">' . htmlspecialchars($tplRow['config']) . '</textarea>';
283 $outCode .= '<input type="hidden" name="e[config]" value="1">';
284 // Display "Include TypoScript file content?" checkbox
285 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[config]=1', 'id="checkIncludeTypoScriptFileContent"');
286 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
287 $theOutput .= '<div style="padding-top: 15px;"></div>';
288 $theOutput .= $this->pObj->doc->section($lang->getLL('setup'), '', true);
289 $theOutput .= $this->pObj->doc->sectionEnd() . $outCode;
290 }
291
292 // Processing:
293 $outCode = '';
294 $outCode .= $this->tableRow($lang->getLL('title'), htmlspecialchars($tplRow['title']), 'title', $tplRow['uid']);
295 $outCode .= $this->tableRow($lang->getLL('sitetitle'), htmlspecialchars($tplRow['sitetitle']), 'sitetitle', $tplRow['uid']);
296 $outCode .= $this->tableRow($lang->getLL('description'), nl2br(htmlspecialchars($tplRow['description'])), 'description', $tplRow['uid']);
297 $outCode .= $this->tableRow($lang->getLL('constants'), sprintf($lang->getLL('editToView'), trim($tplRow['constants']) ? count(explode(LF, $tplRow['constants'])) : 0), 'constants', $tplRow['uid']);
298 $outCode .= $this->tableRow($lang->getLL('setup'), sprintf($lang->getLL('editToView'), trim($tplRow['config']) ? count(explode(LF, $tplRow['config'])) : 0), 'config', $tplRow['uid']);
299 $outCode = '<div class="table-fit"><table class="table table-striped table-hover">' . $outCode . '</table></div>';
300
301 // Edit all icon:
302 $urlParameters = [
303 'edit' => [
304 'sys_template' => [
305 $tplRow['uid'] => 'edit'
306 ]
307 ],
308 'createExtension' => 0,
309 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
310 ];
311 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
312 $title = $lang->getLL('editTemplateRecord', true);
313 $icon = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
314 $outCode .= '<br /><a class="btn btn-default" href="' . htmlspecialchars($url)
315 . '"><strong>' . $icon . '&nbsp;' . $title . '</strong></a>';
316 $theOutput .= $this->pObj->doc->section('', $outCode);
317
318 // hook after compiling the output
319 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'])) {
320 $postOutputProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'];
321 if (is_array($postOutputProcessingHook)) {
322 $hookParameters = array(
323 'theOutput' => &$theOutput,
324 'POST' => $POST,
325 'e' => $e,
326 'tplRow' => $tplRow,
327 'numberOfRows' => $numberOfRows
328 );
329 foreach ($postOutputProcessingHook as $hookFunction) {
330 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
331 }
332 }
333 }
334 } else {
335 $theOutput .= $this->pObj->noTemplate(1);
336 }
337 return $theOutput;
338 }
339 }