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