Project

General

Profile

Actions

Feature #104589

open

TCA generation for domain models by php attributes

Added by Daniel Ablass 3 months ago.

Status:
New
Priority:
Should have
Assignee:
-
Category:
Extbase
Target version:
-
Start date:
2024-08-10
Due date:
% Done:

0%

Estimated time:
PHP Version:
8.1
Tags:
Complexity:
Sprint Focus:

Description

This feature provides an alternative way of generating the TCA for domain models based on php attributes. It does not replace the TCA as underlying structure, but makes files in EXT:my_extension/Configuration/TCA/ obsolete in most cases.

Benefits

  • field configuration is placed directly next to the property definition in the model - no local separation of related information
  • autocompletion of attribute properties in IDE
  • reduces duplicated code by providing useful default values
  • can be used in combination with classic TCA files
A proof of concept can be found inside psb_foundation - especially in

That extension already provides a collection of attributes that covers many of the available TCA options (but not yet 100%). The default values for each property have been derived from many TCA files in some projects to cover most use cases and reduce the number of custom values passed to the attribute constructor.

Examples

Classic TCA file

[
    'ctrl' => [
        'title' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_db.xlf:tx_myextension_domain_model_myclass',
        'label' => 'uid',
        'tstamp' => 'tstamp',
        'crdate' => 'crdate',
        'delete' => 'deleted',
        'default_sortby' => 'uid',
        'iconfile' => 'EXT:core/Resources/Public/Icons/T3Icons/svgs/content/content-extension.svg',
        'enablecolumns' => [
            'disabled' => 'hidden',
            'starttime' => 'starttime',
            'endtime' => 'endtime',
        ],
        'transOrigPointerField' => 'l18n_parent',
        'transOrigDiffSourceField' => 'l18n_diffsource',
        'languageField' => 'sys_language_uid',
        'translationSource' => 'l10n_source',
    ],
    'columns' => [
        'title' => [
            'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_db.xlf:tx_myextension_domain_model_myclass.title',
            'config' => [
                'type' => 'input',
                'size' => 40,
                'max' => 255,
                'eval' => 'trim'
            ],
        ],
        'description' => [
            'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_db.xlf:tx_myextension_domain_model_myclass.description',
            'config' => [
                'type' => 'text',
                'cols' => 32,
                'rows' => 5,
                'eval' => 'trim'
            ],
        ],
        'description' => [
            'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_db.xlf:tx_myextension_domain_model_myclass.number',
            'config' => [
                'type' => 'number',
                'format' => 'integer',
            ],
        ],
    ],
]

New attribute approach

#[Ctrl]
class MyClass
{
    #[Input]
    protected string $title = '';

    #[Text]
    protected string $description = '';

    #[Number]
    protected int $value = 0;
}

Default values can be overridden by constructor arguments:

#[Ctrl(label: 'title', searchFields: ['title', 'description'])]
class MyClass
{
    #[Input(size: 20)]
    protected string $title = '';

    #[Text(enableRichText: true)]
    protected string $description = '';

    #[Number]
    protected int $value = 0;
}

The directory Classes/Domain/Model/ of all active packages is scanned for all classes (skipping abstract ones) that have a Ctrl attribute attached. It is checked if a model relates to an existing table in the database and detects, if it extends another model from a different extension and manipulates the TCA accordingly. When extending another domain model, the default values of the Ctrl attribute are not taken into account, but only those explicitly passed to the constructor to avoid unwanted changes to the original TCA.

Properties without TCA attribute will not be considered in TCA generation. Some configurations will be added automatically if specific fields are defined in the Ctrl attribute (which they are by default): e. g. enableColumns and language fields.

The attributes are not simply transformed into arrays, but have concrete getters that enable additional logic and the implementation of events that focus on small parts of the TCA - it is not necessary to always pass and process the entire TCA array. If a property is null, it will not be included in the final TCA. This prevents the TCA from becoming unnecessarily bloated with unused options.

Example of an auxiliary property

#[Select(linkedModel: MyRelatedModel::class)]
protected MyRelatedModel $relatedModel = null;

linkedModel is resolved to foreign_table during TCA generation. Additionally, properties like foreign_field and mm_opposite_field accept property names. These will be converted to column names.

If a scenario could not be covered by the attributes, the generated TCA can be extended and modified in the usual way with TCA files in established locations. The loading order during TCA generation would be as follows:

  1. TCA attributes
  2. Configuration/TCA/
  3. Configuration/TCA/Overrides/

As the final TCA is cached, the more complex process only has a minimal impact on performance.

No data to display

Actions

Also available in: Atom PDF