[BUGFIX] Changed Constant Editor and Info/Modify subline to h3
[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\Backend\Module\AbstractFunctionModule;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\DataHandling\DataHandler;
20 use TYPO3\CMS\Core\Imaging\Icon;
21 use TYPO3\CMS\Core\Imaging\IconFactory;
22 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
23 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Core\Utility\HttpUtility;
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');
92 $startAnchor = '<a href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($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 $tmpl->init();
117
118 // Get the row of the first VISIBLE template of the page. where clause like the frontend.
119 $GLOBALS['tplRow'] = $tmpl->ext_getFirstTemplate($pageId, $template_uid);
120 if (is_array($GLOBALS['tplRow'])) {
121 $GLOBALS['tplRow'] = $this->processTemplateRowAfterLoading($GLOBALS['tplRow']);
122 return true;
123 }
124 return false;
125 }
126
127 /**
128 * Process template row after loading
129 *
130 * @param array $tplRow Template row
131 * @return array Preprocessed template row
132 */
133 public function processTemplateRowAfterLoading(array $tplRow)
134 {
135 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
136 // Let the recursion detection counter start at 91, so that only 10 recursive calls will be resolved
137 // Otherwise the editor will be bloated with way to many lines making it hard the break the cyclic recursion.
138 $tplRow['config'] = TypoScriptParser::checkIncludeLines($tplRow['config'], 91);
139 $tplRow['constants'] = TypoScriptParser::checkIncludeLines($tplRow['constants'], 91);
140 }
141 return $tplRow;
142 }
143
144 /**
145 * Process template row before saving
146 *
147 * @param array $tplRow Template row
148 * @return array Preprocessed template row
149 */
150 public function processTemplateRowBeforeSaving(array $tplRow)
151 {
152 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
153 $tplRow = TypoScriptParser::extractIncludes_array($tplRow);
154 }
155 return $tplRow;
156 }
157
158 /**
159 * @return LanguageService
160 */
161 protected function getLanguageService()
162 {
163 return $GLOBALS['LANG'];
164 }
165
166 /**
167 * The main processing method if this class
168 *
169 * @return string Information of the template status or the taken actions as HTML string
170 */
171 public function main()
172 {
173 $lang = $this->getLanguageService();
174 $lang->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang_info.xlf');
175 $this->pObj->MOD_MENU['includeTypoScriptFileContent'] = true;
176 $e = $this->pObj->e;
177 // Checking for more than one template an if, set a menu...
178 $manyTemplatesMenu = $this->pObj->templateMenu();
179 $template_uid = 0;
180 if ($manyTemplatesMenu) {
181 $template_uid = $this->pObj->MOD_SETTINGS['templatesOnPage'];
182 }
183 // Initialize
184 $existTemplate = $this->initialize_editor($this->pObj->id, $template_uid);
185 $tplRow = $GLOBALS['tplRow'];
186 $saveId = 0;
187 if ($existTemplate) {
188 $saveId = $tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid'];
189 }
190 // Create extension template
191 $newId = $this->pObj->createTemplate($this->pObj->id, $saveId);
192 if ($newId) {
193 // Switch to new template
194 $urlParameters = [
195 'id' => $this->pObj->id,
196 'SET[templatesOnPage]' => $newId
197 ];
198 $url = BackendUtility::getModuleUrl('web_ts', $urlParameters);
199 HttpUtility::redirect($url);
200 }
201 $tce = null;
202 $theOutput = '';
203 if ($existTemplate) {
204 // Update template ?
205 $POST = GeneralUtility::_POST();
206 if (
207 isset($POST['_savedok'])
208 || isset($POST['_saveandclosedok'])
209 ) {
210 // Set the data to be saved
211 $recData = array();
212 $alternativeFileName = array();
213 if (is_array($POST['data'])) {
214 foreach ($POST['data'] as $field => $val) {
215 switch ($field) {
216 case 'constants':
217 case 'config':
218 $recData['sys_template'][$saveId][$field] = $val;
219 break;
220 }
221 }
222 }
223 if (!empty($recData)) {
224 $recData['sys_template'][$saveId] = $this->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]);
225 // Create new tce-object
226 $tce = GeneralUtility::makeInstance(DataHandler::class);
227 $tce->alternativeFileName = $alternativeFileName;
228 // Initialize
229 $tce->start($recData, array());
230 // Saved the stuff
231 $tce->process_datamap();
232 // Clear the cache (note: currently only admin-users can clear the cache in tce_main.php)
233 $tce->clear_cacheCmd('all');
234 // tce were processed successfully
235 $this->tce_processed = true;
236 // re-read the template ...
237 $this->initialize_editor($this->pObj->id, $template_uid);
238 $tplRow = $GLOBALS['tplRow'];
239 // reload template menu
240 $manyTemplatesMenu = $this->pObj->templateMenu();
241 }
242 }
243 // Hook post updating template/TCE processing
244 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'])) {
245 $postTCEProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'];
246 if (is_array($postTCEProcessingHook)) {
247 $hookParameters = array(
248 'POST' => $POST,
249 'tce' => $tce
250 );
251 foreach ($postTCEProcessingHook as $hookFunction) {
252 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
253 }
254 }
255 }
256 $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>&nbsp;' . htmlspecialchars($tplRow['title']) . '</strong>' . (trim($tplRow['sitetitle']) ? htmlspecialchars(' (' . $tplRow['sitetitle'] . ')') : '');
257 $theOutput .= '<h3>' . htmlspecialchars($lang->getLL('templateInformation')) . '</h3><div>' . $content . '</div>';
258 if ($manyTemplatesMenu) {
259 $theOutput .= '<div>' . $manyTemplatesMenu . '</div>';
260 }
261 $theOutput .= '<div style="padding-top: 10px;"></div>';
262 $numberOfRows = 35;
263 // If abort pressed, nothing should be edited:
264 if (isset($POST['_saveandclosedok'])) {
265 unset($e);
266 }
267 if (isset($e['constants'])) {
268 $outCode = '<textarea name="data[constants]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab" style="width:98%;height:70%" class="text-monospace">' . htmlspecialchars($tplRow['constants']) . '</textarea>';
269 $outCode .= '<input type="hidden" name="e[constants]" value="1">';
270 // Display "Include TypoScript file content?" checkbox
271 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[constants]=1', 'id="checkIncludeTypoScriptFileContent"');
272 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
273 $theOutput .= '<div style="padding-top: 15px;"></div>';
274 $theOutput .= '<h3>' . htmlspecialchars($lang->getLL('constants')) . '</h3>';
275 $theOutput .= $outCode;
276 }
277 if (isset($e['config'])) {
278 $outCode = '<textarea name="data[config]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab" style="width:98%;height:70%" class="text-monospace">' . htmlspecialchars($tplRow['config']) . '</textarea>';
279 $outCode .= '<input type="hidden" name="e[config]" value="1">';
280 // Display "Include TypoScript file content?" checkbox
281 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[config]=1', 'id="checkIncludeTypoScriptFileContent"');
282 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
283 $theOutput .= '<div style="padding-top: 15px;"></div>';
284 $theOutput .= '<h3>' . htmlspecialchars($lang->getLL('setup')) . '</h3>';
285 $theOutput .= $outCode;
286 }
287
288 // Processing:
289 $outCode = '';
290 $outCode .= $this->tableRow($lang->getLL('title'), htmlspecialchars($tplRow['title']), 'title', $tplRow['uid']);
291 $outCode .= $this->tableRow($lang->getLL('sitetitle'), htmlspecialchars($tplRow['sitetitle']), 'sitetitle', $tplRow['uid']);
292 $outCode .= $this->tableRow($lang->getLL('description'), nl2br(htmlspecialchars($tplRow['description'])), 'description', $tplRow['uid']);
293 $outCode .= $this->tableRow($lang->getLL('constants'), sprintf($lang->getLL('editToView'), trim($tplRow['constants']) ? count(explode(LF, $tplRow['constants'])) : 0), 'constants', $tplRow['uid']);
294 $outCode .= $this->tableRow($lang->getLL('setup'), sprintf($lang->getLL('editToView'), trim($tplRow['config']) ? count(explode(LF, $tplRow['config'])) : 0), 'config', $tplRow['uid']);
295 $outCode = '<div class="table-fit"><table class="table table-striped table-hover">' . $outCode . '</table></div>';
296
297 // Edit all icon:
298 $urlParameters = [
299 'edit' => [
300 'sys_template' => [
301 $tplRow['uid'] => 'edit'
302 ]
303 ],
304 'createExtension' => 0,
305 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
306 ];
307 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
308 $title = htmlspecialchars($lang->getLL('editTemplateRecord'));
309 $icon = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
310 $outCode .= '<br /><a class="btn btn-default" href="' . htmlspecialchars($url)
311 . '"><strong>' . $icon . '&nbsp;' . $title . '</strong></a>';
312 $theOutput .= '<div>' . $outCode . '</div>';
313
314 // hook after compiling the output
315 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'])) {
316 $postOutputProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'];
317 if (is_array($postOutputProcessingHook)) {
318 $hookParameters = array(
319 'theOutput' => &$theOutput,
320 'POST' => $POST,
321 'e' => $e,
322 'tplRow' => $tplRow,
323 'numberOfRows' => $numberOfRows
324 );
325 foreach ($postOutputProcessingHook as $hookFunction) {
326 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
327 }
328 }
329 }
330 } else {
331 $theOutput .= $this->pObj->noTemplate(1);
332 }
333 return $theOutput;
334 }
335 }