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