From 29537318a372c0724ee8f5d24eb19cd00833711a Mon Sep 17 00:00:00 2001 From: Oliver Bartsch <bo@cedev.de> Date: Tue, 30 Jan 2024 17:45:14 +0100 Subject: [PATCH] [BUGFIX] Respect TCA type `group` as `foreign_selector` It's now possible to use a TCA type `group` field as `foreign_selector` together with the `useCombination` functionality. The corresponding "child child table" information is in this case fetched from the `allowed` option. Side note: Using TCA type `group` for a `foreign_selector` field is not really documented, but it's also not forbidden. Actually, it's a valid use case and also working quite well as the new styleguide examples demonstrate. However, the documentation should be adjusted to mention that only one table can be defined in `allowed` for such fields. Resolves: #102904 Releases: main, 12.4 Change-Id: Icdde6a8acb1fb9166da8e6259758f6bf64d6c41f Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82994 Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Oliver Bartsch <bo@cedev.de> --- .../Controller/FormInlineAjaxController.php | 22 ++++- .../Form/FormDataProvider/TcaInline.php | 20 ++++- ...2904-UseTCAGroupFieldAsForeignSelector.rst | 80 +++++++++++++++++++ 3 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/12.4.x/Important-102904-UseTCAGroupFieldAsForeignSelector.rst diff --git a/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php b/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php index e65148aba17e..8121b676db44 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 e10e7fa8e904..5c73d2971200 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 000000000000..173cca39f9dc --- /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 -- GitLab