Feature: #104002 - Schema API
See forge#104002
Description
A new Schema API is introduced to access information about TCA structures in a unified way.
The main goal of this architecture is to reduce direct access to
$GLOBALS
after the Bootstrap process is completed.
The Schema API implements the following design goals:
- An object-oriented approach to access common TCA information such as if a database table is localizable or workspace-aware, if it has a "deleted" field ("soft-delete"), or other common functionality such as "enableFields" / "enablecolumns", which can be accessed via "Capabilities" within a Schema.
-
A unified way to access information which "types" a TCA table has available, such as "tt_content", where the "CType" field is the divisor for types, thus, allowing a Schema to have sub-schemata for a TCA Table.
The API in turn then handles which fields are available for a specific "CType". An example is "tt_content" with type "textpic": The sub-schema "tt_content.textpic" only contains the fields that are registered of that "CType", such as "bodytext", which then knows it is a Rich Text Field (the default column does not have this information), or "image" (a file relation field), but the sub-schema does not contain fields that are irrelevant for this type, such as "assets" (also a file relation field).
-
An abstracted approach to available TCA field types such as "input" or "select", which also takes information into account, if a select field is a selection of a static list (such as "pages.layout") or if it contains a relation to another schema or field (based on "foreign_table"). Previously, this was evaluated in many places in TYPO3 Core, and can now be reduced.
Thus, Schema API can now be utilized to determine the
Relationship
of a relational field type in a unified way without having to deal with deeply nested arrays.Type -
Information about relations to other database tables or fields. This is especially useful when dealing with Inline elements or category selection fields.
Schema API can find out, which fields of other schemata are pointing to one-self. Schema API differentiates between an "Active Relation" and a "Passive Relation". An Active Relation is the information that a field such as "pages.media" (a field of type "file") contains a reference to the "sys_file_reference.uid_foreign" field. Active Relations in consequence are connected to a specific field (of type
Relational
).Field Type Interface In turn, a "Passive Relation" is the information what other schemata/fields are pointing to a specific table or field.
A common example of a "Passive Relation" is "sys_workspace_stage": The information stored in
$GLOBALS
does not contain the information that this table is actually used as a reference from the database field[TCA] [sys_ workspace_ stage] sys_
, theworkspace. custom_ stages sys_
Schema now contains this information directly viaworkspace_ stage Tca
. This is possible as TcaSchemaFactory is evaluating all TCA information and holistically as a graph. Passive Relations are currently only connected to a Schema, and Active Relations to a Field or a Schema.Schema->get Passive Relations () As the Schema API fetches information solely based on the TCA, an Active Relation only points to possible references, however, the actual reference (does a record really have a connection to another database table) would require an actual Record instance (a database row) to evaluate this information.
Relations do not know about the "Type" or "Quantity" (many-to-many etc) as this information is already stored in the Field information. For this reason, the "Relations" currently only contain a flat information structure of the table (and possibly a field) pointing TO another schema name (Active Relation) or FROM another schema name / field (Passive Relation).
Schema API also parses all available FlexForm data structures in order to resolve relations. As a result, a field of type FlexFormField contains a list of possible "FlexFormSchema" instances, which resolve all fields, sheets and section containers within each data structure.
-
Once built, the Schema can never be changed. Whereas the TCA could be overridden at runtime, all TCA is now evaluated once and then cached. This is a consequence of working with an object-oriented approach.
If the TCA is changed after the Bootstrap process is completed, the Schema needs to be rebuilt manually, which TYPO3 Core currently does, for example, in some Functional Testing Scenarios.
All key objects (Schema, FieldType, Capabilities) are treated as immutable DTOs and never contain cross-references to their parent objects (Sub schemata do not know information about their parent schema, a field does not know which schema it belongs to), so the only entry point is always the
Tca
object.Schema Factory This design allows the API to be fully cacheable at PHP level as a nested tree.
-
Low-level, not full-fledged but serves as a basis.
Several API decisions were made in order to let Schema API keep only its original purpose, but can be encapsulated further in other APIs:
- Schema API is not available during Bootstrap as it needs TCA to be available and fully finished.
- Schema API does not contain all available TCA properties for each field type. An example is "renderType" for select fields. This information is not relevant when querying records in the frontend, and mainly relevant for FormEngine - it is not generic enough to justify a getter method.
- Extensibility: custom field types are currently not available until TYPO3 Core as fully migrated to Schema API.
- User Permissions: Evaluating if a user has access to "tt_content.bodytext" requires information about the currently logged in user, thus it is not part of the Schema API. A "Permission API" should evaluate this information in the future.
- Available options for a field. As an example, a common scenario is to find out
which possible options are available for "pages.backend_layout". In TYPO3 Core
an
items
is connected to that field in TCA. Whether there is anProc Func items
is stored, but Schema API is not designed to actually execute the itemsProcFunc as it is dependent on various factors evaluated during runtime, such as the page it resides on, user permissions or PageTsConfig overrides.Proc Func
Schema API is currently marked as internal, as it might be changed during TYPO3 v13 development, because more parts of TYPO3 will be migrated towards Schema API.
DataHandler and the Record Factory already utilize Schema API in order to reduce direct access to
$GLOBALS
.[TCA] In the future Schema API might be used to evaluate information for Site Configurations, like TCA and FlexForms.
Impact
Reading and writing $GLOBALS
within Configuration/
and via TCA Overrides is untouched, as the API is meant for reading the
information there in a unified way.
Usage
The API can now be used to find out information about TCA fields.
public function __construct(
protected readonly PageRepository $pageRepository,
protected readonly TcaSchemaFactory $tcaSchemaFactory
) {}
public function myMethod(string $tableName): void
{
if (!$this->tcaSchemaFactory->has($tableName)) {
// this table is not managed via TYPO3's TCA API
return;
}
$schema = $this->tcaSchemaFactory->get($tableName);
// Find out if a table is localizable
if ($schema->isLocalizable()) {
// do something
}
// Find all registered types
$types = $schema->getSubSchemata();
}
Using the API improves handling for parts such as evaluating columns
,
foreign field structures, FlexForm Schema parsing, and evaluating type fields
for database fields.