[BUGFIX] Correct inline foreign_unique with target type="group" handling 21/58421/5
authorCyril Janody <typo3@cjanody.com>
Thu, 27 Sep 2018 22:31:10 +0000 (18:31 -0400)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Thu, 11 Oct 2018 18:25:37 +0000 (20:25 +0200)
Using type="inline" and MM relations having type="group" (instead of
type="select") and foreign_unique defined results in a fatal since
group db relations have been resolved to an array in TcaGroup data
provider already.

Change-Id: I20d138e7622aafb097a11e60014f9e4398bae811
Resolves: #82104
Resolves: #84735
Releases: master, 8.7
Reviewed-on: https://review.typo3.org/58421
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Cyril Janody <typo3@cjanody.com>
Tested-by: Cyril Janody <typo3@cjanody.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php
typo3/sysext/backend/Classes/Form/Element/SelectSingleElement.php

index d4bb45c..0c96e01 100644 (file)
@@ -196,6 +196,7 @@ class InlineControlContainer extends AbstractContainer
 
         if ($config['foreign_unique']) {
             // Add inlineData['unique'] with JS unique configuration
+            // @todo: Improve validation and throw an exception if type is neither select nor group here
             $type = $config['selectorOrUniqueConfiguration']['config']['type'] === 'select' ? 'select' : 'groupdb';
             foreach ($parameterArray['fieldConf']['children'] as $child) {
                 // Determine used unique ids, skip not localized records
@@ -203,18 +204,24 @@ class InlineControlContainer extends AbstractContainer
                     $value = $child['databaseRow'][$config['foreign_unique']];
                     // We're assuming there is only one connected value here for both select and group
                     if ($type === 'select') {
-                        // A resolved select field is an array - take first value
+                        // A select field is an array of uids. See TcaSelectItems data provider for details.
+                        // Pick first entry, ends up as eg. $value = 42.
                         $value = $value['0'];
                     } else {
-                        // A group field is still a list with pipe separated uid|tableName
-                        $valueParts = GeneralUtility::trimExplode('|', $value);
-                        $itemParts = explode('_', $valueParts[0]);
+                        // A group field is an array of arrays containing uid + table + title + row.
+                        // See TcaGroup data provider for details.
+                        // Pick the first one (always on 0), and use uid + table only. Exclude title + row
+                        // since the entire inlineData['unique'] array ends up in JavaScript in the end
+                        // and we don't need and want the title and the entire row data in the frontend.
+                        // Ends up as $value = [ 'uid' => '42', 'table' => 'tx_my_table' ]
                         $value = [
-                            'uid' => array_pop($itemParts),
-                            'table' => implode('_', $itemParts)
+                            'uid' => $value[0]['uid'],
+                            'table' => $value[0]['table'],
                         ];
                     }
-                    // @todo: This is weird, $value has different structure for group and select fields?
+                    // Note structure of $value is different in select vs. group: It's a uid for select, but an
+                    // array with uid + table for group. This is handled differently on JavaScript side, search
+                    // for 'groupdb' in jsfunc.inline.js for details.
                     $uniqueIds[$child['databaseRow']['uid']] = $value;
                 }
             }
index f97927d..a710909 100644 (file)
@@ -87,6 +87,9 @@ class SelectSingleElement extends AbstractFormElement
         $inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
         $uniqueIds = null;
         if ($this->data['isInlineChild'] && $this->data['inlineParentUid']) {
+            // @todo: At least parts of this if is dead and/or broken: $uniqueIds is filled but never used.
+            // See InlineControlContainer where 'inlineData' 'unique' 'used' is set. What exactly is
+            // this if supposed to do and when should it kick in and what for?
             $inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
             $inlineFormName = $inlineStackProcessor->getCurrentStructureFormPrefix();
             if ($this->data['inlineParentConfig']['foreign_table'] === $table