‪TYPO3CMS  10.4
FormInlineAjaxController.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;
34 
39 {
46  public function ‪createAction(ServerRequestInterface $request): ResponseInterface
47  {
48  $ajaxArguments = $request->getParsedBody()['ajax'] ?? $request->getQueryParams()['ajax'];
49  $parentConfig = $this->‪extractSignedParentConfigFromRequest((string)$ajaxArguments['context']);
50 
51  $domObjectId = $ajaxArguments[0];
52  $inlineFirstPid = $this->‪getInlineFirstPidFromDomObjectId($domObjectId);
53  if (!‪MathUtility::canBeInterpretedAsInteger($inlineFirstPid) && strpos((string)$inlineFirstPid, 'NEW') !== 0) {
54  throw new \RuntimeException(
55  'inlineFirstPid should either be an integer or a "NEW..." string',
56  1521220491
57  );
58  }
59  $childChildUid = null;
60  if (isset($ajaxArguments[1]) && ‪MathUtility::canBeInterpretedAsInteger($ajaxArguments[1])) {
61  $childChildUid = (int)$ajaxArguments[1];
62  }
63 
64  // Parse the DOM identifier, add the levels to the structure stack
66  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
67  $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
68  $inlineStackProcessor->injectAjaxConfiguration($parentConfig);
69  $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
70 
71  // Parent, this table embeds the child table
72  $parent = $inlineStackProcessor->getStructureLevel(-1);
73 
74  // Child, a record from this table should be rendered
75  $child = $inlineStackProcessor->getUnstableStructure();
76  if (‪MathUtility::canBeInterpretedAsInteger($child['uid'])) {
77  // If uid comes in, it is the id of the record neighbor record "create after"
78  $childVanillaUid = -1 * abs((int)$child['uid']);
79  } else {
80  // Else inline first Pid is the storage pid of new inline records
81  $childVanillaUid = $inlineFirstPid;
82  }
83 
84  $childTableName = $parentConfig['foreign_table'];
85 
87  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
89  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
90  $formDataCompilerInput = [
91  'command' => 'new',
92  'tableName' => $childTableName,
93  'vanillaUid' => $childVanillaUid,
94  'isInlineChild' => true,
95  'inlineStructure' => $inlineStackProcessor->getStructure(),
96  'inlineFirstPid' => $inlineFirstPid,
97  'inlineParentUid' => $parent['uid'],
98  'inlineParentTableName' => $parent['table'],
99  'inlineParentFieldName' => $parent['field'],
100  'inlineParentConfig' => $parentConfig,
101  'inlineTopMostParentUid' => $inlineTopMostParent['uid'],
102  'inlineTopMostParentTableName' => $inlineTopMostParent['table'],
103  'inlineTopMostParentFieldName' => $inlineTopMostParent['field'],
104  ];
105  if ($childChildUid) {
106  $formDataCompilerInput['inlineChildChildUid'] = $childChildUid;
107  }
108  $childData = $formDataCompiler->compile($formDataCompilerInput);
109 
110  if ($parentConfig['foreign_selector'] && $parentConfig['appearance']['useCombination']) {
111  // We have a foreign_selector. So, we just created a new record on an intermediate table in $childData.
112  // Now, if a valid id is given as second ajax parameter, the intermediate row should be connected to an
113  // existing record of the child-child table specified by the given uid. If there is no such id, user
114  // clicked on "created new" and a new child-child should be created, too.
115  if ($childChildUid) {
116  // Fetch existing child child
117  $childData['databaseRow'][$parentConfig['foreign_selector']] = [
118  $childChildUid,
119  ];
120  $childData['combinationChild'] = $this->‪compileChildChild($childData, $parentConfig, $inlineStackProcessor->getStructure());
121  } else {
123  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
125  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
126  $formDataCompilerInput = [
127  'command' => 'new',
128  'tableName' => $childData['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table'],
129  'vanillaUid' => $inlineFirstPid,
130  'isInlineChild' => true,
131  'isInlineAjaxOpeningContext' => true,
132  'inlineStructure' => $inlineStackProcessor->getStructure(),
133  'inlineFirstPid' => $inlineFirstPid,
134  ];
135  $childData['combinationChild'] = $formDataCompiler->compile($formDataCompilerInput);
136  }
137  }
138 
139  $childData['inlineParentUid'] = $parent['uid'];
140  $childData['renderType'] = 'inlineRecordContainer';
141  $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
142  $childResult = $nodeFactory->create($childData)->render();
143 
144  $jsonArray = [
145  'data' => '',
146  'stylesheetFiles' => [],
147  'scriptCall' => [],
148  'compilerInput' => [
149  'uid' => $childData['databaseRow']['uid'],
150  'childChildUid' => $childChildUid,
151  'parentConfig' => $parentConfig,
152  ],
153  ];
154 
155  $jsonArray = $this->‪mergeChildResultIntoJsonResult($jsonArray, $childResult);
156 
157  return new ‪JsonResponse($jsonArray);
158  }
159 
166  public function ‪detailsAction(ServerRequestInterface $request): ResponseInterface
167  {
168  $ajaxArguments = $request->getParsedBody()['ajax'] ?? $request->getQueryParams()['ajax'];
169 
170  $domObjectId = $ajaxArguments[0] ?? null;
171  $inlineFirstPid = $this->‪getInlineFirstPidFromDomObjectId($domObjectId);
172  $parentConfig = $this->‪extractSignedParentConfigFromRequest((string)$ajaxArguments['context']);
173 
174  // Parse the DOM identifier, add the levels to the structure stack
176  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
177  $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
178  $inlineStackProcessor->injectAjaxConfiguration($parentConfig);
179 
180  // Parent, this table embeds the child table
181  $parent = $inlineStackProcessor->getStructureLevel(-1);
182  $parentFieldName = $parent['field'];
183 
184  // Set flag in config so that only the fields are rendered
185  // @todo: Solve differently / rename / whatever
186  $parentConfig['renderFieldsOnly'] = true;
187 
188  $parentData = [
189  'processedTca' => [
190  'columns' => [
191  $parentFieldName => [
192  'config' => $parentConfig,
193  ],
194  ],
195  ],
196  'uid' => $parent['uid'],
197  'tableName' => $parent['table'],
198  'inlineFirstPid' => $inlineFirstPid,
199  // Hand over given original return url to compile stack. Needed if inline children compile links to
200  // another view (eg. edit metadata in a nested inline situation like news with inline content element image),
201  // so the back link is still the link from the original request. See issue #82525. This is additionally
202  // given down in TcaInline data provider to compiled children data.
203  'returnUrl' => $parentConfig['originalReturnUrl'],
204  ];
205 
206  // Child, a record from this table should be rendered
207  $child = $inlineStackProcessor->getUnstableStructure();
208 
209  $childData = $this->‪compileChild($parentData, $parentFieldName, (int)$child['uid'], $inlineStackProcessor->getStructure());
210 
211  $childData['inlineParentUid'] = (int)$parent['uid'];
212  $childData['renderType'] = 'inlineRecordContainer';
213  $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
214  $childResult = $nodeFactory->create($childData)->render();
215 
216  $jsonArray = [
217  'data' => '',
218  'stylesheetFiles' => [],
219  'scriptCall' => [],
220  ];
221 
222  $jsonArray = $this->‪mergeChildResultIntoJsonResult($jsonArray, $childResult);
223 
224  return new ‪JsonResponse($jsonArray);
225  }
226 
234  public function ‪synchronizeLocalizeAction(ServerRequestInterface $request): ResponseInterface
235  {
236  $ajaxArguments = $request->getParsedBody()['ajax'] ?? $request->getQueryParams()['ajax'];
237  $domObjectId = $ajaxArguments[0] ?? null;
238  $type = $ajaxArguments[1] ?? null;
239  $parentConfig = $this->‪extractSignedParentConfigFromRequest((string)$ajaxArguments['context']);
240 
242  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
243  // Parse the DOM identifier (string), add the levels to the structure stack (array), load the TCA config:
244  $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
245  $inlineStackProcessor->injectAjaxConfiguration($parentConfig);
246  $inlineFirstPid = $this->‪getInlineFirstPidFromDomObjectId($domObjectId);
247 
248  $jsonArray = [
249  'data' => '',
250  'stylesheetFiles' => [],
251  'compilerInput' => [
252  'localize' => [],
253  ],
254  ];
255  if ($type === 'localize' || $type === 'synchronize' || ‪MathUtility::canBeInterpretedAsInteger($type)) {
256  // Parent, this table embeds the child table
257  $parent = $inlineStackProcessor->getStructureLevel(-1);
258  $parentFieldName = $parent['field'];
259 
260  $processedTca = ‪$GLOBALS['TCA'][$parent['table']];
261  $processedTca['columns'][$parentFieldName]['config'] = $parentConfig;
262 
263  $formDataCompilerInputForParent = [
264  'vanillaUid' => (int)$parent['uid'],
265  'command' => 'edit',
266  'tableName' => $parent['table'],
267  'processedTca' => $processedTca,
268  'inlineFirstPid' => $inlineFirstPid,
269  'columnsToProcess' => [
270  $parentFieldName
271  ],
272  // @todo: still needed? NO!
273  'inlineStructure' => $inlineStackProcessor->getStructure(),
274  // Do not compile existing children, we don't need them now
275  'inlineCompileExistingChildren' => false,
276  ];
277  // Full TcaDatabaseRecord is required here to have the list of connected uids $oldItemList
279  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
281  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
282  $parentData = $formDataCompiler->compile($formDataCompilerInputForParent);
283  $parentConfig = $parentData['processedTca']['columns'][$parentFieldName]['config'];
284  $parentLanguageField = $parentData['processedTca']['ctrl']['languageField'];
285  $parentLanguage = $parentData['databaseRow'][$parentLanguageField];
286  $oldItemList = $parentData['databaseRow'][$parentFieldName];
287 
288  // DataHandler cannot handle arrays as field value
289  if (is_array($parentLanguage)) {
290  $parentLanguage = implode(',', $parentLanguage);
291  }
292 
293  $cmd = [];
294  // Localize a single child element from default language of the parent element
296  $cmd[$parent['table']][$parent['uid']]['inlineLocalizeSynchronize'] = [
297  'field' => $parent['field'],
298  'language' => $parentLanguage,
299  'ids' => [$type],
300  ];
301  } else {
302  // Either localize or synchronize all child elements from default language of the parent element
303  $cmd[$parent['table']][$parent['uid']]['inlineLocalizeSynchronize'] = [
304  'field' => $parent['field'],
305  'language' => $parentLanguage,
306  'action' => $type,
307  ];
308  }
309 
311  $tce = GeneralUtility::makeInstance(DataHandler::class);
312  $tce->start([], $cmd);
313  $tce->process_cmdmap();
314 
315  $newItemList = $tce->registerDBList[$parent['table']][$parent['uid']][$parentFieldName];
316 
317  $oldItems = $this->‪getInlineRelatedRecordsUidArray($oldItemList);
318  $newItems = $this->‪getInlineRelatedRecordsUidArray($newItemList);
319 
320  // Render error messages from DataHandler
321  $tce->printLogErrorMessages();
322  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
323  $messages = $flashMessageService->getMessageQueueByIdentifier()->getAllMessagesAndFlush();
324  if (!empty($messages)) {
325  foreach ($messages as $message) {
326  $jsonArray['messages'][] = [
327  'title' => $message->getTitle(),
328  'message' => $message->getMessage(),
329  'severity' => $message->getSeverity()
330  ];
331  if ($message->getSeverity() === ‪AbstractMessage::ERROR) {
332  $jsonArray['hasErrors'] = true;
333  }
334  }
335  }
336 
337  // Set the items that should be removed in the forms view:
338  $removedItems = array_diff($oldItems, $newItems);
339  $jsonArray['compilerInput']['delete'] = $removedItems;
340 
341  $localizedItems = array_diff($newItems, $oldItems);
342  foreach ($localizedItems as $i => $childUid) {
343  $childData = $this->‪compileChild($parentData, $parentFieldName, (int)$childUid, $inlineStackProcessor->getStructure());
344 
345  $childData['inlineParentUid'] = (int)$parent['uid'];
346  $childData['renderType'] = 'inlineRecordContainer';
347  $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
348  $childResult = $nodeFactory->create($childData)->render();
349 
350  $jsonArray = $this->‪mergeChildResultIntoJsonResult($jsonArray, $childResult);
351 
352  // Get the name of the field used as foreign selector (if any):
353  $foreignSelector = isset($parentConfig['foreign_selector']) && $parentConfig['foreign_selector'] ? $parentConfig['foreign_selector'] : false;
354  $selectedValue = $foreignSelector ? GeneralUtility::quoteJSvalue($childData['databaseRow'][$foreignSelector]) : null;
355  if (is_array($selectedValue)) {
356  $selectedValue = $selectedValue[0];
357  }
358 
359  $jsonArray['compilerInput']['localize'][$i] = [
360  'uid' => $childUid,
361  'selectedValue' => $selectedValue,
362  ];
363 
364  // Remove possible virtual records in the form which showed that a child records could be localized:
365  $transOrigPointerFieldName = $childData['processedTca']['ctrl']['transOrigPointerField'];
366  if (isset($childData['databaseRow'][$transOrigPointerFieldName]) && $childData['databaseRow'][$transOrigPointerFieldName]) {
367  $transOrigPointerFieldValue = $childData['databaseRow'][$transOrigPointerFieldName];
368  if (is_array($transOrigPointerFieldValue)) {
369  $transOrigPointerFieldValue = $transOrigPointerFieldValue[0];
370  if (is_array($transOrigPointerFieldValue) && ($transOrigPointerFieldValue['uid'] ?? false)) {
371  // With nested inline containers (eg. fal sys_file_reference), row[l10n_parent][0] is sometimes
372  // a table / row combination again. See tx_styleguide_inline_fal inline_5. If this happens we
373  // pick the uid field from the array ... Basically, we need the uid of the 'default language' record,
374  // since this is used in JS to locate and remove the 'shadowed' container.
375  // @todo: Find out if this is really necessary that sometimes ['databaseRow']['l10n_parent'][0]
376  // is resolved to a direct uid, and sometimes it's a array with items. Could this be harmonized?
377  $transOrigPointerFieldValue = $transOrigPointerFieldValue['uid'];
378  }
379  }
380  $jsonArray['compilerInput']['localize'][$i]['remove'] = $transOrigPointerFieldValue;
381  }
382  }
383  }
384  return new ‪JsonResponse($jsonArray);
385  }
386 
393  public function ‪expandOrCollapseAction(ServerRequestInterface $request): ResponseInterface
394  {
395  $ajaxArguments = $request->getParsedBody()['ajax'] ?? $request->getQueryParams()['ajax'];
396  [$domObjectId, $expand, $collapse] = $ajaxArguments;
397 
399  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
400  // Parse the DOM identifier (string), add the levels to the structure stack (array), don't load TCA config
401  $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
402 
403  $backendUser = $this->‪getBackendUserAuthentication();
404  // The current table - for this table we should add/import records
405  $currentTable = $inlineStackProcessor->getUnstableStructure();
406  $currentTable = $currentTable['table'];
407  // The top parent table - this table embeds the current table
408  $top = $inlineStackProcessor->getStructureLevel(0);
409  $topTable = $top['table'];
410  $topUid = $top['uid'];
411  $inlineView = $this->‪getInlineExpandCollapseStateArray();
412  // Only do some action if the top record and the current record were saved before
414  $expandUids = ‪GeneralUtility::trimExplode(',', $expand);
415  $collapseUids = ‪GeneralUtility::trimExplode(',', $collapse);
416  // Set records to be expanded
417  foreach ($expandUids as $uid) {
418  $inlineView[$topTable][$topUid][$currentTable][] = $uid;
419  }
420  // Set records to be collapsed
421  foreach ($collapseUids as $uid) {
422  $inlineView[$topTable][$topUid][$currentTable] = $this->‪removeFromArray($uid, $inlineView[$topTable][$topUid][$currentTable]);
423  }
424  // Save states back to database
425  if (is_array($inlineView[$topTable][$topUid][$currentTable])) {
426  $inlineView[$topTable][$topUid][$currentTable] = array_unique($inlineView[$topTable][$topUid][$currentTable]);
427  $backendUser->uc['inlineView'] = json_encode($inlineView);
428  $backendUser->writeUC();
429  }
430  }
431  return (new ‪JsonResponse())->setPayload([]);
432  }
433 
446  protected function ‪compileChild(array $parentData, $parentFieldName, $childUid, array $inlineStructure)
447  {
448  $parentConfig = $parentData['processedTca']['columns'][$parentFieldName]['config'];
449 
451  $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
452  $inlineStackProcessor->initializeByGivenStructure($inlineStructure);
453  $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
454 
455  // @todo: do not use stack processor here ...
456  $child = $inlineStackProcessor->getUnstableStructure();
457  $childTableName = $child['table'];
458 
460  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
462  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
463  $formDataCompilerInput = [
464  'command' => 'edit',
465  'tableName' => $childTableName,
466  'vanillaUid' => (int)$childUid,
467  'returnUrl' => $parentData['returnUrl'],
468  'isInlineChild' => true,
469  'inlineStructure' => $inlineStructure,
470  'inlineFirstPid' => $parentData['inlineFirstPid'],
471  'inlineParentConfig' => $parentConfig,
472  'isInlineAjaxOpeningContext' => true,
473 
474  // values of the current parent element
475  // it is always a string either an id or new...
476  'inlineParentUid' => $parentData['databaseRow']['uid'] ?? $parentData['uid'],
477  'inlineParentTableName' => $parentData['tableName'],
478  'inlineParentFieldName' => $parentFieldName,
479 
480  // values of the top most parent element set on first level and not overridden on following levels
481  'inlineTopMostParentUid' => $inlineTopMostParent['uid'],
482  'inlineTopMostParentTableName' => $inlineTopMostParent['table'],
483  'inlineTopMostParentFieldName' => $inlineTopMostParent['field'],
484  ];
485  // For foreign_selector with useCombination $mainChild is the mm record
486  // and $combinationChild is the child-child. For "normal" relations, $mainChild
487  // is just the normal child record and $combinationChild is empty.
488  $mainChild = $formDataCompiler->compile($formDataCompilerInput);
489  if ($parentConfig['foreign_selector'] && $parentConfig['appearance']['useCombination']) {
490  // This kicks in if opening an existing mainChild that has a child-child set
491  $mainChild['combinationChild'] = $this->‪compileChildChild($mainChild, $parentConfig, $inlineStructure);
492  }
493  return $mainChild;
494  }
495 
505  protected function ‪compileChildChild(array $child, array $parentConfig, array $inlineStructure)
506  {
507  // foreign_selector on intermediate is probably type=select, so data provider of this table resolved that to the uid already
508  $childChildUid = $child['databaseRow'][$parentConfig['foreign_selector']][0];
509  // child-child table name is set in child tca "the selector field" foreign_table
510  $childChildTableName = $child['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table'];
512  $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
514  $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
515  $formDataCompilerInput = [
516  'command' => 'edit',
517  'tableName' => $childChildTableName,
518  'vanillaUid' => (int)$childChildUid,
519  'isInlineChild' => true,
520  'isInlineAjaxOpeningContext' => true,
521  // @todo: this is the wrong inline structure, isn't it? Shouldn't contain it the part from child child, too?
522  'inlineStructure' => $inlineStructure,
523  'inlineFirstPid' => $child['inlineFirstPid'],
524  // values of the top most parent element set on first level and not overridden on following levels
525  'inlineTopMostParentUid' => $child['inlineTopMostParentUid'],
526  'inlineTopMostParentTableName' => $child['inlineTopMostParentTableName'],
527  'inlineTopMostParentFieldName' => $child['inlineTopMostParentFieldName'],
528  ];
529  return $formDataCompiler->compile($formDataCompilerInput);
530  }
531 
540  protected function ‪mergeChildResultIntoJsonResult(array $jsonResult, array $childResult)
541  {
542  $jsonResult['data'] .= $childResult['html'];
543  $jsonResult['stylesheetFiles'] = [];
544  foreach ($childResult['stylesheetFiles'] as $stylesheetFile) {
545  $jsonResult['stylesheetFiles'][] = $this->‪getRelativePathToStylesheetFile($stylesheetFile);
546  }
547  if (!empty($childResult['inlineData'])) {
548  $jsonResult['inlineData'] = $childResult['inlineData'];
549  }
550  foreach ($childResult['additionalJavaScriptPost'] as $singleAdditionalJavaScriptPost) {
551  $jsonResult['scriptCall'][] = $singleAdditionalJavaScriptPost;
552  }
553  if (!empty($childResult['additionalInlineLanguageLabelFiles'])) {
554  $labels = [];
555  foreach ($childResult['additionalInlineLanguageLabelFiles'] as $additionalInlineLanguageLabelFile) {
557  $labels,
558  $this->‪getLabelsFromLocalizationFile($additionalInlineLanguageLabelFile)
559  );
560  }
561  $javaScriptCode = [];
562  $javaScriptCode[] = 'if (typeof TYPO3 === \'undefined\' || typeof TYPO3.lang === \'undefined\') {';
563  $javaScriptCode[] = ' TYPO3.lang = {}';
564  $javaScriptCode[] = '}';
565  $javaScriptCode[] = 'var additionalInlineLanguageLabels = ' . json_encode($labels) . ';';
566  $javaScriptCode[] = 'for (var attributeName in additionalInlineLanguageLabels) {';
567  $javaScriptCode[] = ' if (typeof TYPO3.lang[attributeName] === \'undefined\') {';
568  $javaScriptCode[] = ' TYPO3.lang[attributeName] = additionalInlineLanguageLabels[attributeName]';
569  $javaScriptCode[] = ' }';
570  $javaScriptCode[] = '}';
571 
572  $jsonResult['scriptCall'][] = implode(LF, $javaScriptCode);
573  }
574  $jsonResult['requireJsModules'] = $this->‪createExecutableStringRepresentationOfRegisteredRequireJsModules($childResult);
575 
576  return $jsonResult;
577  }
578 
587  protected function ‪getInlineRelatedRecordsUidArray($itemList)
588  {
589  $itemArray = ‪GeneralUtility::trimExplode(',', $itemList, true);
590  // Perform modification of the selected items array:
591  foreach ($itemArray as &$value) {
592  $parts = explode('|', $value, 2);
593  $value = $parts[0];
594  }
595  unset($value);
596  return $itemArray;
597  }
598 
606  protected function ‪getInlineExpandCollapseStateArrayForTableUid($table, $uid)
607  {
608  $inlineView = $this->‪getInlineExpandCollapseStateArray();
609  $result = [];
611  if (!empty($inlineView[$table][$uid])) {
612  $result = $inlineView[$table][$uid];
613  }
614  }
615  return $result;
616  }
617 
624  {
625  $backendUser = $this->‪getBackendUserAuthentication();
626  if (!$this->‪backendUserHasUcInlineView($backendUser)) {
627  return [];
628  }
629 
630  $inlineView = json_decode($backendUser->uc['inlineView'], true);
631  if (!is_array($inlineView)) {
632  $inlineView = [];
633  }
634 
635  return $inlineView;
636  }
637 
646  {
647  return !empty($backendUser->uc['inlineView']);
648  }
649 
658  protected function ‪removeFromArray($needle, $haystack, $strict = false)
659  {
660  $pos = array_search($needle, $haystack, $strict);
661  if ($pos !== false) {
662  unset($haystack[$pos]);
663  }
664  return $haystack;
665  }
666 
673  protected function ‪getErrorMessageForAJAX($message)
674  {
675  return [
676  'data' => $message,
677  'scriptCall' => [
678  'alert("' . $message . '");'
679  ],
680  ];
681  }
682 
689  protected function ‪getInlineFirstPidFromDomObjectId($domObjectId)
690  {
691  // Substitute FlexForm addition and make parsing a bit easier
692  $domObjectId = str_replace('---', ':', $domObjectId);
693  // The starting pattern of an object identifier (e.g. "data-<firstPidValue>-<anything>)
694  $pattern = '/^data-(.+?)-(.+)$/';
695  if (preg_match($pattern, $domObjectId, $match)) {
696  return $match[1];
697  }
698  return null;
699  }
700 
709  protected function ‪extractSignedParentConfigFromRequest(string $contextString): array
710  {
711  if ($contextString === '') {
712  throw new \RuntimeException('Empty context string given', 1489751361);
713  }
714  $context = json_decode($contextString, true);
715  if (empty($context['config'])) {
716  throw new \RuntimeException('Empty context config section given', 1489751362);
717  }
718  if (!hash_equals(GeneralUtility::hmac((string)$context['config'], 'InlineContext'), (string)$context['hmac'])) {
719  throw new \RuntimeException('Hash does not validate', 1489751363);
720  }
721  return json_decode($context['config'], true);
722  }
723 
727  protected function ‪getBackendUserAuthentication()
728  {
729  return ‪$GLOBALS['BE_USER'];
730  }
731 }
‪TYPO3\CMS\Core\DataHandling\DataHandler
Definition: DataHandler.php:84
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\expandOrCollapseAction
‪ResponseInterface expandOrCollapseAction(ServerRequestInterface $request)
Definition: FormInlineAjaxController.php:393
‪TYPO3\CMS\Core\Messaging\AbstractMessage
Definition: AbstractMessage.php:26
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController
Definition: FormInlineAjaxController.php:39
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\compileChildChild
‪array compileChildChild(array $child, array $parentConfig, array $inlineStructure)
Definition: FormInlineAjaxController.php:505
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\backendUserHasUcInlineView
‪bool backendUserHasUcInlineView(BackendUserAuthentication $backendUser)
Definition: FormInlineAjaxController.php:645
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\getErrorMessageForAJAX
‪array getErrorMessageForAJAX($message)
Definition: FormInlineAjaxController.php:673
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\createAction
‪ResponseInterface createAction(ServerRequestInterface $request)
Definition: FormInlineAjaxController.php:46
‪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\FormInlineAjaxController\extractSignedParentConfigFromRequest
‪array extractSignedParentConfigFromRequest(string $contextString)
Definition: FormInlineAjaxController.php:709
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\getInlineExpandCollapseStateArrayForTableUid
‪array getInlineExpandCollapseStateArrayForTableUid($table, $uid)
Definition: FormInlineAjaxController.php:606
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\detailsAction
‪ResponseInterface detailsAction(ServerRequestInterface $request)
Definition: FormInlineAjaxController.php:166
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\createExecutableStringRepresentationOfRegisteredRequireJsModules
‪array createExecutableStringRepresentationOfRegisteredRequireJsModules(array $result)
Definition: AbstractFormEngineAjaxController.php:42
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\synchronizeLocalizeAction
‪ResponseInterface synchronizeLocalizeAction(ServerRequestInterface $request)
Definition: FormInlineAjaxController.php:234
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\getRelativePathToStylesheetFile
‪string getRelativePathToStylesheetFile(string $stylesheetFile)
Definition: AbstractFormEngineAjaxController.php:80
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: FormInlineAjaxController.php:727
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\compileChild
‪array compileChild(array $parentData, $parentFieldName, $childUid, array $inlineStructure)
Definition: FormInlineAjaxController.php:446
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController\getLabelsFromLocalizationFile
‪array getLabelsFromLocalizationFile($file)
Definition: AbstractFormEngineAjaxController.php:99
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\getInlineExpandCollapseStateArray
‪array getInlineExpandCollapseStateArray()
Definition: FormInlineAjaxController.php:623
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Backend\Form\NodeFactory
Definition: NodeFactory.php:37
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\removeFromArray
‪array removeFromArray($needle, $haystack, $strict=false)
Definition: FormInlineAjaxController.php:658
‪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\FormInlineAjaxController\getInlineRelatedRecordsUidArray
‪array getInlineRelatedRecordsUidArray($itemList)
Definition: FormInlineAjaxController.php:587
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\mergeChildResultIntoJsonResult
‪array mergeChildResultIntoJsonResult(array $jsonResult, array $childResult)
Definition: FormInlineAjaxController.php:540
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController
Definition: AbstractFormEngineAjaxController.php:34
‪TYPO3\CMS\Backend\Form\InlineStackProcessor
Definition: InlineStackProcessor.php:30
‪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\Backend\Controller
Definition: AbstractFormEngineAjaxController.php:18
‪TYPO3\CMS\Backend\Controller\FormInlineAjaxController\getInlineFirstPidFromDomObjectId
‪int string null getInlineFirstPidFromDomObjectId($domObjectId)
Definition: FormInlineAjaxController.php:689
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:31