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