‪TYPO3CMS  11.5
FormFlexAjaxController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
28 use TYPO3\CMS\Core\Page\JavaScriptItems;
32 
37 {
44  public function ‪containerAdd(ServerRequestInterface $request): ResponseInterface
45  {
46  $queryParameters = $request->getParsedBody();
47 
48  $vanillaUid = (int)$queryParameters['vanillaUid'];
49  $databaseRowUid = $queryParameters['databaseRowUid'];
50  $command = $queryParameters['command'];
51  $tableName = $queryParameters['tableName'];
52  $fieldName = $queryParameters['fieldName'];
53  $recordTypeValue = $queryParameters['recordTypeValue'];
54  $dataStructureIdentifier = json_encode($queryParameters['dataStructureIdentifier']);
55  $flexFormSheetName = $queryParameters['flexFormSheetName'];
56  $flexFormFieldName = $queryParameters['flexFormFieldName'];
57  $flexFormContainerName = $queryParameters['flexFormContainerName'];
58 
59  // Prepare TCA and data values for a new section container using data providers
60  $processedTca = ‪$GLOBALS['TCA'][$tableName];
61  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
62  $dataStructure = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
63  $processedTca['columns'][$fieldName]['config']['ds'] = $dataStructure;
64  $processedTca['columns'][$fieldName]['config']['dataStructureIdentifier'] = $dataStructureIdentifier;
65  // Get a new unique id for this container.
66  $flexFormContainerIdentifier = ‪StringUtility::getUniqueId();
67  $flexSectionContainerPreparation = [
68  'flexFormSheetName' => $flexFormSheetName,
69  'flexFormFieldName' => $flexFormFieldName,
70  'flexFormContainerName' => $flexFormContainerName,
71  'flexFormContainerIdentifier' => $flexFormContainerIdentifier,
72  ];
73 
74  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
75  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
76  $formDataCompilerInput = [
77  'tableName' => $tableName,
78  'vanillaUid' => (int)$vanillaUid,
79  'command' => $command,
80  'recordTypeValue' => $recordTypeValue,
81  'processedTca' => $processedTca,
82  'flexSectionContainerPreparation' => $flexSectionContainerPreparation,
83  ];
84  // A new container on a new record needs the 'NEW123' uid here, see comment
85  // in DatabaseUniqueUidNewRow for more information on that.
86  // @todo: Resolve, maybe with a redefinition of vanillaUid to transport the information more clean through this var?
87  // @see issue #80100 for a series of changes in this area
88  if ($command === 'new') {
89  $formDataCompilerInput['databaseRow']['uid'] = $databaseRowUid;
90  // This is a hack to handle creation of flex form section containers on new / not-yet-persisted
91  // records that use "sub types" - for example tt_content ctype plugin with plugin list_type (eg. news_pi1):
92  // The container needs to know the list_type to create the proper flex form section container.
93  // We *can* fetch the given sub type from the dataStructureIdentifier when it's type is 'tca'.
94  // This is hacky since we're using 'internal' knowledge of the dataStructureIdentifier here, which
95  // *should* be avoided. But sub types should vanish from TCA at some point anyway (this usage shows
96  // the complexity they introduce quite well), so we live with the solution for now instead of handing
97  // the selected sub type through the system differently.
98  $subtypeValueField = $processedTca['types'][$recordTypeValue]['subtype_value_field'] ?? null;
99  $subtypeValue = explode(',', $queryParameters['dataStructureIdentifier']['dataStructureKey'] ?? '')[0];
100  if ($subtypeValueField
101  && $subtypeValue
102  && ($queryParameters['dataStructureIdentifier']['type'] ?? '') === 'tca'
103  && !in_array($subtypeValue, ['*', 'list', 'default'], true)
104  ) {
105  // Set selected sub type to init flex form container creation for this type & sub type combination
106  $formDataCompilerInput['databaseRow'][$subtypeValueField] = $subtypeValue;
107  }
108  }
109  $formData = $formDataCompiler->compile($formDataCompilerInput);
110 
111  $dataStructure = $formData['processedTca']['columns'][$fieldName]['config']['ds'];
112  $formData['fieldName'] = $fieldName;
113  $formData['flexFormDataStructureArray'] = $dataStructure['sheets'][$flexFormSheetName]['ROOT']['el'][$flexFormFieldName]['children'][$flexFormContainerIdentifier];
114  $formData['flexFormDataStructureIdentifier'] = $dataStructureIdentifier;
115  $formData['flexFormFieldName'] = $flexFormFieldName;
116  $formData['flexFormSheetName'] = $flexFormSheetName;
117  $formData['flexFormContainerName'] = $flexFormContainerName;
118  $formData['flexFormContainerIdentifier'] = $flexFormContainerIdentifier;
119  $formData['flexFormContainerElementCollapsed'] = false;
120 
121  $formData['flexFormFormPrefix'] = '[data][' . $flexFormSheetName . '][lDEF][' . $flexFormFieldName . '][el]';
122 
123  // Set initialized data of that section container from compiler to the array part used
124  // by flexFormElementContainer which prepares parameterArray. Important for initialized
125  // values of group element.
126  if (isset($formData['databaseRow'][$fieldName]
127  ['data'][$flexFormSheetName]
128  ['lDEF'][$flexFormFieldName]
129  ['el'][$flexFormContainerIdentifier][$flexFormContainerName]['el']
130  )
131  && is_array(
132  $formData['databaseRow'][$fieldName]
133  ['data'][$flexFormSheetName]
134  ['lDEF'][$flexFormFieldName]
135  ['el'][$flexFormContainerIdentifier][$flexFormContainerName]['el']
136  )
137  ) {
138  $formData['flexFormRowData'] = $formData['databaseRow'][$fieldName]
139  ['data'][$flexFormSheetName]
140  ['lDEF'][$flexFormFieldName]
141  ['el'][$flexFormContainerIdentifier][$flexFormContainerName]['el'];
142  }
143 
144  $formData['parameterArray']['itemFormElName'] = 'data[' . $tableName . '][' . $formData['databaseRow']['uid'] . '][' . $fieldName . ']';
145 
146  // Client-side behavior for event handlers:
147  $formData['parameterArray']['fieldChangeFunc'] = [];
148  $formData['parameterArray']['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = new ‪UpdateValueOnFieldChange(
149  $tableName,
150  (string)$formData['databaseRow']['uid'],
151  $fieldName,
152  $formData['parameterArray']['itemFormElName']
153  );
154 
155  // @todo: check GroupElement for usage of elementBaseName ... maybe kick that thing?
156 
157  // Feed resulting form data to container structure to render HTML and other result data
158  $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
159  $formData['renderType'] = 'flexFormContainerContainer';
160  $newContainerResult = $nodeFactory->create($formData)->render();
161  $scriptItems = GeneralUtility::makeInstance(JavaScriptItems::class);
162 
163  $jsonResult = [
164  'html' => $newContainerResult['html'],
165  'stylesheetFiles' => [],
166  'scriptItems' => $scriptItems,
167  'scriptCall' => [],
168  ];
169 
170  // @todo deprecate with TYPO3 v12.0
171  foreach ($newContainerResult['additionalJavaScriptPost'] as $singleAdditionalJavaScriptPost) {
172  $jsonResult['scriptCall'][] = $singleAdditionalJavaScriptPost;
173  }
174  foreach ($newContainerResult['stylesheetFiles'] as $stylesheetFile) {
175  $jsonResult['stylesheetFiles'][] = $this->‪getRelativePathToStylesheetFile($stylesheetFile);
176  }
177  if (!empty($newContainerResult['additionalInlineLanguageLabelFiles'])) {
178  $labels = [];
179  foreach ($newContainerResult['additionalInlineLanguageLabelFiles'] as $additionalInlineLanguageLabelFile) {
181  $labels,
182  $this->‪getLabelsFromLocalizationFile($additionalInlineLanguageLabelFile)
183  );
184  }
185  $scriptItems->addGlobalAssignment(['TYPO3' => ['lang' => $labels]]);
186  }
187  $this->‪addRegisteredRequireJsModulesToJavaScriptItems($newContainerResult, $scriptItems);
188  // @todo deprecate modules with arbitrary JavaScript callback function in TYPO3 v12.0
189  $jsonResult['scriptCall'] = $this->‪createExecutableStringRepresentationOfRegisteredRequireJsModules($newContainerResult, true);
190 
191  return new ‪JsonResponse($jsonResult);
192  }
193 }
‪TYPO3\CMS\Backend\Form\Behavior\UpdateValueOnFieldChange
Definition: UpdateValueOnFieldChange.php:27
‪TYPO3\CMS\Backend\Controller\FormFlexAjaxController\containerAdd
‪ResponseInterface containerAdd(ServerRequestInterface $request)
Definition: FormFlexAjaxController.php:44
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Backend\Controller\FormFlexAjaxController
Definition: FormFlexAjaxController.php:37
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\getRelativePathToStylesheetFile
‪string getRelativePathToStylesheetFile(string $stylesheetFile)
Definition: AbstractFormEngineAjaxController.php:106
‪TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools
Definition: FlexFormTools.php:40
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\getLabelsFromLocalizationFile
‪array getLabelsFromLocalizationFile($file)
Definition: AbstractFormEngineAjaxController.php:126
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\addRegisteredRequireJsModulesToJavaScriptItems
‪addRegisteredRequireJsModulesToJavaScriptItems(array $result, JavaScriptItems $items)
Definition: AbstractFormEngineAjaxController.php:91
‪TYPO3\CMS\Backend\Form\NodeFactory
Definition: NodeFactory.php:37
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:128
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\createExecutableStringRepresentationOfRegisteredRequireJsModules
‪array createExecutableStringRepresentationOfRegisteredRequireJsModules(array $result, bool $skipInstructions=false)
Definition: AbstractFormEngineAjaxController.php:48
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController
Definition: AbstractFormEngineAjaxController.php:38
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Form\FormDataCompiler
Definition: FormDataCompiler.php:25
‪TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord
Definition: TcaDatabaseRecord.php:25
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:16