Skip to content

Commit

Permalink
[TASK] Deprecate TCA sub types
Browse files Browse the repository at this point in the history
The sub types feature of TCA was used for
registration of plugins as "list_type". Since
it's encouraged to register plugins as CType
since a couple of versions already and the
deprecation of the "list_type" functionality
with #105076 are the sub types now deprecated
as well.

This special functionality just lead to
headaches and should be replaced by using
dedicated record types, making configuration
much cleaner and more comprehensible.

Resolves: #105213
Related: #105076
Releases: main
Change-Id: If9ce3f5de7ef69aaf16cf987ebcb62ea50f9a6a6
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/86425
Reviewed-by: Torben Hansen <[email protected]>
Reviewed-by: Oliver Bartsch <[email protected]>
Tested-by: Torben Hansen <[email protected]>
Reviewed-by: Christian Kuhn <[email protected]>
Tested-by: Benni Mack <[email protected]>
Tested-by: core-ci <[email protected]>
Tested-by: Christian Kuhn <[email protected]>
Reviewed-by: Benni Mack <[email protected]>
Tested-by: Oliver Bartsch <[email protected]>
  • Loading branch information
o-ba committed Oct 7, 2024
1 parent 19f39c1 commit dd1c4bd
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ protected function loadAvailableWizardsFromContentElements(): array
: [];
}

