From bac90eeed93f8c8b45aa289f7f6156113094640c Mon Sep 17 00:00:00 2001 From: Christian Kuhn <lolli@schwarzbu.ch> Date: Tue, 28 Mar 2023 12:22:50 +0200 Subject: [PATCH] [TASK] Deprecate TCA config MM_insert_fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "True" MM relations (intermediata table with uid_local and uid_foreign columns, and no TCA for this table) are still hard to configure in TYPO3. One reason is the amount of TCA config options: It's often not clear to developers which ones need to be set, and which ones are optional or useless. One of the 'useless' options is MM_insert_fields: It allows setting a column in the intermediate table to a configured value. Intermediate tables are transparent in TYPO3: They are fully managed by the system, there is not way to edit them within the framework. As such, having an additional column within intermediate tables that carry some value, is useless. Looking at usages within extensions of MM_insert_fields, it turns out developers typically confuse it with MM_match_fields (this config is a story on its own). Developers simply tend to set both MM_insert_fields and MM_match_fields to the same value "to be sure". The patch deprecates MM_insert_fields without substitution in v12. TYPO3 v13 will actively remove this config option from TCA. Resolves: #100335 Releases: main Change-Id: I7832321fb3bcbfc00bb6f288c6f0cd5ceb41dc64 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78297 Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: Stefan Bürk <stefan@buerk.tech> Reviewed-by: Stefan Bürk <stefan@buerk.tech> Tested-by: core-ci <typo3@b13.com> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../core/Classes/Database/RelationHandler.php | 10 ++- .../core/Classes/Migrations/TcaMigration.php | 22 ++++++ ...ation-100335-TCAConfigMM_insert_fields.rst | 77 +++++++++++++++++++ .../Unit/Migrations/TcaMigrationTest.php | 33 ++++++++ .../Classes/Persistence/Generic/Backend.php | 1 + .../Persistence/Generic/Mapper/ColumnMap.php | 7 ++ .../Generic/Mapper/ColumnMapFactory.php | 1 + 7 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100335-TCAConfigMM_insert_fields.rst diff --git a/typo3/sysext/core/Classes/Database/RelationHandler.php b/typo3/sysext/core/Classes/Database/RelationHandler.php index 7dcd830ab838..3923835a540c 100644 --- a/typo3/sysext/core/Classes/Database/RelationHandler.php +++ b/typo3/sysext/core/Classes/Database/RelationHandler.php @@ -134,6 +134,8 @@ class RelationHandler /** * Array of fields and value pairs used for insert in MM table + * + * @deprecated since v12. Remove in v13 with other MM_insert_fields places. */ protected array $MM_insert_fields = []; @@ -243,6 +245,7 @@ class RelationHandler $this->MM_table_where = $conf['MM_table_where'] ?? null; $this->MM_hasUidField = $conf['MM_hasUidField'] ?? null; $this->MM_match_fields = (isset($conf['MM_match_fields']) && is_array($conf['MM_match_fields'])) ? $conf['MM_match_fields'] : []; + // @deprecated since v12. Remove in v13 with other MM_insert_fields places. $this->MM_insert_fields = (isset($conf['MM_insert_fields']) && is_array($conf['MM_insert_fields'])) ? $conf['MM_insert_fields'] : []; $this->currentTable = $currentTable; if (!empty($conf['MM_oppositeUsage']) && is_array($conf['MM_oppositeUsage'])) { @@ -722,6 +725,8 @@ class RelationHandler // foreach loop only the ones that need to be deleted are in there. unset($oldMMs_inclUid[$oldMMs_index]); } else { + // @deprecated since v12. Remove in v13 with other MM_insert_fields places. + // Simplify to $insertFields = $this->MM_match_fields; $insertFields = $this->MM_insert_fields; $insertFields = array_merge($insertFields, $this->MM_match_fields); $insertFields[$uidLocal_field] = $uid; @@ -1531,9 +1536,8 @@ class RelationHandler $configuration = $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config']; if (!empty($configuration['MM_insert_fields'])) { - // @todo: MM_insert_fields does not make sense and should be probably dropped altogether. - // No core usages, not even with sys_category. There is no point in having data fields that - // are filled with static content, especially since the mm table can't be edited directly. + // @deprecated since v12. Remove in v13 with other MM_insert_fields places. + // Remove if() and change elseif() to if(). $referenceValues = array_merge($configuration['MM_insert_fields'], $referenceValues); } elseif (!empty($configuration['MM_match_fields'])) { // @todo: In the end, MM_match_fields does not make sense. The 'tablename' and 'fieldname' restriction diff --git a/typo3/sysext/core/Classes/Migrations/TcaMigration.php b/typo3/sysext/core/Classes/Migrations/TcaMigration.php index 869bbd948c18..a1523f1999b1 100644 --- a/typo3/sysext/core/Classes/Migrations/TcaMigration.php +++ b/typo3/sysext/core/Classes/Migrations/TcaMigration.php @@ -87,6 +87,7 @@ class TcaMigration $tca = $this->removeFalRelatedOptionsFromTypeInline($tca); $tca = $this->removePassContentFromTypeNone($tca); $tca = $this->migrateItemsToAssociativeArray($tca); + $tca = $this->removeMmInsertFields($tca); return $tca; } @@ -1446,4 +1447,25 @@ class TcaMigration } return $tca; } + + protected function removeMmInsertFields(array $tca): array + { + foreach ($tca as $table => $tableDefinition) { + if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'] ?? false)) { + continue; + } + foreach ($tableDefinition['columns'] as $fieldName => $fieldConfig) { + if (isset($fieldConfig['config']['MM_insert_fields'])) { + // @deprecated since v12. + // *Enable* the commented unset line in v13 when removing MM_insert_fields deprecations. + // *Enable* the disabled unit test set. + // unset($tca[$table]['columns'][$fieldName]['config']['MM_insert_fields']); + $this->messages[] = 'The TCA field \'' . $fieldName . '\' of table \'' . $table . '\' uses ' + . '\'MM_insert_fields\'. This config key is obsolete and should be removed. ' + . 'Please adjust your TCA accordingly.'; + } + } + } + return $tca; + } } diff --git a/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100335-TCAConfigMM_insert_fields.rst b/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100335-TCAConfigMM_insert_fields.rst new file mode 100644 index 000000000000..8ffbcd5cb847 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100335-TCAConfigMM_insert_fields.rst @@ -0,0 +1,77 @@ +.. include:: /Includes.rst.txt + +.. _deprecation-100335-1679998903: + +================================================== +Deprecation: #100335 - TCA config MM_insert_fields +================================================== + +See :issue:`100335` + +Description +=========== + +The TCA option :php:`MM_insert_fields` has been marked +as deprecated and should not be used anymore. + + +Impact +====== + +Using :php:`MM_insert_fields` raises a deprecation level log message +during TCA cache warmup. Its functionality is kept in TYPO3 v12 but will +be removed in v13. + + +Affected installations +====================== + +There may be extensions that use this option when configuring database +MM relations. In most cases, the option can be removed. The migration +section gives more details. + + +Migration +========= + +General scope: :php:`MM_insert_fields` is used in combination with "true" +database MM intermediate tables to allow many-to-many relations between +two tables for :php:`group`, :php:`select` and sometimes even :php:`inline` +type fields. + +A core example is the :sql:`sys_category` to :sql:`tt_content` +relation, with :sql:`sys_category_record_mm` as intermediate table: The +intermediate table has field :sql:`uid_local` (pointing to a uid of +the "left" :sql:`sys_category` table), and :sql:`uid_foreign` (pointing to a +uid of the "right" :sql:`tt_content` table). Note this specific relation also +allows multiple different "right-side" table-field combinations, using the two +additional fields :sql:`tablenames` and :sql:`fieldname`. All this is configured +with TCA on the "left" and the "right" side table field, while table +:sql:`sys_category_record_mm` has no TCA itself. Rows within the intermediate +table are transparently handled by TYPO3 by the :php:`RelationHandler` and +extbase TCA-aware domain logic. + +The :php:`MM_insert_fields` now allows to configure a hard coded value for +an additional column within the intermediate table. This is obsolete: There is +no API to retrieve this value again, having a "stable" value in an additional +column is useless. This config option should be removed from TCA +definition. + +Note on the related option :php:`MM_match_fields`: This is important when an +MM relation allows multiple "right" sides. In the example above, when a category +is added to a tt_content record using the :sql:`categories` field, and when editing +this relation from the "right" side (editing a tt_content record), then this option +is used to select only relations for this tt_content/categories combination. The +TCA column :sql:`categories` thus uses :sql:`MM_match_fields` to restrict the +query. Note :sql:`MM_match_fields` is *not* set for the "left-side" :sql:`sys_category` +:sql:`items` fields, this would indicate a TCA misconfiguration. + +Various extensions in the wild did not get these details right, and often simply +set *both* :php:`MM_insert_fields` and :php:`MM_match_fields` to the same values. +Removing :php:`MM_insert_fields` helps reducing confusion and simplifies this +construct a bit. Affected extensions can simply remove the :php:`MM_insert_fields` +configuration and keep the :php:`MM_match_fields`. Note the core strives to further +simplify these options and :php:`MM_match_fields` may become fully obsolete in the +future as well. + +.. index:: TCA, NotScanned, ext:core diff --git a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php index 5b33d527145e..bcd463a04341 100644 --- a/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php +++ b/typo3/sysext/core/Tests/Unit/Migrations/TcaMigrationTest.php @@ -3655,4 +3655,37 @@ class TcaMigrationTest extends UnitTestCase self::assertSame($expected, (new TcaMigration())->migrate($input)); } + + /** + * @deprecated since v12. Add @test when removing MM_insert_fields in v13. + */ + public function migrationRemovesMmInsertFields(): void + { + $input = [ + 'aTable' => [ + 'columns' => [ + 'aColumn' => [ + 'config' => [ + 'type' => 'group', + 'MM_insert_fields' => [ + 'aField' => 'aValue', + ], + ], + ], + ], + ], + ]; + $expected = [ + 'aTable' => [ + 'columns' => [ + 'aColumn' => [ + 'config' => [ + 'type' => 'group', + ], + ], + ], + ], + ]; + self::assertSame($expected, (new TcaMigration())->migrate($input)); + } } diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php index 02bbb0ecee8a..2521ed6d20e9 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php @@ -679,6 +679,7 @@ class Backend implements BackendInterface, SingletonInterface if (is_array($relationTableMatchFields)) { $row = array_merge($relationTableMatchFields, $row); } + // @deprecated since v12. Remove in v13 with other MM_insert_fields places. $relationTableInsertFields = $columnMap->getRelationTableInsertFields(); if (is_array($relationTableInsertFields)) { $row = array_merge($relationTableInsertFields, $row); diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMap.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMap.php index 898ca767e566..598fff7e14a1 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMap.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMap.php @@ -84,6 +84,7 @@ class ColumnMap * * @see https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ColumnsConfig/Type/Group/Properties/Mm.html#confval-MM_insert_fields(type=%3Egroup) * @var array|null + * @deprecated since v12. Remove in v13 with other MM_insert_fields places. */ private $relationTableInsertFields; @@ -202,11 +203,17 @@ class ColumnMap return $this->relationTableMatchFields; } + /** + * @deprecated since v12. Remove in v13 with other MM_insert_fields places. + */ public function setRelationTableInsertFields(array $relationTableInsertFields): void { $this->relationTableInsertFields = $relationTableInsertFields; } + /** + * @deprecated since v12. Remove in v13 with other MM_insert_fields places. + */ public function getRelationTableInsertFields(): ?array { return $this->relationTableInsertFields; diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMapFactory.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMapFactory.php index bf6a17dfcd5b..fba78847a3de 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMapFactory.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/ColumnMapFactory.php @@ -228,6 +228,7 @@ class ColumnMapFactory if (isset($columnConfiguration['MM_match_fields']) && is_array($columnConfiguration['MM_match_fields'])) { $columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']); } + // @deprecated since v12. Remove in v13 with other MM_insert_fields places. if (isset($columnConfiguration['MM_insert_fields']) && is_array($columnConfiguration['MM_insert_fields'])) { $columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']); } -- GitLab