Feature #104589
openTCA generation for domain models by php attributes
0%
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
- https://github.com/phantasie-schmiede/psb-foundation/tree/main/Classes/Attribute/TCA
- https://github.com/phantasie-schmiede/psb-foundation/blob/main/Classes/Service/Configuration/TcaService.php (method buildFromAttributes)
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:
- TCA attributes
- Configuration/TCA/
- Configuration/TCA/Overrides/
As the final TCA is cached, the more complex process only has a minimal impact on performance.