Backend relation scoping 

What the scoping does for editors is described in Backend relation scoping. This page covers how it is wired and what to decide when a record kind is added.

To achieve a seamless integration, TCA and Flexform are manipulated after being compiled and the result is then cached. PSR-14 events take care of the manipulation. The final result can be inspected via the Sites -> Page TSconfig and Configuration -> TCA backend modules.

The criterion 

\WerkraumMedia\ThueCat\Service\SiteScopedSelectFields decides which fields are scoped and what clause they carry. A column matches when it is a select field, its foreign_table is listed in SiteScopedSelectFields::SCOPED_TABLES , and it is not the table's translation parent (ctrl.transOrigPointerField).

A matching column receives two conditions on the foreign table:

AND {#<foreign_table>}.{#pid} IN (###PAGE_TSCONFIG_IDLIST###)
AND {#<foreign_table>}.{#sys_language_uid} IN (0, -1)
Copied!

Each condition is appended to the column's existing foreign_table_where only when that clause does not already state it, compared with whitespace removed. Whatever else the clause holds stays untouched.

Event listeners 

Three PSR-14 listeners apply the criterion. Each one derives the fields from it rather than from a list, so the fields carrying the clause and the fields receiving an id list cannot drift apart.

SiteScopedRelationsTcaListener on AfterTcaCompilationEvent
Writes the clause into every matching column of every table in the compiled TCA.
SiteScopedRelationsFlexFormListener on AfterFlexFormDataStructureParsedEvent
Writes the clause into matching fields of each parsed FlexForm sheet, so a content element selecting ThueCat records is scoped too. A sheet has no ctrl, so no field there is excluded as a translation parent.
SiteScopedRelationsPageTsConfigListener on ModifyLoadedPageTsConfigEvent

Supplies the value of ###PAGE_TSCONFIG_IDLIST###. Core resolves the marker per table and field and offers no wildcard, so the listener emits one line per scoped field:

TCEFORM.<table>.<field>.PAGE_TSCONFIG_IDLIST = <ids>
TCEFORM.<table>.<flexField>.<recordType>.<sheet>.<field>.PAGE_TSCONFIG_IDLIST = <ids>
Copied!

FlexForm field names containing a dot, such as settings.towns , are escaped, because TSconfig reads the dot as a path separator. The FlexForm data structure is parsed per record type; a type whose structure cannot be resolved contributes no lines.

The ids are the pages of the site holding the current page, the deepest entry of the rootline, resolved by \WerkraumMedia\ThueCat\Service\SitePageIds — the service the import uses for the same question. A page outside any site yields 0: an unresolved marker would leave the clause offering the whole table.

The type-ahead wizard is limited by TCEFORM.suggest.default.addWhere in Configuration/page.tsconfig, reading the same marker. Its columns are unqualified, because the wizard queries one table at a time, while the dropdown's query joins and needs the table name.

Core's SuggestWizardController ignores a field's foreign_table_where while TSconfig sets an addWhere. The language condition is therefore part of the TSconfig block as well: fields carrying it only in their own foreign_table_where would lose it on the wizard while keeping it on the dropdown.

Category and keyword fields are not part of this mechanism. Their tree start is resolved by the form data provider \WerkraumMedia\ThueCat\Typo3\FormDataProvider\AnchorStartingPoints from the ###THUECAT_ANCHOR### marker, see Category and keyword trees.

Adding a record kind 

SCOPED_TABLES is the statement of what counts as a ThueCat record, and it is maintained by hand.

When a new record kind is introduced, decide whether its table belongs in that list. Nothing detects the omission: a relation field pointing at a table missing from it keeps working and offers the records of the whole installation, in every site, on both the dropdown and the suggest wizard.

Adding the table is the usual answer, but not automatic. A table deliberately shared across sites, or one never used as a relation target, is correctly left out.

Append \WerkraumMedia\ThueCat\Service\SiteScopedSelectFields::SCOPED_TABLES with the new table, this is all it takes.