[!!!][TASK] Remove deprecated code from EXT:tstemplate
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateModuleController.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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Routing\UriBuilder;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
24 use TYPO3\CMS\Core\Database\Connection;
25 use TYPO3\CMS\Core\Database\ConnectionPool;
26 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
27 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28 use TYPO3\CMS\Core\DataHandling\DataHandler;
29 use TYPO3\CMS\Core\Http\HtmlResponse;
30 use TYPO3\CMS\Core\Imaging\Icon;
31 use TYPO3\CMS\Core\Localization\LanguageService;
32 use TYPO3\CMS\Core\Messaging\FlashMessage;
33 use TYPO3\CMS\Core\Messaging\FlashMessageService;
34 use TYPO3\CMS\Core\Page\PageRenderer;
35 use TYPO3\CMS\Core\Type\Bitmask\Permission;
36 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
37 use TYPO3\CMS\Core\Utility\GeneralUtility;
38 use TYPO3\CMS\Core\Versioning\VersionState;
39 use TYPO3\CMS\Fluid\View\StandaloneView;
40 use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
41
42 /**
43 * Module: TypoScript Tools
44 * @internal This is a specific Backend Controller implementation and is not considered part of the Public TYPO3 API.
45 */
46 class TypoScriptTemplateModuleController
47 {
48
49 /**
50 * @var string
51 */
52 protected $perms_clause;
53
54 /**
55 * @var string
56 */
57 public $modMenu_dontValidateList = '';
58
59 /**
60 * @var string Written by client classes
61 */
62 public $modMenu_setDefaultList = '';
63
64 /**
65 * @var array
66 */
67 protected $pageinfo = [];
68
69 /**
70 * @var bool
71 */
72 protected $access = false;
73
74 /**
75 * The name of the module
76 *
77 * @var string
78 */
79 protected $moduleName = 'web_ts';
80
81 /**
82 * ModuleTemplate Container
83 *
84 * @var ModuleTemplate
85 */
86 protected $moduleTemplate;
87
88 /**
89 * @var ExtendedTemplateService
90 */
91 protected $templateService;
92
93 /**
94 * @var int GET/POST var 'id'
95 */
96 protected $id;
97
98 /**
99 * The module menu items array. Each key represents a key for which values can range between the items in the array of that key.
100 * Written by client classes.
101 *
102 * @var array
103 */
104 public $MOD_MENU = [
105 'function' => []
106 ];
107
108 /**
109 * Current settings for the keys of the MOD_MENU array, used in client classes
110 *
111 * @see $MOD_MENU
112 * @var array
113 */
114 public $MOD_SETTINGS = [];
115
116 /**
117 * Module TSconfig based on PAGE TSconfig / USER TSconfig
118 *
119 * @var array
120 */
121 protected $modTSconfig;
122
123 /**
124 * Contains module configuration parts from TBE_MODULES_EXT if found
125 *
126 * @see handleExternalFunctionValue()
127 * @var array
128 */
129 protected $extClassConf;
130
131 /**
132 * Generally used for accumulating the output content of backend modules
133 *
134 * @var string
135 */
136 protected $content = '';
137
138 /**
139 * May contain an instance of a 'Function menu module' which connects to this backend module.
140 *
141 * @see checkExtObj()
142 * @var \object
143 */
144 protected $extObj;
145
146 /**
147 * Constructor
148 */
149 public function __construct()
150 {
151 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
152 $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
153
154 $this->moduleTemplate->addJavaScriptCode(
155 'jumpToUrl',
156 '
157 function jumpToUrl(URL) {
158 window.location.href = URL;
159 return false;
160 }
161 '
162 );
163 }
164
165 /**
166 * Init
167 */
168 protected function init()
169 {
170 $this->menuConfig();
171 $this->handleExternalFunctionValue();
172 $this->id = (int)GeneralUtility::_GP('id');
173 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
174 }
175
176 /**
177 * Clear cache
178 */
179 protected function clearCache()
180 {
181 if (GeneralUtility::_GP('clear_all_cache')) {
182 $tce = GeneralUtility::makeInstance(DataHandler::class);
183 $tce->start([], []);
184 $tce->clear_cacheCmd('all');
185 }
186 }
187
188 /**
189 * Main
190 */
191 protected function main()
192 {
193 // Access check...
194 // The page will show only if there is a valid page and if this page may be viewed by the user
195 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
196 $this->access = is_array($this->pageinfo);
197 $view = $this->getFluidTemplateObject('tstemplate');
198 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
199 if ($this->id && $this->access) {
200 $urlParameters = [
201 'id' => $this->id,
202 'template' => 'all'
203 ];
204 $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
205
206 // JavaScript
207 $this->moduleTemplate->addJavaScriptCode(
208 'TSTemplateInlineJS',
209 'function uFormUrl(aname) {
210 document.forms[0].action = ' . GeneralUtility::quoteJSvalue($aHref . '#') . '+aname;
211 }
212 function brPoint(lnumber,t) {
213 window.location.href = '
214 . GeneralUtility::quoteJSvalue(
215 $aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\'
216 . 'TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='
217 ) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
218 return false;
219 }
220 if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';'
221 );
222 $this->moduleTemplate->getPageRenderer()->addCssInlineBlock(
223 'TSTemplateInlineStyle',
224 'TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
225 TABLE#typo3-objectBrowser A { text-decoration: none; }
226 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
227 .ts-typoscript { width: 100%; }
228 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
229 .tst-analyzer-options { margin:5px 0; }'
230 );
231 // Setting up the context sensitive menu:
232 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
233 // Build the module content
234 $view->assign('actionName', $aHref);
235 $view->assign('typoscriptTemplateModuleContent', $this->getExtObjContent());
236 // Setting up the buttons and markers for docheader
237 $this->getButtons();
238 $this->generateMenu();
239 } else {
240 $workspaceId = $this->getBackendUser()->workspace;
241 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
242 ->getQueryBuilderForTable('sys_template');
243 $queryBuilder->getRestrictions()
244 ->removeAll()
245 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
246 $this->applyWorkspaceConstraint(
247 $queryBuilder,
248 'sys_template',
249 $workspaceId
250 );
251 $result = $queryBuilder
252 ->select(
253 'uid',
254 'pid',
255 'title',
256 'sitetitle',
257 'root',
258 'hidden',
259 'starttime',
260 'endtime',
261 't3ver_oid',
262 't3ver_wsid',
263 't3ver_state',
264 't3ver_move_id'
265 )
266 ->from('sys_template')
267 ->orderBy('sys_template.pid')
268 ->addOrderBy('sys_template.sorting')
269 ->execute();
270 $pArray = [];
271 while ($record = $result->fetch()) {
272 BackendUtility::workspaceOL('sys_template', $record, $workspaceId, true);
273 if (empty($record) || VersionState::cast($record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
274 continue;
275 }
276 $additionalFieldsForRootline = ['sorting', 'shortcut'];
277 $rootline = BackendUtility::BEgetRootLine($record['pid'], '', true, $additionalFieldsForRootline);
278 $this->setInPageArray($pArray, $rootline, $record);
279 }
280
281 $view->getRenderingContext()->setControllerAction('PageZero');
282 $view->assign('pageTree', $pArray);
283
284 // RENDER LIST of pages with templates, END
285 // Setting up the buttons and markers for docheader
286 $this->getButtons();
287 }
288 $this->content = $view->render();
289 }
290
291 /**
292 * Generates the menu based on $this->MOD_MENU
293 *
294 * @throws \InvalidArgumentException
295 */
296 protected function generateMenu()
297 {
298 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
299 $menu->setIdentifier('WebFuncJumpMenu');
300 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
301 foreach ($this->MOD_MENU['function'] as $controller => $title) {
302 $item = $menu
303 ->makeMenuItem()
304 ->setHref(
305 (string)$uriBuilder->buildUriFromRoute(
306 $this->moduleName,
307 [
308 'id' => $this->id,
309 'SET' => [
310 'function' => $controller
311 ]
312 ]
313 )
314 )
315 ->setTitle($title);
316 if ($controller === $this->MOD_SETTINGS['function']) {
317 $item->setActive(true);
318 }
319 $menu->addMenuItem($item);
320 }
321 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
322 }
323
324 /**
325 * Injects the request object for the current request or subrequest
326 * Then checks for module functions that have hooked in, and renders menu etc.
327 *
328 * @param ServerRequestInterface $request the current request
329 * @return ResponseInterface the response with the content
330 */
331 public function mainAction(ServerRequestInterface $request): ResponseInterface
332 {
333 $this->init();
334
335 // Checking for first level external objects
336 $this->checkExtObj();
337
338 $this->clearCache();
339 $this->main();
340
341 $this->moduleTemplate->setContent($this->content);
342 return new HtmlResponse($this->moduleTemplate->renderContent());
343 }
344
345 /**
346 * Create the panel of buttons for submitting the form or otherwise perform operations.
347 */
348 protected function getButtons()
349 {
350 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
351 $lang = $this->getLanguageService();
352
353 if ($this->id && $this->access) {
354 // View page
355 $viewButton = $buttonBar->makeLinkButton()
356 ->setHref('#')
357 ->setOnClick(BackendUtility::viewOnClick(
358 $this->pageinfo['uid'],
359 '',
360 BackendUtility::BEgetRootLine($this->pageinfo['uid'])
361 ))
362 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
363 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-page', Icon::SIZE_SMALL));
364 $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
365
366 if ($this->extClassConf['name'] === TypoScriptTemplateInformationModuleFunctionController::class) {
367 // NEW button
368 $urlParameters = [
369 'id' => $this->id,
370 'template' => 'all',
371 'createExtension' => 'new'
372 ];
373 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
374 $newButton = $buttonBar->makeLinkButton()
375 ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
376 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:db_new.php.pagetitle'))
377 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
378 'actions-add',
379 Icon::SIZE_SMALL
380 ));
381 $buttonBar->addButton($newButton);
382 } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class
383 && !empty($this->MOD_MENU['constant_editor_cat'])) {
384 // SAVE button
385 $saveButton = $buttonBar->makeInputButton()
386 ->setName('_savedok')
387 ->setValue('1')
388 ->setForm('TypoScriptTemplateModuleController')
389 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
390 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
391 'actions-document-save',
392 Icon::SIZE_SMALL
393 ))
394 ->setShowLabelText(true);
395 $buttonBar->addButton($saveButton);
396 } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class
397 && !empty(GeneralUtility::_GP('sObj'))
398 ) {
399 // back button in edit mode of object browser. "sObj" is set by ExtendedTemplateService
400 $urlParameters = [
401 'id' => $this->id
402 ];
403 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
404 $backButton = $buttonBar->makeLinkButton()
405 ->setHref((string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters))
406 ->setClasses('typo3-goBack')
407 ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
408 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
409 'actions-view-go-back',
410 Icon::SIZE_SMALL
411 ));
412 $buttonBar->addButton($backButton);
413 }
414 }
415 // Shortcut
416 $shortcutButton = $buttonBar->makeShortcutButton()
417 ->setModuleName('web_ts')
418 ->setGetVariables(['id', 'route']);
419 $buttonBar->addButton($shortcutButton);
420 }
421
422 /**
423 * Wrap title for link in template, called from client classes.
424 *
425 * @param string $title
426 * @param string $onlyKey
427 * @return string
428 */
429 public function linkWrapTemplateTitle($title, $onlyKey = '')
430 {
431 $urlParameters = [
432 'id' => $this->id
433 ];
434 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
435 $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
436 if ($onlyKey) {
437 $title = '<a href="' . htmlspecialchars($aHref . '&e[' . $onlyKey . ']=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController') . '">' . htmlspecialchars($title) . '</a>';
438 } else {
439 $title = '<a href="' . htmlspecialchars($aHref . '&e[constants]=1&e[config]=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController') . '">' . htmlspecialchars($title) . '</a>';
440 }
441 return $title;
442 }
443
444 /**
445 * No template, called from client classes.
446 *
447 * @param int $newStandardTemplate
448 * @return string
449 */
450 public function noTemplate($newStandardTemplate = 0)
451 {
452 $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
453
454 $moduleContent['state'] = InfoboxViewHelper::STATE_INFO;
455
456 // New standard?
457 if ($newStandardTemplate) {
458 $selector = '';
459 $staticsText = '';
460 // Hook to change output, implemented for statictemplates
461 $hookObject = $this->getHookObjectForAction('newStandardTemplateView');
462 if (!empty($hookObject)) {
463 $reference = [
464 'selectorHtml' => &$selector,
465 'staticsText' => &$staticsText
466 ];
467 GeneralUtility::callUserFunction(
468 $hookObject,
469 $reference,
470 $this
471 );
472 $selector = $reference['selectorHtml'];
473 $staticsText = $reference['staticsText'];
474 }
475 // Extension?
476 $moduleContent['staticsText'] = $staticsText;
477 $moduleContent['selector'] = $selector;
478 }
479 // Go to previous Page with Template...
480 $previousPage = $this->templateService->ext_prevPageWithTemplate($this->id, $this->perms_clause);
481 if ($previousPage) {
482 $urlParameters = [
483 'id' => $previousPage['uid']
484 ];
485 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
486 $previousPage['aHref'] = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
487 $moduleContent['previousPage'] = $previousPage;
488 }
489 $view = $this->getFluidTemplateObject('tstemplate', 'NoTemplate');
490 $view->assign('content', $moduleContent);
491 return $view->render();
492 }
493
494 /**
495 * Render template menu, called from client classes.
496 *
497 * @return string
498 */
499 public function templateMenu()
500 {
501 $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
502
503 $all = $this->templateService->ext_getAllTemplates($this->id);
504 if (count($all) > 1) {
505 $this->MOD_MENU['templatesOnPage'] = [];
506 foreach ($all as $d) {
507 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
508 }
509 }
510 $this->MOD_SETTINGS = BackendUtility::getModuleData(
511 $this->MOD_MENU,
512 GeneralUtility::_GP('SET'),
513 'web_ts',
514 '',
515 $this->modMenu_dontValidateList,
516 $this->modMenu_setDefaultList
517 );
518 return BackendUtility::getFuncMenu(
519 $this->id,
520 'SET[templatesOnPage]',
521 $this->MOD_SETTINGS['templatesOnPage'],
522 $this->MOD_MENU['templatesOnPage']
523 );
524 }
525
526 /**
527 * Create template, called from client classes.
528 *
529 * @param int $id
530 * @param int $actTemplateId
531 * @return string
532 */
533 public function createTemplate($id, $actTemplateId = 0)
534 {
535 $recData = [];
536 $tce = GeneralUtility::makeInstance(DataHandler::class);
537
538 if (GeneralUtility::_GP('createExtension')) {
539 $recData['sys_template']['NEW'] = [
540 'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
541 'title' => '+ext'
542 ];
543 $tce->start($recData, []);
544 $tce->process_datamap();
545 } elseif (GeneralUtility::_GP('newWebsite')) {
546 // Hook to handle row data, implemented for statictemplates
547 $hookObject = $this->getHookObjectForAction('newStandardTemplateHandler');
548 if (!empty($hookObject)) {
549 $reference = [
550 'recData' => &$recData,
551 'id' => $id,
552 ];
553 GeneralUtility::callUserFunction(
554 $hookObject,
555 $reference,
556 $this
557 );
558 $recData = $reference['recData'];
559 } else {
560 $recData['sys_template']['NEW'] = [
561 'pid' => $id,
562 'title' => $this->getLanguageService()->getLL('titleNewSite'),
563 'sorting' => 0,
564 'root' => 1,
565 'clear' => 3,
566 'config' => '
567 # Default PAGE object:
568 page = PAGE
569 page.10 = TEXT
570 page.10.value = HELLO WORLD!
571 '
572 ];
573 }
574 $tce->start($recData, []);
575 $tce->process_datamap();
576 $tce->clear_cacheCmd('all');
577 }
578 return $tce->substNEWwithIDs['NEW'];
579 }
580
581 /**
582 * Set page in array
583 * To render list of page tree with templates
584 *
585 * @param array $pArray Multidimensional array of page tree with template records
586 * @param array $rlArr Rootline array
587 * @param array $row Record of sys_template
588 */
589 protected function setInPageArray(&$pArray, $rlArr, $row)
590 {
591 ksort($rlArr);
592 reset($rlArr);
593 if (!$rlArr[0]['uid']) {
594 array_shift($rlArr);
595 }
596 $cEl = current($rlArr);
597 if (empty($pArray[$cEl['uid']])) {
598 $pArray[$cEl['uid']] = $cEl;
599 }
600 array_shift($rlArr);
601 if (!empty($rlArr)) {
602 if (empty($pArray[$cEl['uid']]['_nodes'])) {
603 $pArray[$cEl['uid']]['_nodes'] = [];
604 }
605 $this->setInPageArray($pArray[$cEl['uid']]['_nodes'], $rlArr, $row);
606 } else {
607 $pArray[$cEl['uid']]['_templates'][] = $row;
608 }
609 uasort($pArray, function ($a, $b) {
610 return $a['sorting'] - $b['sorting'];
611 });
612 }
613
614 /**
615 * Returns a new standalone view, shorthand function
616 *
617 * @param string $extensionName
618 * @param string $templateName
619 * @return StandaloneView
620 */
621 protected function getFluidTemplateObject($extensionName, $templateName = 'Main')
622 {
623 $view = GeneralUtility::makeInstance(StandaloneView::class);
624 $view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName($extensionName);
625 $view->getRenderingContext()->setControllerAction($templateName);
626 $view->getRequest()->setControllerExtensionName('tstemplate');
627 return $view;
628 }
629
630 /**
631 * @param QueryBuilder $queryBuilder
632 * @param string $tableName
633 * @param int $workspaceId
634 */
635 protected function applyWorkspaceConstraint(
636 QueryBuilder $queryBuilder,
637 string $tableName,
638 int $workspaceId
639 ) {
640 if (empty($GLOBALS['TCA'][$tableName]['ctrl']['versioningWS'])) {
641 return;
642 }
643
644 $workspaceIds = [0];
645 if ($workspaceId > 0) {
646 $workspaceIds[] = $workspaceId;
647 }
648 $queryBuilder->andWhere(
649 $queryBuilder->expr()->in(
650 't3ver_wsid',
651 $queryBuilder->createNamedParameter($workspaceIds, Connection::PARAM_INT_ARRAY)
652 ),
653 $queryBuilder->expr()->neq(
654 'pid',
655 $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
656 )
657 );
658 }
659
660 /**
661 * @param string $action
662 * @return string
663 */
664 protected function getHookObjectForAction($action)
665 {
666 if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action])) {
667 return $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class][$action];
668 }
669 return null;
670 }
671
672 /**
673 * Initializes the internal MOD_MENU array setting and unsetting items based on various conditions. It also merges in external menu items from the global array TBE_MODULES_EXT (see mergeExternalItems())
674 * Then MOD_SETTINGS array is cleaned up (see \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()) so it contains only valid values. It's also updated with any SET[] values submitted.
675 * Also loads the modTSconfig internal variable.
676 *
677 * @see init(), $MOD_MENU, $MOD_SETTINGS, \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData(), mergeExternalItems()
678 */
679 protected function menuConfig()
680 {
681 // Page / user TSconfig settings and blinding of menu-items
682 $this->modTSconfig['properties'] = BackendUtility::getPagesTSconfig($this->id)['mod.']['web_ts.'] ?? [];
683 $this->MOD_MENU['function'] = $this->mergeExternalItems('web_ts', 'function', $this->MOD_MENU['function']);
684 $blindActions = $this->modTSconfig['properties']['menu.']['function.'] ?? [];
685 foreach ($blindActions as $key => $value) {
686 if (!$value && array_key_exists($key, $this->MOD_MENU['function'])) {
687 unset($this->MOD_MENU['function'][$key]);
688 }
689 }
690 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), 'web_ts', '', $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
691 }
692
693 /**
694 * Merges menu items from global array $TBE_MODULES_EXT
695 *
696 * @param string $modName Module name for which to find value
697 * @param string $menuKey Menu key, eg. 'function' for the function menu.
698 * @param array $menuArr The part of a MOD_MENU array to work on.
699 * @return array Modified array part.
700 * @internal
701 * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction(), menuConfig()
702 */
703 protected function mergeExternalItems($modName, $menuKey, $menuArr)
704 {
705 $mergeArray = $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
706 if (is_array($mergeArray)) {
707 foreach ($mergeArray as $k => $v) {
708 if (((string)$v['ws'] === '' || $this->getBackendUser()->workspace === 0 && GeneralUtility::inList($v['ws'], 'online')) || $this->getBackendUser()->workspace === -1 && GeneralUtility::inList($v['ws'], 'offline') || $this->getBackendUser()->workspace > 0 && GeneralUtility::inList($v['ws'], 'custom')) {
709 $menuArr[$k] = $this->getLanguageService()->sL($v['title']);
710 }
711 }
712 }
713 return $menuArr;
714 }
715
716 /**
717 * Loads $this->extClassConf with the configuration for the CURRENT function of the menu.
718 *
719 * @param string $MM_key The key to MOD_MENU for which to fetch configuration. 'function' is default since it is first and foremost used to get information per "extension object" (I think that is what its called)
720 * @param string $MS_value The value-key to fetch from the config array. If NULL (default) MOD_SETTINGS[$MM_key] will be used. This is useful if you want to force another function than the one defined in MOD_SETTINGS[function]. Call this in init() function of your Script Class: handleExternalFunctionValue('function', $forcedSubModKey)
721 * @see getExternalItemConfig(), init()
722 */
723 protected function handleExternalFunctionValue($MM_key = 'function', $MS_value = null)
724 {
725 if ($MS_value === null) {
726 $MS_value = $this->MOD_SETTINGS[$MM_key];
727 }
728 $this->extClassConf = $this->getExternalItemConfig('web_ts', $MM_key, $MS_value);
729 }
730
731 /**
732 * Returns configuration values from the global variable $TBE_MODULES_EXT for the module given.
733 * For example if the module is named "web_info" and the "function" key ($menuKey) of MOD_SETTINGS is "stat" ($value) then you will have the values of $TBE_MODULES_EXT['webinfo']['MOD_MENU']['function']['stat'] returned.
734 *
735 * @param string $modName Module name
736 * @param string $menuKey Menu key, eg. "function" for the function menu. See $this->MOD_MENU
737 * @param string $value Optionally the value-key to fetch from the array that would otherwise have been returned if this value was not set. Look source...
738 * @return mixed The value from the TBE_MODULES_EXT array.
739 * @see handleExternalFunctionValue()
740 */
741 protected function getExternalItemConfig($modName, $menuKey, $value = '')
742 {
743 if (isset($GLOBALS['TBE_MODULES_EXT'][$modName])) {
744 return (string)$value !== ''
745 ? $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey][$value]
746 : $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
747 }
748 return null;
749 }
750
751 /**
752 * Creates an instance of the class found in $this->extClassConf['name'] in $this->extObj if any (this should hold three keys, "name", "path" and "title" if a "Function menu module" tries to connect...)
753 * This value in extClassConf might be set by an extension (in an ext_tables/ext_localconf file) which thus "connects" to a module.
754 * The array $this->extClassConf is set in handleExternalFunctionValue() based on the value of MOD_SETTINGS[function]
755 * If an instance is created it is initiated with $this passed as value and $this->extClassConf as second argument. Further the $this->MOD_SETTING is cleaned up again after calling the init function.
756 *
757 * @see handleExternalFunctionValue(), \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction(), $extObj
758 */
759 protected function checkExtObj()
760 {
761 if (is_array($this->extClassConf) && $this->extClassConf['name']) {
762 $this->extObj = GeneralUtility::makeInstance($this->extClassConf['name']);
763 $this->extObj->init($this);
764 // Re-write:
765 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), 'web_ts', '', $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
766 }
767 }
768
769 /**
770 * Calls the 'main' function inside the "Function menu module" if present
771 */
772 protected function extObjContent()
773 {
774 if ($this->extObj === null) {
775 $flashMessage = GeneralUtility::makeInstance(
776 FlashMessage::class,
777 $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:no_modules_registered'),
778 $this->getLanguageService()->getLL('title'),
779 FlashMessage::ERROR
780 );
781 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
782 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue $defaultFlashMessageQueue */
783 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
784 $defaultFlashMessageQueue->enqueue($flashMessage);
785 } else {
786 if (is_callable([$this->extObj, 'main'])) {
787 $this->content .= $this->extObj->main();
788 }
789 }
790 }
791
792 /**
793 * Return the content of the 'main' function inside the "Function menu module" if present
794 *
795 * @return string
796 */
797 protected function getExtObjContent()
798 {
799 $savedContent = $this->content;
800 $this->content = '';
801 $this->extObjContent();
802 $newContent = $this->content;
803 $this->content = $savedContent;
804 return $newContent;
805 }
806
807 /**
808 * Returns the Language Service
809 * @return LanguageService
810 */
811 protected function getLanguageService(): LanguageService
812 {
813 return $GLOBALS['LANG'];
814 }
815
816 /**
817 * Returns the Backend User
818 * @return BackendUserAuthentication
819 */
820 protected function getBackendUser(): BackendUserAuthentication
821 {
822 return $GLOBALS['BE_USER'];
823 }
824
825 /**
826 * @return PageRenderer
827 */
828 protected function getPageRenderer(): PageRenderer
829 {
830 return GeneralUtility::makeInstance(PageRenderer::class);
831 }
832 }