[TASK] Use ServerRequestInterface in ContentElement/NewContentElementController
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / ContentElement / NewContentElementController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Controller\ContentElement;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Template\DocumentTemplate;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Backend\View\BackendLayoutView;
25 use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface;
26 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
28 use TYPO3\CMS\Core\Http\HtmlResponse;
29 use TYPO3\CMS\Core\Imaging\Icon;
30 use TYPO3\CMS\Core\Localization\LanguageService;
31 use TYPO3\CMS\Core\Service\DependencyOrderingService;
32 use TYPO3\CMS\Core\Type\Bitmask\Permission;
33 use TYPO3\CMS\Core\Utility\ArrayUtility;
34 use TYPO3\CMS\Core\Utility\GeneralUtility;
35 use TYPO3\CMS\Fluid\View\StandaloneView;
36
37 /**
38 * Script Class for the New Content element wizard
39 */
40 class NewContentElementController
41 {
42 use PublicPropertyDeprecationTrait;
43
44 /**
45 * @var array
46 */
47 protected $deprecatedPublicProperties = [
48 'id' => 'Using $id of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
49 'sys_language' => 'Using $sys_language of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
50 'R_URI' => 'Using $R_URI of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
51 'colPos' => 'Using $colPos of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
52 'uid_pid' => 'Using $uid_pid of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
53 'modTSconfig' => 'Using $modTSconfig of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
54 'doc' => 'Using $doc of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
55 'content' => 'Using $content of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
56 'access' => 'Using $access of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
57 'config' => 'Using $config of NewContentElementController from the outside is discouraged as this variable is used for internal storage.',
58 ];
59
60 /**
61 * Page id
62 *
63 * @var int
64 */
65 protected $id;
66
67 /**
68 * Sys language
69 *
70 * @var int
71 */
72 protected $sys_language = 0;
73
74 /**
75 * Return URL.
76 *
77 * @var string
78 */
79 protected $R_URI = '';
80
81 /**
82 * If set, the content is destined for a specific column.
83 *
84 * @var int|null
85 */
86 protected $colPos;
87
88 /**
89 * @var int
90 */
91 protected $uid_pid;
92
93 /**
94 * Module TSconfig.
95 *
96 * @var array
97 */
98 protected $modTSconfig = [];
99
100 /**
101 * Internal backend template object
102 *
103 * @var DocumentTemplate
104 */
105 protected $doc;
106
107 /**
108 * Used to accumulate the content of the module.
109 *
110 * @var string
111 */
112 protected $content;
113
114 /**
115 * Access boolean.
116 *
117 * @var bool
118 */
119 protected $access;
120
121 /**
122 * config of the wizard
123 *
124 * @var array
125 */
126 protected $config;
127
128 /**
129 * @var array
130 */
131 protected $pageInfo;
132
133 /**
134 * @var string
135 */
136 protected $onClickEvent;
137
138 /**
139 * @var array
140 */
141 protected $MCONF;
142
143 /**
144 * @var StandaloneView
145 */
146 protected $view;
147
148 /**
149 * @var StandaloneView
150 */
151 protected $menuItemView;
152
153 /**
154 * ModuleTemplate object
155 *
156 * @var ModuleTemplate
157 */
158 protected $moduleTemplate;
159
160 /**
161 * Constructor
162 */
163 public function __construct()
164 {
165 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
166 $GLOBALS['SOBE'] = $this;
167 $this->view = $this->getFluidTemplateObject();
168 $this->menuItemView = $this->getFluidTemplateObject('MenuItem.html');
169
170 // @deprecated since v9, will be obsolete in v10 with removal of init()
171 $request = $GLOBALS['TYPO3_REQUEST'];
172 // @deprecated since v9, will be moved out of __construct() in v10
173 $this->init($request);
174 }
175
176 /**
177 * Constructor, initializing internal variables.
178 *
179 * @param ServerRequestInterface|null $request
180 */
181 public function init(ServerRequestInterface $request = null)
182 {
183 if ($request === null) {
184 // Method signature in v10: protected function init(ServerRequestInterface $request)
185 trigger_error('Method init() will be set to protected in v10. Do not call from other extension', E_USER_DEPRECATED);
186 $request = $GLOBALS['TYPO3_REQUEST'];
187 }
188
189 $lang = $this->getLanguageService();
190 $lang->includeLLFile('EXT:lang/Resources/Private/Language/locallang_misc.xlf');
191 $LOCAL_LANG_orig = $GLOBALS['LOCAL_LANG'];
192 $lang->includeLLFile('EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf');
193 ArrayUtility::mergeRecursiveWithOverrule($LOCAL_LANG_orig, $GLOBALS['LOCAL_LANG']);
194 $GLOBALS['LOCAL_LANG'] = $LOCAL_LANG_orig;
195
196 $parsedBody = $request->getParsedBody();
197 $queryParams = $request->getQueryParams();
198
199 // Setting internal vars:
200 $this->id = (int)($parsedBody['id'] ?? $queryParams['id'] ?? 0);
201 $this->sys_language = (int)($parsedBody['sys_language_uid'] ?? $queryParams['sys_language_uid'] ?? 0);
202 $this->R_URI = GeneralUtility::sanitizeLocalUrl($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? '');
203 $colPos = $parsedBody['colPos'] ?? $queryParams['colPos'] ?? null;
204 $this->colPos = $colPos === null ? null : (int)$colPos;
205 $this->uid_pid = (int)($parsedBody['uid_pid'] ?? $queryParams['uid_pid'] ?? 0);
206 $this->MCONF['name'] = 'xMOD_db_new_content_el';
207 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.wizards.newContentElement');
208 $config = BackendUtility::getPagesTSconfig($this->id);
209 $this->config = $config['mod.']['wizards.']['newContentElement.'];
210 // Starting the document template object:
211 // We keep this here in case somebody relies on it in a hook or alike
212 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
213 // Setting up the context sensitive menu:
214 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
215 // Getting the current page and receiving access information (used in main())
216 $perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
217 $this->pageInfo = BackendUtility::readPageAccess($this->id, $perms_clause);
218 $this->access = is_array($this->pageInfo);
219 }
220
221 /**
222 * Injects the request object for the current request or subrequest
223 * As this controller goes only through the main() method, it is rather simple for now
224 *
225 * @param ServerRequestInterface $request the current request
226 * @return ResponseInterface the response with the content
227 */
228 public function mainAction(ServerRequestInterface $request): ResponseInterface
229 {
230 $this->prepareContent('window');
231 $this->moduleTemplate->setContent($this->content);
232 return new HtmlResponse($this->moduleTemplate->renderContent());
233 }
234
235 /**
236 * Injects the request object for the current request or subrequest
237 * As this controller goes only through the main() method, it is rather simple for now
238 *
239 * @param ServerRequestInterface $request the current request
240 * @return ResponseInterface the response with the content
241 */
242 public function wizardAction(ServerRequestInterface $request): ResponseInterface
243 {
244 $this->prepareContent('list_frame');
245 return new HtmlResponse($this->content);
246 }
247
248 /**
249 * Creating the module output.
250 *
251 * @deprecated since TYPO3 v9, will be removed in TYPO3v10 without substitute
252 */
253 public function main()
254 {
255 trigger_error('Method main() will be replaced by protected method prepareContent() in v10. Do not call from other extension', E_USER_DEPRECATED);
256 $this->prepareContent('window');
257 }
258
259 /**
260 * Returns the array of elements in the wizard display.
261 * For the plugin section there is support for adding elements there from a global variable.
262 *
263 * @return array
264 */
265 public function wizardArray()
266 {
267 trigger_error('Method wizardArray() will be replaced by protected method getWizards() in v10. Do not call from other extension', E_USER_DEPRECATED);
268 return $this->getWizards();
269 }
270
271 /**
272 * @param mixed $wizardElements
273 * @return array
274 */
275 public function wizard_appendWizards($wizardElements)
276 {
277 trigger_error('Method wizard_appendWizards() will be replaced by protected method getAppendWizards() in v10. Do not call from other extension', E_USER_DEPRECATED);
278 return $this->getAppendWizards($wizardElements);
279 }
280
281 /**
282 * @param string $groupKey Not used
283 * @param string $itemKey Not used
284 * @param array $itemConf
285 * @return array
286 */
287 public function wizard_getItem($groupKey, $itemKey, $itemConf)
288 {
289 trigger_error('Method wizard_getItem() will be replaced by protected method getWizardItem() in v10. Do not call from other extension', E_USER_DEPRECATED);
290 return $this->getWizardItem($groupKey, $itemKey, $itemConf);
291 }
292
293 /**
294 * @param string $groupKey Not used
295 * @param array $wizardGroup
296 * @return array
297 */
298 public function wizard_getGroupHeader($groupKey, $wizardGroup)
299 {
300 trigger_error('Method wizard_getGroupHeader() will be replaced by protected method getWizardGroupHeader() in v10. Do not call from other extension', E_USER_DEPRECATED);
301 return $this->getWizardGroupHeader($wizardGroup);
302 }
303
304 /**
305 * Checks the array for elements which might contain unallowed default values and will unset them!
306 * Looks for the "tt_content_defValues" key in each element and if found it will traverse that array as fieldname /
307 * value pairs and check.
308 * The values will be added to the "params" key of the array (which should probably be unset or empty by default).
309 *
310 * @param array $wizardItems Wizard items, passed by reference
311 */
312 public function removeInvalidElements(&$wizardItems)
313 {
314 trigger_error('Method removeInvalidElements() will be replaced by protected method removeInvalidWizardItems() in v10. Do not call from other extension', E_USER_DEPRECATED);
315 $this->removeInvalidWizardItems($wizardItems);
316 }
317
318 /**
319 * Creating the module output.
320 *
321 * @param string $clientContext JavaScript client context to be used
322 * + 'window', legacy if rendered in current document
323 * + 'list_frame', in case rendered in global modal
324 *
325 * @throws \UnexpectedValueException
326 */
327 protected function prepareContent(string $clientContext): void
328 {
329 $hasAccess = true;
330 if ($this->id && $this->access) {
331
332 // Init position map object:
333 $posMap = GeneralUtility::makeInstance(
334 ContentCreationPagePositionMap::class,
335 null,
336 $clientContext
337 );
338 $posMap->cur_sys_language = $this->sys_language;
339 // If a column is pre-set:
340 if (isset($this->colPos)) {
341 if ($this->uid_pid < 0) {
342 $row = [];
343 $row['uid'] = abs($this->uid_pid);
344 } else {
345 $row = '';
346 }
347 $this->onClickEvent = $posMap->onClickInsertRecord(
348 $row,
349 $this->colPos,
350 '',
351 $this->uid_pid,
352 $this->sys_language
353 );
354 } else {
355 $this->onClickEvent = '';
356 }
357 // ***************************
358 // Creating content
359 // ***************************
360 // Wizard
361 $wizardItems = $this->getWizards();
362 // Wrapper for wizards
363 // Hook for manipulating wizardItems, wrapper, onClickEvent etc.
364 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'] ?? [] as $className) {
365 $hookObject = GeneralUtility::makeInstance($className);
366 if (!$hookObject instanceof NewContentElementWizardHookInterface) {
367 throw new \UnexpectedValueException(
368 $className . ' must implement interface ' . NewContentElementWizardHookInterface::class,
369 1227834741
370 );
371 }
372 $hookObject->manipulateWizardItems($wizardItems, $this);
373 }
374
375 // Traverse items for the wizard.
376 // An item is either a header or an item rendered with a radio button and title/description and icon:
377 $cc = ($key = 0);
378 $menuItems = [];
379
380 $this->view->assign('onClickEvent', $this->onClickEvent);
381
382 foreach ($wizardItems as $wizardKey => $wInfo) {
383 $wizardOnClick = '';
384 if ($wInfo['header']) {
385 $menuItems[] = [
386 'label' => $wInfo['header'] ?: '-',
387 'content' => ''
388 ];
389 $key = count($menuItems) - 1;
390 } else {
391 if (!$this->onClickEvent) {
392 // Radio button:
393 $wizardOnClick = 'document.editForm.defValues.value=unescape(' . GeneralUtility::quoteJSvalue(rawurlencode($wInfo['params'])) . '); window.location.hash=\'#sel2\';';
394 // Onclick action for icon/title:
395 $aOnClick = 'document.getElementsByName(\'tempB\')[' . $cc . '].checked=1;' . $wizardOnClick . 'return false;';
396 } else {
397 $aOnClick = "document.editForm.defValues.value=unescape('" . rawurlencode($wInfo['params']) . "');goToalt_doc();";
398 }
399
400 $icon = $this->moduleTemplate->getIconFactory()->getIcon($wInfo['iconIdentifier'])->render();
401
402 $this->menuItemView->assignMultiple([
403 'onClickEvent' => $this->onClickEvent,
404 'aOnClick' => $aOnClick,
405 'wizardInformation' => $wInfo,
406 'icon' => $icon,
407 'wizardOnClick' => $wizardOnClick,
408 'wizardKey' => $wizardKey
409 ]);
410 $menuItems[$key]['content'] .= $this->menuItemView->render();
411 $cc++;
412 }
413 }
414
415 $this->view->assign('renderedTabs', $this->moduleTemplate->getDynamicTabMenu(
416 $menuItems,
417 'new-content-element-wizard'
418 ));
419
420 // If the user must also select a column:
421 if (!$this->onClickEvent) {
422
423 // Load SHARED page-TSconfig settings and retrieve column list from there, if applicable:
424 $colPosArray = GeneralUtility::callUserFunction(
425 BackendLayoutView::class . '->getColPosListItemsParsed',
426 $this->id,
427 $this
428 );
429 $colPosIds = array_column($colPosArray, 1);
430 // Removing duplicates, if any
431 $colPosList = implode(',', array_unique(array_map('intval', $colPosIds)));
432 // Finally, add the content of the column selector to the content:
433 $this->view->assign('posMap', $posMap->printContentElementColumns($this->id, 0, $colPosList, 1, $this->R_URI));
434 }
435 } else {
436 // In case of no access:
437 $hasAccess = false;
438 }
439 $this->view->assign('hasAccess', $hasAccess);
440
441 $this->content = $this->view->render();
442 // Setting up the buttons and markers for docheader
443 $this->getButtons();
444 }
445
446 /**
447 * Create the panel of buttons for submitting the form or otherwise perform operations.
448 */
449 protected function getButtons()
450 {
451 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
452 if ($this->R_URI) {
453 $backButton = $buttonBar->makeLinkButton()
454 ->setHref($this->R_URI)
455 ->setTitle($this->getLanguageService()->getLL('goBack'))
456 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
457 'actions-view-go-back',
458 Icon::SIZE_SMALL
459 ));
460 $buttonBar->addButton($backButton);
461 }
462 $cshButton = $buttonBar->makeHelpButton()->setModuleName('xMOD_csh_corebe')->setFieldName('new_ce');
463 $buttonBar->addButton($cshButton);
464 }
465
466 /**
467 * Returns the array of elements in the wizard display.
468 * For the plugin section there is support for adding elements there from a global variable.
469 *
470 * @return array
471 */
472 protected function getWizards(): array
473 {
474 $wizardItems = [];
475 if (is_array($this->config)) {
476 $wizards = $this->config['wizardItems.'] ?? [];
477 $appendWizards = $this->getAppendWizards($wizards['elements.'] ?? []);
478 if (is_array($wizards)) {
479 foreach ($wizards as $groupKey => $wizardGroup) {
480 $this->prepareDependencyOrdering($wizards[$groupKey], 'before');
481 $this->prepareDependencyOrdering($wizards[$groupKey], 'after');
482 }
483 $wizards = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($wizards);
484
485 foreach ($wizards as $groupKey => $wizardGroup) {
486 $groupKey = rtrim($groupKey, '.');
487 $showItems = GeneralUtility::trimExplode(',', $wizardGroup['show'], true);
488 $showAll = in_array('*', $showItems, true);
489 $groupItems = [];
490 if (is_array($appendWizards[$groupKey . '.']['elements.'])) {
491 $wizardElements = array_merge((array)$wizardGroup['elements.'], $appendWizards[$groupKey . '.']['elements.']);
492 } else {
493 $wizardElements = $wizardGroup['elements.'];
494 }
495 if (is_array($wizardElements)) {
496 foreach ($wizardElements as $itemKey => $itemConf) {
497 $itemKey = rtrim($itemKey, '.');
498 if ($showAll || in_array($itemKey, $showItems)) {
499 $tmpItem = $this->getWizardItem($groupKey, $itemKey, $itemConf);
500 if ($tmpItem) {
501 $groupItems[$groupKey . '_' . $itemKey] = $tmpItem;
502 }
503 }
504 }
505 }
506 if (!empty($groupItems)) {
507 $wizardItems[$groupKey] = $this->getWizardGroupHeader($wizardGroup);
508 $wizardItems = array_merge($wizardItems, $groupItems);
509 }
510 }
511 }
512 }
513 // Remove elements where preset values are not allowed:
514 $this->removeInvalidWizardItems($wizardItems);
515 return $wizardItems;
516 }
517
518 /**
519 * @param array $wizardElements
520 * @return array
521 */
522 protected function getAppendWizards(array $wizardElements): array
523 {
524 if (!is_array($wizardElements)) {
525 $wizardElements = [];
526 }
527 if (is_array($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'])) {
528 foreach ($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'] as $class => $path) {
529 if (!class_exists($class) && file_exists($path)) {
530 require_once $path;
531 }
532 $modObj = GeneralUtility::makeInstance($class);
533 if (method_exists($modObj, 'proc')) {
534 $wizardElements = $modObj->proc($wizardElements);
535 }
536 }
537 }
538 $returnElements = [];
539 foreach ($wizardElements as $key => $wizardItem) {
540 preg_match('/^[a-zA-Z0-9]+_/', $key, $group);
541 $wizardGroup = $group[0] ? substr($group[0], 0, -1) . '.' : $key;
542 $returnElements[$wizardGroup]['elements.'][substr($key, strlen($wizardGroup)) . '.'] = $wizardItem;
543 }
544 return $returnElements;
545 }
546
547 /**
548 * @param string $groupKey Not used
549 * @param string $itemKey Not used
550 * @param array $itemConf
551 * @return array
552 */
553 protected function getWizardItem(string $groupKey, string $itemKey, array $itemConf): array
554 {
555 $itemConf['title'] = $this->getLanguageService()->sL($itemConf['title']);
556 $itemConf['description'] = $this->getLanguageService()->sL($itemConf['description']);
557 $itemConf['tt_content_defValues'] = $itemConf['tt_content_defValues.'];
558 unset($itemConf['tt_content_defValues.']);
559 return $itemConf;
560 }
561
562 /**
563 * @param array $wizardGroup
564 * @return array
565 */
566 protected function getWizardGroupHeader(array $wizardGroup): array
567 {
568 return [
569 'header' => $this->getLanguageService()->sL($wizardGroup['header'])
570 ];
571 }
572
573 /**
574 * Checks the array for elements which might contain unallowed default values and will unset them!
575 * Looks for the "tt_content_defValues" key in each element and if found it will traverse that array as fieldname /
576 * value pairs and check.
577 * The values will be added to the "params" key of the array (which should probably be unset or empty by default).
578 *
579 * @param array $wizardItems Wizard items, passed by reference
580 */
581 protected function removeInvalidWizardItems(array &$wizardItems): void
582 {
583 // Get TCEFORM from TSconfig of current page
584 $row = ['pid' => $this->id];
585 $TCEFORM_TSconfig = BackendUtility::getTCEFORM_TSconfig('tt_content', $row);
586 $headersUsed = [];
587 // Traverse wizard items:
588 foreach ($wizardItems as $key => $cfg) {
589 // Exploding parameter string, if any (old style)
590 if ($wizardItems[$key]['params']) {
591 // Explode GET vars recursively
592 $tempGetVars = GeneralUtility::explodeUrl2Array($wizardItems[$key]['params'], true);
593 // If tt_content values are set, merge them into the tt_content_defValues array,
594 // unset them from $tempGetVars and re-implode $tempGetVars into the param string
595 // (in case remaining parameters are around).
596 if (is_array($tempGetVars['defVals']['tt_content'])) {
597 $wizardItems[$key]['tt_content_defValues'] = array_merge(
598 is_array($wizardItems[$key]['tt_content_defValues']) ? $wizardItems[$key]['tt_content_defValues'] : [],
599 $tempGetVars['defVals']['tt_content']
600 );
601 unset($tempGetVars['defVals']['tt_content']);
602 $wizardItems[$key]['params'] = GeneralUtility::implodeArrayForUrl('', $tempGetVars);
603 }
604 }
605 // If tt_content_defValues are defined...:
606 if (is_array($wizardItems[$key]['tt_content_defValues'])) {
607 $backendUser = $this->getBackendUser();
608 // Traverse field values:
609 foreach ($wizardItems[$key]['tt_content_defValues'] as $fN => $fV) {
610 if (is_array($GLOBALS['TCA']['tt_content']['columns'][$fN])) {
611 // Get information about if the field value is OK:
612 $config = &$GLOBALS['TCA']['tt_content']['columns'][$fN]['config'];
613 $authModeDeny = $config['type'] === 'select' && $config['authMode']
614 && !$backendUser->checkAuthMode('tt_content', $fN, $fV, $config['authMode']);
615 // explode TSconfig keys only as needed
616 if (!isset($removeItems[$fN]) && isset($TCEFORM_TSconfig[$fN]['removeItems']) && $TCEFORM_TSconfig[$fN]['removeItems'] !== '') {
617 $removeItems[$fN] = array_flip(GeneralUtility::trimExplode(
618 ',',
619 $TCEFORM_TSconfig[$fN]['removeItems'],
620 true
621 ));
622 }
623 if (!isset($keepItems[$fN]) && isset($TCEFORM_TSconfig[$fN]['keepItems']) && $TCEFORM_TSconfig[$fN]['keepItems'] !== '') {
624 $keepItems[$fN] = array_flip(GeneralUtility::trimExplode(
625 ',',
626 $TCEFORM_TSconfig[$fN]['keepItems'],
627 true
628 ));
629 }
630 $isNotInKeepItems = !empty($keepItems[$fN]) && !isset($keepItems[$fN][$fV]);
631 if ($authModeDeny || ($fN === 'CType' && (isset($removeItems[$fN][$fV]) || $isNotInKeepItems))) {
632 // Remove element all together:
633 unset($wizardItems[$key]);
634 break;
635 }
636 // Add the parameter:
637 $wizardItems[$key]['params'] .= '&defVals[tt_content][' . $fN . ']=' . rawurlencode($this->getLanguageService()->sL($fV));
638 $tmp = explode('_', $key);
639 $headersUsed[$tmp[0]] = $tmp[0];
640 }
641 }
642 }
643 }
644 // remove headers without elements
645 foreach ($wizardItems as $key => $cfg) {
646 $tmp = explode('_', $key);
647 if ($tmp[0] && !$tmp[1] && !in_array($tmp[0], $headersUsed)) {
648 unset($wizardItems[$key]);
649 }
650 }
651 }
652
653 /**
654 * Prepare a wizard tab configuration for sorting.
655 *
656 * @param array $wizardGroup TypoScript wizard tab configuration
657 * @param string $key Which array key should be prepared
658 */
659 protected function prepareDependencyOrdering(&$wizardGroup, $key)
660 {
661 if (isset($wizardGroup[$key])) {
662 $wizardGroup[$key] = GeneralUtility::trimExplode(',', $wizardGroup[$key]);
663 $wizardGroup[$key] = array_map(function ($s) {
664 return $s . '.';
665 }, $wizardGroup[$key]);
666 }
667 }
668
669 /**
670 * @return LanguageService
671 */
672 protected function getLanguageService(): LanguageService
673 {
674 return $GLOBALS['LANG'];
675 }
676
677 /**
678 * @return BackendUserAuthentication
679 */
680 protected function getBackendUser(): BackendUserAuthentication
681 {
682 return $GLOBALS['BE_USER'];
683 }
684
685 /**
686 * @param string $filename
687 * @return StandaloneView
688 */
689 protected function getFluidTemplateObject(string $filename = 'Main.html'): StandaloneView
690 {
691 /** @var StandaloneView $view */
692 $view = GeneralUtility::makeInstance(StandaloneView::class);
693 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/NewContentElement/' . $filename));
694 $view->getRequest()->setControllerExtensionName('Backend');
695 return $view;
696 }
697 }