/**
* @deprecated Remove in v14, when "sub types" are removed altogether
*/
protected function loadAvailableWizardsFromPluginSubTypes(): array
{
return (($pluginSubtypeValueField = (string)($GLOBALS['TCA']['tt_content']['types']['list']['subtype_value_field'] ?? '')) !== '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public function containerAdd(ServerRequestInterface $request): ResponseInterface
// *should* be avoided. But sub types should vanish from TCA at some point anyway (this usage shows
// the complexity they introduce quite well), so we live with the solution for now instead of handing
// the selected sub type through the system differently.
// @deprecated Remove in v14, when "sub types" are removed altogether
$subtypeValueField = $processedTca['types'][$recordTypeValue]['subtype_value_field'] ?? null;
$subtypeValue = explode(',', $queryParameters['dataStructureIdentifier']['dataStructureKey'] ?? '')[0];
if ($subtypeValueField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public function addData(array $result)

// fields added to subtypes_addlist (can be pi_flexform)
$recordTypeValue = $result['recordTypeValue'];
// @deprecated Remove in v14, when "sub types" are removed altogether
if (!empty($result['processedTca']['types'][$recordTypeValue]['subtype_value_field'])) {
$subtypeFieldName = $result['processedTca']['types'][$recordTypeValue]['subtype_value_field'];
$fieldName = $result['databaseRow'][$subtypeFieldName] ?? null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function addData(array $result)
$recordTypeValue = $result['recordTypeValue'];

// Handle subtype_value_field, subtypes_addlist, subtypes_excludelist
// @deprecated Remove in v14, when "sub types" are removed altogether
if (!empty($result['processedTca']['types'][$recordTypeValue]['subtype_value_field'])) {
$subtypeFieldName = $result['processedTca']['types'][$recordTypeValue]['subtype_value_field'];
if (array_key_exists($subtypeFieldName, $result['databaseRow'])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function resolveRendererFor(string $table, array $row, int $pageUid): Pre
$tcaTypeOfRow = $row[$tcaTypeField];
$typeConfiguration = $tca['types'][$tcaTypeOfRow] ?? [];

// @deprecated Remove in v14, when "sub types" are removed altogether
$subTypeValueField = $typeConfiguration['subtype_value_field'] ?? null;
if (!empty($typeConfiguration['previewRenderer'])) {
if (!empty($subTypeValueField) && is_array($typeConfiguration['previewRenderer'])) {
Expand Down
29 changes: 27 additions & 2 deletions typo3/sysext/core/Classes/Configuration/Tca/TcaMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* Migrate TCA from old to new syntax.
* Used in bootstrap and Flex Form Data Structures.
* This is to *migrate* from "old" to "new" TCA syntax,
* all methods must add a deprecation method if they
* all methods must add a deprecation message if they
* change something.
*
* @internal Class and API may change any time.
Expand All @@ -49,6 +49,7 @@ class TcaMigration
public function migrate(array $tca): array
{
$this->validateTcaType($tca);
$this->deprecateSubTypes($tca);

$tca = $this->migrateColumnsConfig($tca);
$tca = $this->migratePagesLanguageOverlayRemoval($tca);
Expand Down Expand Up @@ -107,7 +108,7 @@ public function getMessages(): array
*
* @param array $tca Incoming TCA
*/
protected function validateTcaType(array $tca)
protected function validateTcaType(array $tca): void
{
foreach ($tca as $table => $tableDefinition) {
if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
Expand All @@ -124,6 +125,30 @@ protected function validateTcaType(array $tca)
}
}

/**
* Adds deprecation log entries for sub types usages
*/
protected function deprecateSubTypes(array $tca): void
{
foreach ($tca as $table => $tableDefinition) {
if (!is_array($tableDefinition['types'] ?? false)) {
continue;
}
foreach ($tableDefinition['types'] ?? [] as $typeName => $typeConfig) {
if (!isset($typeConfig['subtype_value_field'])
// Do not add deprecation entry for tt_content.list_type as this is deprecated separately
|| ($table === 'tt_content' && $typeConfig['subtype_value_field'] === 'list_type')
) {
continue;
}
$this->messages[] = 'The TCA record type \'' . $typeName . '\' of table \'' . $table . '\' defines the '
. 'field \'' . $typeConfig['subtype_value_field'] . '\' as \'subtype_value_field\', which is '
. 'deprecated since TYPO3 v13 and will stop working in TYPO3 v14. Please adjust your TCA '
. 'accordingly by migrating those sub types to dedicated record types.';
}
}
}

/**
* Find columns fields that don't have a 'config' section at all, add
* ['config']['type'] = 'none'; for those to enforce config
Expand Down
3 changes: 2 additions & 1 deletion typo3/sysext/core/Classes/Schema/TcaSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ public function getSubSchemaDivisorField(): ?FieldTypeInterface
}

/**
* @internal "subtype" is not considered as API of TcaSchema since this feature will most likely be deprecated in upcoming versions
* @deprecated Remove in v14, when "sub types" are removed altogether
* @internal "subtype" is not considered as API of TcaSchema
*/
public function getSubTypeDivisorField(): ?FieldTypeInterface
{
Expand Down
2 changes: 1 addition & 1 deletion typo3/sysext/core/Classes/Schema/TcaSchemaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ protected function build(string $schemaName, array $fullTca, RelationMap $relati
$subSchemaFields[$fieldName] = $field;
}

// @todo Support of "subtypes" will most likely be deprecated in upcoming versions
// @deprecated Remove"sub type" handling in v14
$subTypeSchemata = [];
if (isset($subSchemaDefinition['subtype_value_field'])
&& ($subTypeDivisorField = $subSchemaFields[$subSchemaDefinition['subtype_value_field']] ?? null) !== null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
.. include:: /Includes.rst.txt

.. _deprecation-105213-1728286135:

====================================
Deprecation: #105213 - TCA sub types
====================================

See :issue:`105213`

Description
===========

One of the main features of TCA are the record types. This allows to use
a single table for different purposes and in different contexts. The most
known examples of using record types are the "Page Types" of :sql:`pages`
and the "Content Types" of :sql:`tt_content`. For every specific type of
such table, it's possible to define the fields to be used and even
manipulate them e.g. change their label.

A special case since ever has been the plugin registration. This for
a long time has been done using the so called "sub types" feature of TCA.
This is another layer below record types and allows to further customize
the behaviour of a record type using another select field, defined via
:php:`subtype_value_field` as well as defining fields to be added
- :php:`subtypes_addlist` - or excluded - :php:`subtypes_excludelist` - for
the record type, depending on the selected sub type.

For a couple of version now, it's encouraged to register plugins just
as standard content elements via the :php:`tt_content` type field :php:`CType`.
Therefore, the special registration via the combination of the :php:`list`
record type and the selection of a sub type via the :php:`list_type` field
has already been deprecated with :ref:`deprecation-105076-1726923626`.

Since the "sub types" feature was mainly used for this scenario only, it has
now been deprecated as well. Registration of custom types should therefore
always be done by using record types. This makes configuration much cleaner
and more comprehensible.

Impact
======

Using :php:`subtype_value_field` in a TCA `types` configurations will
lead to a deprecation log entry containing information about where
adaptations need to take place.


Affected installations
======================

All installations using the sub types feature by defining a
:php:`subtype_value_field` in a TCA `types` configuration, which
is really uncommon as the feature was mainly used for plugin
registration in the :sql:`tt_content` table only.

Migration
=========

Replace any :php:`subtype_value_field` configuration with dedicated record
types. Please also consider migrating corresponding :php:`subtypes_addlist`
and :php:`subtypes_excludelist` definitions accordingly.

Before
^^^^^^

.. code-block:: php
'ctrl' => [
'type' => 'type',
],
'columns' => [
'type' => [
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => 'A record type',
'value' => 'a_record_type'
]
]
]
],
'subtype' => [
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => 'A sub type',
'value' => 'a_sub_type'
]
]
]
],
],
'types' => [
'a_record_type' => [
'showitem' => 'aField,bField',
'subtype_value_field' => 'subtype',
'subtypes_addlist' => [
'a_sub_type' => 'pi_flexform'
],
'subtypes_excludelist' => [
'a_sub_type' => 'bField'
]
]
]
After
^^^^^

.. code-block:: php
'ctrl' => [
'type' => 'type',
],
'columns' => [
'type' => [
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => 'A record type',
'value' => 'a_record_type'
],
[
'label' => 'A sub type',
'value' => 'a_sub_type'
]
]
]
],
],
'types' => [
'a_record_type' => [
'showitem' => 'aField,bField'
],
'a_sub_type' => [
'showitem' => 'aField,pi_flexform'
]
]
.. index:: PHP-API, TCA, FullyScanned, ext:core
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,32 @@ public function missingTypeThrowsException(): void
$subject->migrate($input);
}

#[Test]
public function usageOfSubTypeAddsMessage(): void
{
$input = [
'aTable' => [
'types' => [
'aType' => [
'subtype_value_field' => 'subtype_value_file',
],
],
],
'tt_content' => [
'types' => [
'list' => [
'subtype_value_field' => 'list_type',
],
],
],
];
$subject = new TcaMigration();
$subject->migrate($input);
$messages = $subject->getMessages();
self::assertCount(1, $messages);
self::assertStringContainsString('The TCA record type \'aType\' of table \'aTable\' defines the field \'subtype_value_file\' as \'subtype_value_field\'', $messages[0]);
}

#[Test]
public function migrateReturnsGivenArrayUnchangedIfNoMigrationNeeded(): void
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
/**
* This event listener removes the Content Element "General Plugin" (CType: list) if
* there are no `list_type` plugins registered.
*
* @deprecated Remove event listener in v14, when the whole sub types feature is removed
*/
class RemoveListTypePluginFromNewContentElementWizard
{
Expand Down

0 comments on commit dd1c4bd

Please sign in to comment.