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