52684c4313c8b639c3ca7729451d67cbf8c3b434
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateObjectBrowserModuleFunctionController.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\Exception;
21 use TYPO3\CMS\Core\Messaging\FlashMessage;
22 use TYPO3\CMS\Core\Messaging\FlashMessageService;
23 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Core\Utility\RootlineUtility;
26 use TYPO3\CMS\Fluid\View\StandaloneView;
27
28 /**
29 * This class displays the submodule "TypoScript Object Browser" inside the Web > Template module
30 */
31 class TypoScriptTemplateObjectBrowserModuleFunctionController extends AbstractFunctionModule
32 {
33 /**
34 * @var string
35 */
36 protected $localLanguageFilePath;
37
38 /**
39 * @var TypoScriptTemplateModuleController
40 */
41 public $pObj;
42
43 /**
44 * The currently selected sys_template record
45 * @var array
46 */
47 protected $templateRow;
48
49 /**
50 * @var ExtendedTemplateService
51 */
52 protected $templateService;
53
54 /**
55 * Init
56 *
57 * @param TypoScriptTemplateModuleController $pObj
58 * @param array $conf
59 */
60 public function init(&$pObj, $conf)
61 {
62 parent::init($pObj, $conf);
63 $this->pObj->modMenu_dontValidateList .= ',ts_browser_toplevel_setup,ts_browser_toplevel_const,ts_browser_TLKeys_setup,ts_browser_TLKeys_const';
64 $this->pObj->modMenu_setDefaultList .= ',ts_browser_fixedLgd,ts_browser_showComments';
65 $this->localLanguageFilePath = 'EXT:tstemplate/Resources/Private/Language/locallang_objbrowser.xlf';
66 }
67
68 /**
69 * Mod menu
70 *
71 * @return array
72 */
73 public function modMenu()
74 {
75 $lang = $this->getLanguageService();
76 $lang->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang_objbrowser.xlf');
77 $modMenu = [
78 'ts_browser_type' => [
79 'const' => $lang->getLL('constants'),
80 'setup' => $lang->getLL('setup')
81 ],
82 'ts_browser_toplevel_setup' => [
83 '0' => mb_strtolower($lang->getLL('all'), 'utf-8')
84 ],
85 'ts_browser_toplevel_const' => [
86 '0' => mb_strtolower($lang->getLL('all'), 'utf-8')
87 ],
88 'ts_browser_const' => [
89 '0' => $lang->getLL('plainSubstitution'),
90 'subst' => $lang->getLL('substitutedGreen'),
91 'const' => $lang->getLL('unsubstitutedGreen')
92 ],
93 'ts_browser_regexsearch' => '1',
94 'ts_browser_fixedLgd' => '1',
95 'ts_browser_showComments' => '1',
96 'ts_browser_alphaSort' => '1'
97 ];
98 foreach (['setup', 'const'] as $bType) {
99 $addKey = GeneralUtility::_GET('addKey');
100 // If any plus-signs were clicked, it's registered.
101 if (is_array($addKey)) {
102 reset($addKey);
103 if (current($addKey)) {
104 $this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType][key($addKey)] = key($addKey);
105 } else {
106 unset($this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType][key($addKey)]);
107 }
108 $this->getBackendUserAuthentication()->pushModuleData($this->pObj->MCONF['name'], $this->pObj->MOD_SETTINGS);
109 }
110 if (!empty($this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType])) {
111 $modMenu['ts_browser_toplevel_' . $bType]['-'] = '---';
112 $modMenu['ts_browser_toplevel_' . $bType] = $modMenu['ts_browser_toplevel_' . $bType] + $this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType];
113 }
114 }
115 return $modMenu;
116 }
117
118 /**
119 * Initialize editor
120 *
121 * Initializes the module. Done in this function because we may need to re-initialize if data is submitted!
122 *
123 * @param int $pageId
124 * @param int $template_uid
125 * @return bool
126 */
127 public function initialize_editor($pageId, $template_uid = 0)
128 {
129 // Defined global here!
130 $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
131 $this->templateService->init();
132
133 // Gets the rootLine
134 $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $pageId);
135 $rootLine = $rootlineUtility->get();
136 // This generates the constants/config + hierarchy info for the template.
137 $this->templateService->runThroughTemplates($rootLine, $template_uid);
138
139 // Get the row of the first VISIBLE template of the page. whereclause like the frontend.
140 $this->templateRow = $this->templateService->ext_getFirstTemplate($pageId, $template_uid);
141 return is_array($this->templateRow);
142 }
143
144 /**
145 * Main
146 *
147 * @return string
148 */
149 public function main()
150 {
151 $lang = $this->getLanguageService();
152 $POST = GeneralUtility::_POST();
153
154 // Checking for more than one template an if, set a menu...
155 $manyTemplatesMenu = $this->pObj->templateMenu();
156 $template_uid = 0;
157 if ($manyTemplatesMenu) {
158 $template_uid = $this->pObj->MOD_SETTINGS['templatesOnPage'];
159 }
160 $bType = $this->pObj->MOD_SETTINGS['ts_browser_type'];
161 $existTemplate = $this->initialize_editor($this->pObj->id, $template_uid);
162 // initialize
163 $assigns = [];
164 $assigns['LLPrefix'] = 'LLL:' . $this->localLanguageFilePath . ':';
165 $assigns['existTemplate'] = $existTemplate;
166 $assigns['tsBrowserType'] = $this->pObj->MOD_SETTINGS['ts_browser_type'];
167 if ($existTemplate) {
168 $assigns['templateRecord'] = $this->templateRow;
169 $assigns['linkWrapTemplateTitle'] = $this->pObj->linkWrapTemplateTitle($this->templateRow['title'], ($bType === 'setup' ? 'config' : 'constants'));
170 $assigns['manyTemplatesMenu'] = $manyTemplatesMenu;
171
172 if ($POST['add_property'] || $POST['update_value'] || $POST['clear_object']) {
173 // add property
174 $line = '';
175 if (is_array($POST['data'])) {
176 $name = key($POST['data']);
177 if ($POST['data'][$name]['name'] !== '') {
178 // Workaround for this special case: User adds a key and submits by pressing the return key. The form however will use "add_property" which is the name of the first submit button in this form.
179 unset($POST['update_value']);
180 $POST['add_property'] = 'Add';
181 }
182 if ($POST['add_property']) {
183 $property = trim($POST['data'][$name]['name']);
184 if (preg_replace('/[^a-zA-Z0-9_\\.]*/', '', $property) != $property) {
185 $badPropertyMessage = GeneralUtility::makeInstance(FlashMessage::class, $lang->getLL('noSpaces') . $lang->getLL('nothingUpdated'), $lang->getLL('badProperty'), FlashMessage::ERROR);
186 $this->addFlashMessage($badPropertyMessage);
187 } else {
188 $pline = $name . '.' . $property . ' = ' . trim($POST['data'][$name]['propertyValue']);
189 $propertyAddedMessage = GeneralUtility::makeInstance(FlashMessage::class, $pline, $lang->getLL('propertyAdded'));
190 $this->addFlashMessage($propertyAddedMessage);
191 $line .= LF . $pline;
192 }
193 } elseif ($POST['update_value']) {
194 $pline = $name . ' = ' . trim($POST['data'][$name]['value']);
195 $updatedMessage = GeneralUtility::makeInstance(FlashMessage::class, $pline, $lang->getLL('valueUpdated'));
196 $this->addFlashMessage($updatedMessage);
197 $line .= LF . $pline;
198 } elseif ($POST['clear_object']) {
199 if ($POST['data'][$name]['clearValue']) {
200 $pline = $name . ' >';
201 $objectClearedMessage = GeneralUtility::makeInstance(FlashMessage::class, $pline, $lang->getLL('objectCleared'));
202 $this->addFlashMessage($objectClearedMessage);
203 $line .= LF . $pline;
204 }
205 }
206 }
207 if ($line) {
208 $saveId = $this->templateRow['_ORIG_uid'] ?: $this->templateRow['uid'];
209 // Set the data to be saved
210 $recData = [];
211 $field = $bType === 'setup' ? 'config' : 'constants';
212 $recData['sys_template'][$saveId][$field] = $this->templateRow[$field] . $line;
213 // Create new tce-object
214 $tce = GeneralUtility::makeInstance(DataHandler::class);
215 // Initialize
216 $tce->start($recData, []);
217 // Saved the stuff
218 $tce->process_datamap();
219 // Clear the cache (note: currently only admin-users can clear the cache in tce_main.php)
220 $tce->clear_cacheCmd('all');
221 // re-read the template ...
222 $this->initialize_editor($this->pObj->id, $template_uid);
223 }
224 }
225 }
226 $tsbr = GeneralUtility::_GET('tsbr');
227 $update = 0;
228 if (is_array($tsbr)) {
229 // If any plus-signs were clicked, it's registred.
230 $this->pObj->MOD_SETTINGS['tsbrowser_depthKeys_' . $bType] = $this->templateService->ext_depthKeys($tsbr, $this->pObj->MOD_SETTINGS['tsbrowser_depthKeys_' . $bType]);
231 $update = 1;
232 }
233 if ($POST['Submit']) {
234 // If any POST-vars are send, update the condition array
235 $this->pObj->MOD_SETTINGS['tsbrowser_conditions'] = $POST['conditions'];
236 $update = 1;
237 }
238 if ($update) {
239 $this->getBackendUserAuthentication()->pushModuleData($this->pObj->MCONF['name'], $this->pObj->MOD_SETTINGS);
240 }
241 $this->templateService->matchAlternative = $this->pObj->MOD_SETTINGS['tsbrowser_conditions'];
242 $this->templateService->matchAlternative[] = 'dummydummydummydummydummydummydummydummydummydummydummy';
243 // This is just here to make sure that at least one element is in the array so that the tsparser actually uses this array to match.
244 $this->templateService->constantMode = $this->pObj->MOD_SETTINGS['ts_browser_const'];
245 if ($this->pObj->sObj && $this->templateService->constantMode) {
246 $this->templateService->constantMode = 'untouched';
247 }
248 $this->templateService->regexMode = $this->pObj->MOD_SETTINGS['ts_browser_regexsearch'];
249 $this->templateService->fixedLgd = $this->pObj->MOD_SETTINGS['ts_browser_fixedLgd'];
250 $this->templateService->linkObjects = true;
251 $this->templateService->ext_regLinenumbers = true;
252 $this->templateService->ext_regComments = $this->pObj->MOD_SETTINGS['ts_browser_showComments'];
253 $this->templateService->bType = $bType;
254 if ($this->pObj->MOD_SETTINGS['ts_browser_type'] === 'const') {
255 $this->templateService->ext_constants_BRP = (int)GeneralUtility::_GP('breakPointLN');
256 } else {
257 $this->templateService->ext_config_BRP = (int)GeneralUtility::_GP('breakPointLN');
258 }
259 $this->templateService->generateConfig();
260 if ($bType === 'setup') {
261 $theSetup = $this->templateService->setup;
262 } else {
263 $theSetup = $this->templateService->setup_constants;
264 }
265 // EDIT A VALUE:
266 $assigns['typoScriptPath'] = $this->pObj->sObj;
267 if ($this->pObj->sObj) {
268 list($theSetup, $theSetupValue) = $this->templateService->ext_getSetup($theSetup, $this->pObj->sObj ? $this->pObj->sObj : '');
269 $assigns['theSetupValue'] = $theSetupValue;
270 if ($existTemplate === false) {
271 $noTemplateMessage = GeneralUtility::makeInstance(FlashMessage::class, $lang->getLL('noCurrentTemplate'), $lang->getLL('edit'), FlashMessage::ERROR);
272 $this->addFlashMessage($noTemplateMessage);
273 }
274 // Links:
275 $urlParameters = [
276 'id' => $this->pObj->id
277 ];
278 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
279 $assigns['moduleUrl'] = BackendUtility::getModuleUrl('web_ts', $urlParameters);
280 $assigns['isNotInTopLevelKeyList'] = !isset($this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType][$this->pObj->sObj]);
281 $assigns['hasProperties'] = !empty($theSetup);
282 if (!$this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType][$this->pObj->sObj]) {
283 if (!empty($theSetup)) {
284 $assigns['moduleUrlObjectListAction'] = $aHref . '&addKey[' . rawurlencode($this->pObj->sObj) . ']=1&SET[ts_browser_toplevel_' . $bType . ']=' . rawurlencode($this->pObj->sObj);
285 }
286 } else {
287 $assigns['moduleUrlObjectListAction'] = $aHref . '&addKey[' . rawurlencode($this->pObj->sObj) . ']=0&SET[ts_browser_toplevel_' . $bType . ']=0';
288 }
289 } else {
290 $this->templateService->tsbrowser_depthKeys = $this->pObj->MOD_SETTINGS['tsbrowser_depthKeys_' . $bType];
291 if (GeneralUtility::_POST('search') && GeneralUtility::_POST('search_field')) {
292 // If any POST-vars are send, update the condition array
293 $searchString = GeneralUtility::_POST('search_field');
294 try {
295 $this->templateService->tsbrowser_depthKeys =
296 $this->templateService->ext_getSearchKeys(
297 $theSetup,
298 '',
299 $searchString,
300 []
301 );
302 } catch (Exception $e) {
303 $this->addFlashMessage(
304 GeneralUtility::makeInstance(FlashMessage::class, sprintf($lang->getLL('error.' . $e->getCode()), $searchString), '', FlashMessage::ERROR)
305 );
306 }
307 }
308 $assigns['hasTsBrowserTypes'] = is_array($this->pObj->MOD_MENU['ts_browser_type']) && count($this->pObj->MOD_MENU['ts_browser_type']) > 1;
309 if (is_array($this->pObj->MOD_MENU['ts_browser_type']) && count($this->pObj->MOD_MENU['ts_browser_type']) > 1) {
310 $assigns['browserTypeDropdownMenu'] = BackendUtility::getDropdownMenu($this->pObj->id, 'SET[ts_browser_type]', $bType, $this->pObj->MOD_MENU['ts_browser_type']);
311 }
312 $assigns['hasTopLevelInObjectList'] = is_array($this->pObj->MOD_MENU['ts_browser_toplevel_' . $bType]) && count($this->pObj->MOD_MENU['ts_browser_toplevel_' . $bType]) > 1;
313 if (is_array($this->pObj->MOD_MENU['ts_browser_toplevel_' . $bType]) && count($this->pObj->MOD_MENU['ts_browser_toplevel_' . $bType]) > 1) {
314 $assigns['objectListDropdownMenu'] = BackendUtility::getDropdownMenu($this->pObj->id, 'SET[ts_browser_toplevel_' . $bType . ']', $this->pObj->MOD_SETTINGS['ts_browser_toplevel_' . $bType], $this->pObj->MOD_MENU['ts_browser_toplevel_' . $bType]);
315 }
316
317 $assigns['regexSearchCheckbox'] = BackendUtility::getFuncCheck($this->pObj->id, 'SET[ts_browser_regexsearch]', $this->pObj->MOD_SETTINGS['ts_browser_regexsearch'], '', '', 'id="checkTs_browser_regexsearch"');
318 $assigns['postSearchField'] = $POST['search_field'];
319 $theKey = $this->pObj->MOD_SETTINGS['ts_browser_toplevel_' . $bType];
320 if (!$theKey || !str_replace('-', '', $theKey)) {
321 $theKey = '';
322 }
323 list($theSetup, $theSetupValue) = $this->templateService->ext_getSetup($theSetup, $this->pObj->MOD_SETTINGS['ts_browser_toplevel_' . $bType] ? $this->pObj->MOD_SETTINGS['ts_browser_toplevel_' . $bType] : '');
324 $tree = $this->templateService->ext_getObjTree($theSetup, $theKey, '', '', $theSetupValue, $this->pObj->MOD_SETTINGS['ts_browser_alphaSort']);
325 $tree = $this->templateService->substituteCMarkers($tree);
326 $urlParameters = [
327 'id' => $this->pObj->id
328 ];
329 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
330 // Parser Errors:
331 $pEkey = $bType === 'setup' ? 'config' : 'constants';
332 $assigns['hasParseErrors'] = !empty($this->templateService->parserErrors[$pEkey]);
333 if (!empty($this->templateService->parserErrors[$pEkey])) {
334 $assigns['showErrorDetailsUri'] = $aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TemplateAnalyzerModuleFunctionController&template=all&SET[ts_analyzer_checkLinenum]=1#line-';
335 $assigns['parseErrors'] = $this->templateService->parserErrors[$pEkey];
336 }
337
338 if (isset($this->pObj->MOD_SETTINGS['ts_browser_TLKeys_' . $bType][$theKey])) {
339 $assigns['moduleUrlRemoveFromObjectList'] = $aHref . '&addKey[' . $theKey . ']=0&SET[ts_browser_toplevel_' . $bType . ']=0';
340 }
341
342 $assigns['hasKeySelected'] = $theKey !== '';
343
344 if ($theKey) {
345 $assigns['treeLabel'] = $theKey;
346 } else {
347 $assigns['rootLLKey'] = $bType === 'setup' ? 'setupRoot' : 'constantRoot';
348 }
349 $assigns['tsTree'] = $tree;
350
351 // second row options
352 $assigns['isSetupAndCropLinesDisabled'] = $bType === 'setup' && !$this->pObj->MOD_SETTINGS['ts_browser_fixedLgd'];
353 $assigns['checkBoxShowComments'] = BackendUtility::getFuncCheck($this->pObj->id, 'SET[ts_browser_showComments]', $this->pObj->MOD_SETTINGS['ts_browser_showComments'], '', '', 'id="checkTs_browser_showComments"');
354 $assigns['checkBoxAlphaSort'] = BackendUtility::getFuncCheck($this->pObj->id, 'SET[ts_browser_alphaSort]', $this->pObj->MOD_SETTINGS['ts_browser_alphaSort'], '', '', 'id="checkTs_browser_alphaSort"');
355 $assigns['checkBoxCropLines'] = BackendUtility::getFuncCheck($this->pObj->id, 'SET[ts_browser_fixedLgd]', $this->pObj->MOD_SETTINGS['ts_browser_fixedLgd'], '', '', 'id="checkTs_browser_fixedLgd"');
356 if ($bType === 'setup' && !$this->pObj->MOD_SETTINGS['ts_browser_fixedLgd']) {
357 $assigns['dropdownDisplayConstants'] = BackendUtility::getDropdownMenu($this->pObj->id, 'SET[ts_browser_const]', $this->pObj->MOD_SETTINGS['ts_browser_const'], $this->pObj->MOD_MENU['ts_browser_const']);
358 }
359
360 // Conditions:
361 $assigns['hasConditions'] = is_array($this->templateService->sections) && !empty($this->templateService->sections);
362 if (is_array($this->templateService->sections) && !empty($this->templateService->sections)) {
363 $tsConditions = [];
364 foreach ($this->templateService->sections as $key => $val) {
365 $tsConditions[] = [
366 'key' => $key,
367 'value' => $val,
368 'label' => $this->templateService->substituteCMarkers(htmlspecialchars($val)),
369 'isSet' => $this->pObj->MOD_SETTINGS['tsbrowser_conditions'][$key] ? true : false
370 ];
371 }
372 $assigns['tsConditions'] = $tsConditions;
373 }
374 // Ending section displayoptions
375 }
376
377 $view = GeneralUtility::makeInstance(StandaloneView::class);
378 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
379 'EXT:tstemplate/Resources/Private/Templates/TemplateObjectBrowserModuleFunction.html'
380 ));
381 $view->assignMultiple($assigns);
382
383 return $view->render();
384 }
385
386 /**
387 * Add flash message to queue
388 *
389 * @param FlashMessage $flashMessage
390 */
391 protected function addFlashMessage(FlashMessage $flashMessage)
392 {
393 /** @var $flashMessageService FlashMessageService */
394 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
395 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
396 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
397 $defaultFlashMessageQueue->enqueue($flashMessage);
398 }
399 }