diff --git a/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php b/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php index e65148aba17e44a050fa00c5fb270281d1a71c38..8121b676db4408c8e3be8e92712eb392f01d74f3 100644 --- a/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php +++ b/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php @@ -120,7 +120,7 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController $formDataCompilerInput = [ 'request' => $request, 'command' => 'new', - 'tableName' => $childData['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table'], + 'tableName' => $this->getChildChildTableName($parentConfig['foreign_selector'], $childData), 'vanillaUid' => $inlineFirstPid, 'isInlineChild' => true, 'isInlineAjaxOpeningContext' => true, @@ -492,13 +492,11 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController { // foreign_selector on intermediate is probably type=select, so data provider of this table resolved that to the uid already $childChildUid = $child['databaseRow'][$parentConfig['foreign_selector']][0]; - // child-child table name is set in child tca "the selector field" foreign_table - $childChildTableName = $child['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table']; $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class); $formDataCompilerInput = [ 'request' => $request, 'command' => 'edit', - 'tableName' => $childChildTableName, + 'tableName' => $this->getChildChildTableName($parentConfig['foreign_selector'] ?? '', $child), 'vanillaUid' => (int)$childChildUid, 'isInlineChild' => true, 'isInlineAjaxOpeningContext' => true, @@ -662,6 +660,22 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController return json_decode($context['config'], true); } + /** + * The child-child table name is set in the child TCA "the selector field" and is depending on + * the TCA type (select or group) either the "foreign_table" or the (first) "allowed" table. + */ + protected function getChildChildTableName(string $foreignSelector, array $childConfiguration): string + { + $config = $childConfiguration['processedTca']['columns'][$foreignSelector]['config'] ?? []; + $type = $config['type'] ?? ''; + + return match ($type) { + 'select' => $config['foreign_table'] ?? '', + 'group' => GeneralUtility::trimExplode(',', $config['allowed'] ?? '', true)[0] ?? '', + default => '', + }; + } + protected function getBackendUserAuthentication(): BackendUserAuthentication { return $GLOBALS['BE_USER']; diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php index e10e7fa8e90401bfb0efee5ed96336bb91b7cc80..5c73d29712004bcb835eeeadc055ffd386b73acd 100644 --- a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php +++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInline.php @@ -389,14 +389,12 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid { // foreign_selector on intermediate is probably type=select, so data provider of this table resolved that to the uid already $childChildUid = $child['databaseRow'][$parentConfig['foreign_selector']][0]; - // child-child table name is set in child tca "the selector field" foreign_table - $childChildTableName = $child['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table']; $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class); $formDataCompilerInput = [ 'request' => $child['request'], 'command' => 'edit', - 'tableName' => $childChildTableName, + 'tableName' => $this->getChildChildTableName($parentConfig['foreign_selector'] ?? '', $child), 'vanillaUid' => (int)$childChildUid, 'isInlineChild' => true, 'isInlineChildExpanded' => $child['isInlineChildExpanded'], @@ -493,6 +491,22 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid return $liveDefaultId; } + /** + * The child-child table name is set in the child TCA "the selector field" and is depending on + * the TCA type (select or group) either the "foreign_table" or the (first) "allowed" table. + */ + protected function getChildChildTableName(string $foreignSelector, array $childConfiguration): string + { + $config = $childConfiguration['processedTca']['columns'][$foreignSelector]['config'] ?? []; + $type = $config['type'] ?? ''; + + return match ($type) { + 'select' => $config['foreign_table'] ?? '', + 'group' => GeneralUtility::trimExplode(',', $config['allowed'] ?? '', true)[0] ?? '', + default => '', + }; + } + protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; diff --git a/typo3/sysext/core/Documentation/Changelog/12.4.x/Important-102904-UseTCAGroupFieldAsForeignSelector.rst b/typo3/sysext/core/Documentation/Changelog/12.4.x/Important-102904-UseTCAGroupFieldAsForeignSelector.rst new file mode 100644 index 0000000000000000000000000000000000000000..173cca39f9dc6f0d9ce9246d4014bb68134284c7 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/12.4.x/Important-102904-UseTCAGroupFieldAsForeignSelector.rst @@ -0,0 +1,80 @@ +.. include:: /Includes.rst.txt + +.. _important-102904-1706702424: + +============================================================ +Important: #102904 - Use TCA group field as foreign selector +============================================================ + +See :issue:`102904` + +Description +=========== + +When using TCA type :php:`inline`, developers have the possibility to use the +"foreign selector" feature by defining the :php:`foreign_selector` option, +pointing to a field on the foreign (child) table. This way, editors can +use the corresponding selector field to choose existing child records, +to create a new inline relation. This can be further extended, using the +:php:`useCombination` appearance option, which allows to modify the child record +via the parent record globally. + +The field referenced in :php:`foreign_selector` is usually a field with TCA type +:php:`select`, using the `foreign_table` option itself to provide the corresponding +items to choose. + +It's nevertheless also possible to use a TCA type :php:`group` field as +:php:`foreign_selector`. In this case, the child records have to be selected +from the table, defined via the :php:`allowed` option. For this use case, +**only one table** can be defined. This means, the first table name in +:php:`allowed` is taken, no matter if there are multiple table names defined. + +.. note:: + + This unfortunately does not work out of the box for Extbase. Therefore, the + corresponding table has to be defined additionally via the :php:`foreign_table` + option. This option is only used as a + `workaround <https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ColumnsConfig/Type/Group/Properties/ForeignTable.html>`__ + by Extbase and is not sufficient for the TYPO3 Form editor, which will always + just consider the value from the :php:`allowed` option. + +Example using an intermediate table and the :php:`useCombination` feature: + +.. code-block:: php + + // Inline field in parent table "tx_extension_inline_usecombination" + 'inline' => [ + 'label' => 'inline', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_extension_inline_usecombination_mm', // Referencing the intermediate table + 'foreign_field' => 'group_parent', + 'foreign_selector' => 'group_child', + 'foreign_unique' => 'group_child', + 'appearance' => [ + 'useCombination' => true, + ], + ], + ], + + // Reference fields in intermediate table "tx_extension_inline_usecombination_mm" + 'group_parent' => [ + 'label' => 'group parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_extension_inline_usecombination', // Referencing the parent table + ], + ], + 'group_child' => [ + 'label' => 'group child', + 'config' => [ + 'type' => 'group', + 'allowed' => 'tx_extension_inline_usecombination_child', // Referencing the child table + 'foreign_table' => 'tx_extension_inline_usecombination_child', // ONLY USED FOR extbase! + ], + ], + + // Child table "tx_extension_inline_usecombination_child" does not have any relation fields + +.. index:: Backend, PHP-API, TCA, ext:backend