2 namespace TYPO3\CMS\Backend\Controller;
45 $domObjectId = $ajaxArguments[0];
47 $childChildUid = null;
49 $childChildUid = (int)$ajaxArguments[1];
55 $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
56 $inlineStackProcessor->injectAjaxConfiguration($ajaxArguments[
'context']);
59 $parent = $inlineStackProcessor->getStructureLevel(-1);
60 $parentFieldName = $parent[
'field'];
64 $vanillaUid = (int)$parent[
'uid'];
67 'uid' => (int)$parent[
'uid'],
72 $vanillaUid = (int)$inlineFirstPid;
74 $formDataCompilerInputForParent = [
75 'vanillaUid' => $vanillaUid,
76 'command' => $command,
77 'tableName' => $parent[
'table'],
78 'databaseRow' => $databaseRow,
79 'inlineFirstPid' => $inlineFirstPid,
80 'columnsToProcess' => [
84 'inlineResolveExistingChildren' =>
false,
90 $parentData = $formDataCompiler->compile($formDataCompilerInputForParent);
91 $parentConfig = $parentData[
'processedTca'][
'columns'][$parentFieldName][
'config'];
94 $child = $inlineStackProcessor->getUnstableStructure();
97 $childVanillaUid = -1 * abs((
int)$child[
'uid']);
100 $childVanillaUid = (int)$inlineFirstPid;
103 if ($parentConfig[
'type'] ===
'flex') {
106 $childTableName = $parentConfig[
'foreign_table'];
112 $formDataCompilerInput = [
114 'tableName' => $childTableName,
115 'vanillaUid' => $childVanillaUid,
116 'isInlineChild' =>
true,
117 'inlineStructure' => $inlineStackProcessor->getStructure(),
118 'inlineFirstPid' => $inlineFirstPid,
119 'inlineParentUid' => $parent[
'uid'],
120 'inlineParentTableName' => $parent[
'table'],
121 'inlineParentFieldName' => $parent[
'field'],
122 'inlineParentConfig' => $parentConfig,
124 if ($childChildUid) {
125 $formDataCompilerInput[
'inlineChildChildUid'] = $childChildUid;
127 $childData = $formDataCompiler->compile($formDataCompilerInput);
144 if ($parentConfig[
'foreign_selector'] && $parentConfig[
'appearance'][
'useCombination']) {
149 if ($childChildUid) {
151 $childData[
'databaseRow'][$parentConfig[
'foreign_selector']] = [
160 $formDataCompilerInput = [
162 'tableName' => $childData[
'processedTca'][
'columns'][$parentConfig[
'foreign_selector']][
'config'][
'foreign_table'],
163 'vanillaUid' => (int)$inlineFirstPid,
164 'inlineFirstPid' => (
int)$inlineFirstPid,
166 $childData[
'combinationChild'] = $formDataCompiler->compile($formDataCompilerInput);
170 $childData[
'inlineParentUid'] = (int)$parent[
'uid'];
171 $childData[
'renderType'] =
'inlineRecordContainer';
173 $childResult = $nodeFactory->create($childData)->render();
177 'stylesheetFiles' => [],
182 $objectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($inlineFirstPid);
183 $objectPrefix = $objectName .
'-' . $child[
'table'];
184 $objectId = $objectPrefix .
'-' . $childData[
'databaseRow'][
'uid'];
185 $expandSingle = $parentConfig[
'appearance'][
'expandSingle'];
186 if (!$child[
'uid']) {
194 if ($parentConfig[
'appearance'][
'useSortable']) {
195 $inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($inlineFirstPid);
198 if (!$parentConfig[
'appearance'][
'collapseAll'] && $expandSingle) {
204 $response->
getBody()->write(json_encode($jsonArray));
220 $domObjectId = $ajaxArguments[0];
226 $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
227 $inlineStackProcessor->injectAjaxConfiguration($ajaxArguments[
'context']);
230 $parent = $inlineStackProcessor->getStructureLevel(-1);
231 $parentFieldName = $parent[
'field'];
233 $formDataCompilerInputForParent = [
234 'vanillaUid' => (int)$parent[
'uid'],
236 'tableName' => $parent[
'table'],
239 'uid' => (
int)$parent[
'uid'],
241 'inlineFirstPid' => $inlineFirstPid,
242 'columnsToProcess' => [
246 'inlineStructure' => $inlineStackProcessor->getStructure(),
248 'inlineResolveExistingChildren' =>
false,
254 $parentData = $formDataCompiler->compile($formDataCompilerInputForParent);
257 $parentData[
'processedTca'][
'columns'][$parentFieldName][
'config'][
'renderFieldsOnly'] =
true;
258 $parentConfig = $parentData[
'processedTca'][
'columns'][$parentFieldName][
'config'];
261 $child = $inlineStackProcessor->getUnstableStructure();
263 $childData = $this->compileChild($parentData, $parentFieldName, (
int)$child[
'uid'], $inlineStackProcessor->getStructure());
265 $childData[
'inlineParentUid'] = (int)$parent[
'uid'];
266 $childData[
'renderType'] =
'inlineRecordContainer';
268 $childResult = $nodeFactory->create($childData)->render();
272 'stylesheetFiles' => [],
277 $objectPrefix = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($inlineFirstPid) .
'-' . $child[
'table'];
278 $objectId = $objectPrefix .
'-' . (int)$child[
'uid'];
279 $expandSingle = $parentConfig[
'appearance'][
'expandSingle'];
281 if ($parentConfig[
'foreign_unique']) {
284 $jsonArray = $this->mergeChildResultIntoJsonResult($jsonArray, $childResult);
285 if ($parentConfig['appearance
']['useSortable
']) {
286 $inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($inlineFirstPid);
287 $jsonArray['scriptCall
'][] = 'inline.createDragAndDropSorting(
' . GeneralUtility::quoteJSvalue($inlineObjectName . '_records
') . ');
';
289 if (!$parentConfig['appearance
']['collapseAll
'] && $expandSingle) {
290 $jsonArray['scriptCall
'][] = 'inline.collapseAllRecords(
' . GeneralUtility::quoteJSvalue($objectId) . ',
' . GeneralUtility::quoteJSvalue($objectPrefix) . ',\
'' . (
int)$child[
'uid'] .
'\');
';
293 $response->getBody()->write(json_encode($jsonArray));
306 public function synchronizeLocalizeAction(ServerRequestInterface $request, ResponseInterface $response)
308 $ajaxArguments = isset($request->getParsedBody()['ajax
']) ? $request->getParsedBody()['ajax
'] : $request->getQueryParams()['ajax
'];
309 $domObjectId = $ajaxArguments[0];
310 $type = $ajaxArguments[1];
313 $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
314 // Parse the DOM identifier (string), add the levels to the structure stack (array), load the TCA config:
315 $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
316 $inlineStackProcessor->injectAjaxConfiguration($ajaxArguments['context
']);
317 $inlineFirstPid = $this->getInlineFirstPidFromDomObjectId($domObjectId);
320 if ($type === 'localize
' || $type === 'synchronize
' || MathUtility::canBeInterpretedAsInteger($type)) {
321 // Parent, this table embeds the child table
322 $parent = $inlineStackProcessor->getStructureLevel(-1);
323 $parentFieldName = $parent['field
'];
325 // Child, a record from this table should be rendered
326 $child = $inlineStackProcessor->getUnstableStructure();
328 $formDataCompilerInputForParent = [
329 'vanillaUid
' => (int)$parent['uid
'],
331 'tableName
' => $parent['table
'],
333 // TcaInlineExpandCollapseState needs this
334 'uid
' => (int)$parent['uid
'],
336 'inlineFirstPid
' => $inlineFirstPid,
337 'columnsToProcess
' => [
340 // @todo: still needed? NO!
341 'inlineStructure
' => $inlineStackProcessor->getStructure(),
342 // Do not compile existing children, we don't need them now
343 'inlineCompileExistingChildren' =>
false,
350 $parentData = $formDataCompiler->compile($formDataCompilerInputForParent);
351 $parentConfig = $parentData[
'processedTca'][
'columns'][$parentFieldName][
'config'];
352 $oldItemList = $parentData[
'databaseRow'][$parentFieldName];
355 $cmd[$parent[
'table']][$parent[
'uid']][
'inlineLocalizeSynchronize'] = $parent[
'field'] .
',' . $type;
358 $tce->stripslashes_values =
false;
359 $tce->start(array(), $cmd);
360 $tce->process_cmdmap();
362 $newItemList = $tce->registerDBList[$parent[
'table']][$parent[
'uid']][$parentFieldName];
366 'stylesheetFiles' => [],
369 $nameObject = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($inlineFirstPid);
370 $nameObjectForeignTable = $nameObject .
'-' . $child[
'table'];
376 $removedItems = array_diff($oldItems, $newItems);
377 foreach ($removedItems as $childUid) {
378 $jsonArray[
'scriptCall'][] =
'inline.deleteRecord(' .
GeneralUtility::quoteJSvalue($nameObjectForeignTable .
'-' . $childUid) .
', {forceDirectRemoval: true});';
381 $localizedItems = array_diff($newItems, $oldItems);
382 foreach ($localizedItems as $childUid) {
383 $childData = $this->compileChild($parentData, $parentFieldName, (
int)$childUid, $inlineStackProcessor->getStructure());
385 $childData[
'inlineParentUid'] = (int)$parent[
'uid'];
386 $childData[
'renderType'] =
'inlineRecordContainer';
388 $childResult = $nodeFactory->create($childData)->render();
393 $foreignSelector = isset($parentConfig[
'foreign_selector']) && $parentConfig[
'foreign_selector'] ? $parentConfig[
'foreign_selector'] :
false;
395 if (is_array($selectedValue)) {
396 $selectedValue = $selectedValue[0];
400 $transOrigPointerFieldName = $childData[
'processedTca'][
'ctrl'][
'transOrigPointerField'];
401 if (isset($childData[
'databaseRow'][$transOrigPointerFieldName]) && $childData[
'databaseRow'][$transOrigPointerFieldName]) {
402 $transOrigPointerField = $childData[
'databaseRow'][$transOrigPointerFieldName];
403 if (is_array($transOrigPointerField)) {
404 $transOrigPointerField = $transOrigPointerField[0];
406 $jsonArray[
'scriptCall'][] =
'inline.fadeAndRemove(' .
GeneralUtility::quoteJSvalue($nameObjectForeignTable .
'-' . $transOrigPointerField .
'_div') .
');';
411 if (!empty($jsonArray[
'data'])) {
413 $jsonArray[
'scriptCall'],
421 $response->
getBody()->write(json_encode($jsonArray));
436 $domObjectId = $ajaxArguments[0];
441 $inlineStackProcessor->initializeByParsingDomObjectIdString($domObjectId);
442 $expand = $ajaxArguments[1];
443 $collapse = $ajaxArguments[2];
447 $currentTable = $inlineStackProcessor->getUnstableStructure();
448 $currentTable = $currentTable[
'table'];
450 $top = $inlineStackProcessor->getStructureLevel(0);
451 $topTable = $top[
'table'];
452 $topUid = $top[
'uid'];
459 foreach ($expandUids as $uid) {
460 $inlineView[$topTable][$topUid][$currentTable][] = $uid;
463 foreach ($collapseUids as $uid) {
464 $inlineView[$topTable][$topUid][$currentTable] = $this->
removeFromArray($uid, $inlineView[$topTable][$topUid][$currentTable]);
467 if (is_array($inlineView[$topTable][$topUid][$currentTable])) {
468 $inlineView[$topTable][$topUid][$currentTable] = array_unique($inlineView[$topTable][$topUid][$currentTable]);
469 $backendUser->uc[
'inlineView'] = serialize($inlineView);
470 $backendUser->writeUC();
474 $response->
getBody()->write(json_encode(array()));
491 protected function compileChild(array $parentData, $parentFieldName, $childUid, array $inlineStructure)
493 $parentConfig = $parentData[
'processedTca'][
'columns'][$parentFieldName][
'config'];
497 $inlineStackProcessor->initializeByGivenStructure($inlineStructure);
498 $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
501 $child = $inlineStackProcessor->getUnstableStructure();
502 $childTableName = $child[
'table'];
508 $formDataCompilerInput = [
510 'tableName' => $childTableName,
511 'vanillaUid' => (int)$childUid,
512 'isInlineChild' =>
true,
513 'inlineStructure' => $inlineStructure,
514 'inlineFirstPid' => $parentData[
'inlineFirstPid'],
515 'inlineParentConfig' => $parentConfig,
516 'isInlineAjaxOpeningContext' =>
true,
520 'inlineParentUid' => $parentData[
'databaseRow'][
'uid'],
521 'inlineParentTableName' => $parentData[
'tableName'],
522 'inlineParentFieldName' => $parentFieldName,
525 'inlineTopMostParentUid' => $parentData[
'inlineTopMostParentUid'] ?: $inlineTopMostParent[
'uid'],
526 'inlineTopMostParentTableName' => $parentData[
'inlineTopMostParentTableName'] ?: $inlineTopMostParent[
'table'],
527 'inlineTopMostParentFieldName' => $parentData[
'inlineTopMostParentFieldName'] ?: $inlineTopMostParent[
'field'],
532 $mainChild = $formDataCompiler->compile($formDataCompilerInput);
533 if ($parentConfig[
'foreign_selector'] && $parentConfig[
'appearance'][
'useCombination']) {
551 $intermediateUid = $intermediate[
'databaseRow'][$parentConfig[
'foreign_selector']][0];
552 $combinationChild = $this->compileChild($intermediate, $parentConfig[
'foreign_selector'], $intermediateUid, $inlineStructure);
553 return $combinationChild;
566 $jsonResult[
'data'] .= $childResult[
'html'];
567 $jsonResult[
'stylesheetFiles'] = $childResult[
'stylesheetFiles'];
568 if (!empty($childResult[
'inlineData'])) {
569 $jsonResult[
'scriptCall'][] =
'inline.addToDataArray(' . json_encode($childResult[
'inlineData']) .
');';
571 if (!empty($childResult[
'additionalJavaScriptSubmit'])) {
572 $additionalJavaScriptSubmit = implode(
'', $childResult[
'additionalJavaScriptSubmit']);
573 $additionalJavaScriptSubmit = str_replace(array(CR, LF),
'', $additionalJavaScriptSubmit);
574 $jsonResult[
'scriptCall'][] =
'TBE_EDITOR.addActionChecks("submit", "' . addslashes($additionalJavaScriptSubmit) .
'");';
576 foreach ($childResult[
'additionalJavaScriptPost'] as $singleAdditionalJavaScriptPost) {
577 $jsonResult[
'scriptCall'][] = $singleAdditionalJavaScriptPost;
579 $jsonResult[
'scriptCall'][] = $childResult[
'extJSCODE'];
580 if (!empty($childResult[
'requireJsModules'])) {
581 foreach ($childResult[
'requireJsModules'] as $module) {
584 if (is_string($module)) {
586 $moduleName = $module;
588 }
elseif (is_array($module)) {
590 foreach ($module as $key => $value) {
596 if ($moduleName !== null) {
597 $inlineCodeKey = $moduleName;
598 $javaScriptCode =
'require(["' . $moduleName .
'"]';
599 if ($callback !== null) {
600 $inlineCodeKey .= sha1($callback);
601 $javaScriptCode .=
', ' . $callback;
603 $javaScriptCode .=
');';
604 $jsonResult[
'scriptCall'][] =
'/*RequireJS-Module-' . $inlineCodeKey .
'*/' . LF . $javaScriptCode;
623 foreach ($itemArray as &$value) {
624 $parts = explode(
'|', $value, 2);
641 if (!empty($selectorConfiguration[
'PA'][
'fieldConf'][
'config'][
'appearance'][
'elementBrowserAllowed'])) {
644 $selectorConfiguration[
'PA'][
'fieldConf'][
'config'][
'appearance'][
'elementBrowserAllowed'],
647 if (!in_array(strtolower($fileRecord[
'extension']), $allowedFileExtensions,
true)) {
666 if (!empty($inlineView[$table][$uid])) {
667 $result = $inlineView[$table][$uid];
681 $inlineView = unserialize($backendUser->uc[
'inlineView']);
682 if (!is_array($inlineView)) {
683 $inlineView = array();
698 $pos = array_search($needle, $haystack, $strict);
699 if ($pos !==
false) {
700 unset($haystack[$pos]);
716 'alert("' . $message .
'");'
730 $domObjectId = str_replace(
'---',
':', $domObjectId);
732 $pattern =
'/^data' .
'-' .
'(.+?)' .
'-' .
'(.+)$/';
733 if (preg_match($pattern, $domObjectId, $match)) {
760 $domObjectId = str_replace(
'---',
':', $domObjectId);
762 $pattern =
'/^data' .
'-' .
'(?<firstPidValue>.+?)' .
'-' .
'(?<anything>.+)$/';
766 if (preg_match($pattern, $domObjectId, $match)) {
767 $parts = explode(
'-', $match[
'anything']);
769 if (!isset($parts[2]) || strpos($parts[2],
':') ===
false) {
770 throw new \UnexpectedValueException(
771 'DOM Object ID' . $domObjectId.
'does not contain required information '
772 .
'to extract inline field configuration.',
780 if (empty($fieldParts) || !isset($fieldParts[1]) || $fieldParts[1] !==
'data') {
781 throw new \UnexpectedValueException(
782 'Malformed flexform identifier: ' . $parts[2],
787 $flexFormPath = array_slice($fieldParts, 2);
790 $childConfig = $parentConfig[
'ds'][
'sheets'];
792 foreach ($flexFormPath as $flexFormNode) {
796 if (!isset($childConfig[$flexFormNode]) && preg_match(
'/^[lv][[:alpha:]]+$/', $flexFormNode)) {
799 $childConfig = $childConfig[$flexFormNode];
802 if (isset($childConfig[
'ROOT']) && $childConfig[
'ROOT'][
'type'] ==
'array') {
803 $childConfig = $childConfig[
'ROOT'][
'el'];
807 if (!isset($childConfig[
'config'])
808 || !is_array($childConfig[
'config'])
809 || $childConfig[
'config'][
'type'] !==
'inline'
811 throw new \UnexpectedValueException(
812 'Configuration retrieved from FlexForm is incomplete or not of type "inline".',
816 return $childConfig[
'config'];