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