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