Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
b901041
Refactor: Introduce `SimpleEquationFilterType` and `AbstractFilterTyp…
ericges Apr 28, 2026
83ab235
Chore: Enable strict types in FilterType classes
ericges Apr 28, 2026
1315dec
Feat: Add initial filter builder and interfaces for FlareBundle
ericges Apr 30, 2026
fe56afe
Feat: Introduce `FilterTypeInterface`, `AbstractFilterType`, and `Sim…
ericges Apr 30, 2026
37df913
refactor: update filter handling and introduce new filter types and e…
ericges May 1, 2026
8d1cd50
refactor: remove unused FilterFactoryInterface and update mago.toml w…
ericges May 1, 2026
9331166
refactor: update mago.toml by refining paths and fix missing newline …
ericges May 1, 2026
bb30f1f
refactor: enhance type handling in AbstractFilterElement and DcaHelpe…
ericges May 1, 2026
6dd8529
Chore: Add PHPStan ignore for Symfony Config template defaults
ericges Jul 13, 2026
99462b6
refactor!: element-owned filter architecture
ericges Jul 13, 2026
38fba43
refactor: consolidate filter namespace and align naming conventions
ericges Jul 13, 2026
f813922
test: add comprehensive unit tests for Filter, FilterOptionsResolver,…
ericges Jul 13, 2026
ef7d612
Enable strict types, implement `CallbackChoiceLoader`, and improve fi…
ericges Jul 13, 2026
cee10fa
refactor: remove unused `DcaContract` implementation from `CodefogTag…
ericges Jul 13, 2026
9eb6e18
refactor: rename `AbstractFilterFilterElement` to `AbstractFilterElem…
ericges Jul 13, 2026
e9cd754
refactor: rename filter element classes to include `Filter` suffix an…
ericges Jul 13, 2026
31235da
refactor: rename `FilterConfigResolverTest` to `FilterOptionsResolver…
ericges Jul 13, 2026
289a360
refactor: restructure filter resolver namespace and update references
ericges Jul 14, 2026
ed767a8
feat: add transformer machinery for canonical config translation
ericges Jul 14, 2026
6950043
refactor: replace `configFromRow` with transformer cycle and remove p…
ericges Jul 14, 2026
8c7a658
feat: add Lists domain — `ListSpec` DTO, `ListBuilder`, per-type list…
ericges Jul 14, 2026
b3e6f41
refactor: replace `ListSpecification` with immutable `ListSpec` built…
ericges Jul 14, 2026
22b5511
refactor: rename `ConfigureQueryContract` to `BuildQueryContract`
ericges Jul 14, 2026
4f8a93a
test: cover transformer machinery and Lists domain; update AGENTS.md
ericges Jul 14, 2026
8270fd2
refactor: exact-class precedence in `TransformerBuilder::resolve()`; …
ericges Jul 14, 2026
8afb1e7
refactor: rename `Lists` namespace to singular `List`
ericges Jul 14, 2026
bdb4076
refactor: add missing imports, normalize namespaces, fix type names a…
ericges Jul 14, 2026
0a45ce0
refactor: replace `TransformerBuilder` with `TransformerResolver`, in…
ericges Jul 14, 2026
0d642bc
refactor: replace `TransformerBuilder` with `TransformerResolver` and…
ericges Jul 14, 2026
c122973
test: align tests with `TransformerResolver` API and `(ConfigBuilder,…
ericges Jul 14, 2026
501b76e
fix mago lint findings
ericges Jul 14, 2026
ee7bef2
add clarification comment for PHPStan ignore annotation
ericges Jul 14, 2026
da44504
refactor: add `from_enabled`/`to_enabled` options to `DateRangeFilter…
ericges Jul 14, 2026
edb1dd7
refactor: replace `intrinsicOnly` attribute with `IntrinsicContract` …
ericges Jul 14, 2026
61df0e7
refactor: streamline ChoicesBuilder usage and remove redundant option…
ericges Jul 14, 2026
1588748
refactor: introduce `FilterFormBuilderInterface` to handle single-fie…
ericges Jul 15, 2026
81d4c72
refactor: move `FilterFormBuilder` and `FilterFormFactory` to `Filter…
ericges Jul 15, 2026
be917f4
refactor: extract `Config\SchemaResolver`
ericges Jul 15, 2026
0397841
refactor: make `ListOptionsResolver` and `FilterOptionsResolver` `fin…
ericges Jul 15, 2026
b41a295
refactor: extract `List\Resolver\ListTransformerResolver`
ericges Jul 15, 2026
c8ead4a
feat: dispatch `ListTransformerEvent` from `ListTransformerResolver`
ericges Jul 15, 2026
16fb33b
refactor: consolidate `ListType` to `ListDriver` terminology and upda…
ericges Jul 15, 2026
94a2717
refactor: rename `ListType` to `ListDriver` in translation files
ericges Jul 15, 2026
5a2e77a
refactor: fix usages missed in the ListDriver/ListSpecBuilder rename,…
ericges Jul 15, 2026
2450785
refactor: rename `ListType` to `ListDriver` across the codebase
ericges Jul 15, 2026
2002692
refactor: centralize `ListDriverReference` handling, replace inline c…
ericges Jul 15, 2026
5407cbe
feat: add PHPUnit CI workflow and configuration
ericges Jul 15, 2026
3646040
docs: improve README formatting and emphasize description
ericges Jul 15, 2026
787361b
docs: add security CI badge to README
ericges Jul 15, 2026
0d41df8
refactor: replace `type` with `driver` in ListSpec and rename `getDat…
ericges Jul 16, 2026
cfca7a5
refactor: remove obsolete classes and interfaces related to ListDrive…
ericges Jul 17, 2026
38d3b90
refactor: rename `ListType` namespaces to `ListDriver` and update rel…
ericges Jul 17, 2026
d089e1e
refactor: replace `getDataContainerName` method with `dc` property ac…
ericges Jul 17, 2026
f64176c
refactor: mark filter-related classes as `final` and enhance immutabi…
ericges Jul 17, 2026
ef66a59
refactor: replace `hasFilterOfType` with `hasFilterInstance` for impr…
ericges Jul 17, 2026
21724d6
refactor: replace `DcaBuilder` with `DcaBuilderInterface` across all …
ericges Jul 17, 2026
39065f7
add `test` target to Makefile and update AGENTS.md to document its usage
ericges Jul 17, 2026
4949a22
refactor: streamline type handling across ListDriver and FilterElemen…
ericges Jul 18, 2026
6f2cddc
refactor: update tests to reflect recent Filter and ListSpec type han…
ericges Jul 18, 2026
5bc8e51
refactor: replace getters and setters with public readonly properties…
ericges Jul 18, 2026
bb6e784
fix: model validation logic in `LinksToReaderTrait`
ericges Jul 18, 2026
12a386e
refactor: remove redundant element parameter from Filter and adjust r…
ericges Jul 18, 2026
7fab61f
refactor: replace `ChildDefinition` with `setAlias` for FilterElement…
ericges Jul 18, 2026
c2cb570
refactor: enhance immutability and streamline type handling across mu…
ericges Jul 18, 2026
9eca4d4
refactor: improve headline processing and HTML tag handling in `Str`,…
ericges Jul 19, 2026
5940ad6
refactor: remove unused imports and redundant constructor dependencie…
ericges Jul 19, 2026
71c57d8
add combined audit findings documentation for tests, CI, security, ar…
ericges Jul 19, 2026
1ca2243
refactor: improve null safety in context constructors, introduce `Ent…
ericges Jul 20, 2026
807793b
feat: add duplicate filter alias detection and improve ListDriver res…
ericges Jul 20, 2026
417309e
refactor: standardize `FlareException` method parameter usage across …
ericges Jul 21, 2026
f222f99
refactor: improve error handling and type consistency in List and Rea…
ericges Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
56 changes: 56 additions & 0 deletions .audit/260719012-combined/00-uebersicht.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Kombiniertes Audit: contao-flare-bundle — Branch `feat/filter-types`

**Datum:** 2026-07-20 · **Stand:** Commit `5940ad6`
**Quellen:** `.audit/2607171801-claude/` und `.audit/2607171755-codex/` (beide vom 2026-07-17, Review-Commit `39065f73`)

## Methodik

Jeder Punkt beider Audits wurde gegen den aktuellen Code (`5940ad6`) verifiziert. Enthalten sind **ausschließlich weiterhin valide Punkte** mit aktuellen Datei-/Zeilen-Belegen; inzwischen behobene sowie widerlegte Punkte wurden entfernt, Duplikate beider Audits zusammengeführt. Positive Beobachtungen stehen separat in [99-positive-punkte.md](99-positive-punkte.md), damit die actionable Dateien schlank bleiben.

Seit dem Audit-Datum wurden mehrere der ursprünglichen Top-Findings behoben — darunter der `?_preview`-Feld-Dump, die verlorene Listen-ID im `ListSpec`-Pfad, die Transformer-Memoization pro Klasse, das Suche-verwirft-sich-selbst-Kernproblem und der `'0'`-Verlust im `ChoicesBuilder`. Die Kapitel Tests/CI und Performance/Stabilität sind dagegen vollständig unverändert offen.

## Die Dateien

| Datei | Thema | Schwerste offene Findings |
|---|---|---|
| [10-architektur.md](10-architektur.md) | Architektur & Design | Terminal42 als toter, nicht kompilierbarer Code (A-01); stale AGENTS.md (A-02) |
| [20-korrektheit.md](20-korrektheit.md) | Korrektheit & Bugs | Boolean-Binary-Modi nicht implementiert (K-01), unabwählbarer Preselect (K-02), Kalender-Datumsgrenzen ignoriert (K-03), totes Stop-Word-Feature (K-07), `'0'`-Verluste (K-08) |
| [30-sicherheit.md](30-sicherheit.md) | Security & Query-Safety | Model-Registry umgeht `start`/`stop`-Fenster (SEC-01); Backend-Ausgabe teils unescaped (SEC-03) |
| [40-performance-stabilitaet.md](40-performance-stabilitaet.md) | Performance & Stabilität | 500er statt Degradierung im Render-Pfad (PS-01), positionaler Entry-Cache (PS-02), DBAL-Constraint (PS-03), Calendar-OOM-Potenzial (PS-15/16), doppelte Query-Pipeline (PS-14) |
| [50-tests-ci.md](50-tests-ci.md) | Tests, CI & Tooling | Query-Schicht/Filter-Types/Engine ungetestet (T-01), Compatibility-Gate durch `continue-on-error` entwertet (CI-02), PHPUnit nur PHP 8.2 (CI-01) |
| [60-contao-integration-doku.md](60-contao-integration-doku.md) | Contao-Integration, API, Doku & Kompatibilität | Doku-Beispiele mit Fatal Error (C-01), Intrinsic-DX-Falle (C-02), tote DB-Felder der Terminal42-Integration (C-03), rohe Backend-Labels (C-04) |
| [99-positive-punkte.md](99-positive-punkte.md) | Positivbefunde (nicht actionable) | — |

## Priorisierung (konsolidiert, nur offene Punkte)

### Vor dem Merge fixen

1. **DBAL-Constraint `^2.13 || ^3.0` erlaubt Versionen ohne `ArrayParameterType`** → Fatal auf Contao 4.13; Fix ist eine Zeile: `^3.6 || ^4.0` (PS-03, C-05).
* Gefixt.
2. **Render-Pfad-Stabilität:** `createView()` läuft erst im Template; Laufzeitfehler eines kaputten Filters reißt die Seite in einen 500er — `createView()` in den Controller ziehen bzw. `FlareException` beim Rendern abfangen; dazu 200-vs-500-Inkonsistenz Listview/Reader (PS-01, PS-05).
* Nein: Dieses Verhalten ist exakt richtig. Unbehandelte Exceptions sorgen für Fehler 500, auch vom Template aus.
3. **Entry-Cache positional statt per ID indiziert** — falscher Datensatz im Reader-Pfad möglich, öffentliche API (PS-02).
4. **Doku-`buildDca()`-Beispiele erzeugen Fatal Error** (konkrete Klasse statt `DcaBuilderInterface`; C-01).

### Zeitnah (Korrektheit der namensgebenden Features)

5. **BooleanFilterElement:** `NULL_FALSE`/`TRUE_FALSE` nicht implementiert, unabwählbarer Preselect, „CBX"-Label, rohe Backend-Keys (K-01, K-02, K-11, C-04).
6. **CalendarCurrentFilterElement:** numerische Datumsgrenzen wirkungslos, kein Gating durch `configure_*`, ungefangene Exception (K-03, K-04, K-05).
7. **Suche:** nur-leere Suchgruppen → `ArgumentCountError` (K-06); Stop-Word-Feature komplett tot — Parameter existiert nie (K-07).
8. **`'0'`-/falsy-Verluste in den Choice-Pfaden** inkl. Label-Kollisionen (K-08, K-09).
9. **Sichtbarkeit:** still geskippte intrinsische Filter (PS-08), Registry-Shortcut umgeht `start`/`stop` (SEC-01), fehlende Generic-Driver-Warnung im No-Parent-Zweig (SEC-02), Preview-Modus ignoriert (PS-09).
10. **Intrinsic-Pflichtmuster** in Interface-Docblock/zentralem Guard verankern; Migrationsdoku um Alias-Skip + Intrinsic-Verlagerung ergänzen (C-02, C-06).

### Vor dem ersten Stable-Release

11. **Testabdeckung der Risikozonen:** `src/Query/` (SQL-Leitplanken!), Filter-Types, Engine-Pipeline, Paginator, ChoicesBuilder; Regressionstests für K-01–K-08 gleich mitnehmen; Stubs autoloadbar machen, Random-Order aktivieren (T-01, T-02, T-03).
12. **CI reparieren:** `continue-on-error` raus, PHPUnit-Matrix (lowest-deps + Contao 4.13), `pull_request`-Trigger, `composer audit` ohne `|| true`, Mago wieder inkl. `tests/` (CI-01–CI-05).
13. **Terminal42-Integration entscheiden:** portieren oder entfernen — toter, nicht kompilierbarer Code plus tote DB-Felder, unsichtbar nur dank PHPStan-Excludes (A-01, C-03).
14. **Public-API-/DX-Politur:** Registry-Vereinheitlichung, `#[TaggedIterator]`-Ablösung, `PaginatorConfig`-TypeErrors und Off-by-one, Alias-Kollisions-Warning, Übersetzungslücken/Waisen (A-03–A-16, K-12, K-13, C-07–C-19).

### Performance-Backlog (kein Blocker, aber lohnend)

- Filter-Pipeline-Ergebnis request-scoped teilen — Count + Entries + Partials rechnen bis zu 3× dasselbe (PS-14, PS-17, PS-21).
- Calendar-Integration: SQL-seitiges Zeitfenster + harte Occurrence-Obergrenze — Full-Fetch ×2 + unbegrenzte Expansion = OOM-Risiko durch Redakteurs-Eingabe (PS-15, PS-16).
- Shared-Service-Caches via `kernel.reset` leeren — sonst stale unter Worker-Runtimes (PS-07).
- Choices begrenzen (LIMIT/Suche/Ajax) und O(n²)-Wertauflösung beheben (PS-19, PS-20).
120 changes: 120 additions & 0 deletions .audit/260719012-combined/10-architektur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Architektur & Design

Kombinierte, am Stand `5940ad6` (2026-07-20) verifizierte Findings aus beiden Audits (claude 2607171801, codex 2607171755). Die ursprünglichen Top-Findings beider Audits — verlorene Listen-ID im `ListSpec`-Pfad (Formularnamen-Kollision) und Transformer-Memoization pro Klasse statt (Klasse, Typ) — sind inzwischen behoben und daher hier nicht mehr enthalten. Positive Beobachtungen: siehe [99-positive-punkte.md](99-positive-punkte.md).

## A-01: Terminal42-ChangeLanguage-Integration ist toter, nicht kompilierbarer Code — Major (beide Audits)

Der Listener importiert fünf nicht existierende Klassen (`Event\AbstractFetchEvent`, `Event\FetchAutoItemEvent`, `Event\FetchCountEvent`, `Event\FetchListEntriesEvent`, `Query\ListQueryBuilder`), abonniert nie dispatchte Event-Namen und benutzt die entfernte Fetch-API (`getListQueryBuilder()`, `getFilters()`, `getContentContext()`). Das Laden der Integration ist auskommentiert; PHPStan excludiert das Verzeichnis komplett und ignoriert `class.notFound` für `src/Integration/` — der Bruch bleibt systematisch unsichtbar. Nebenbefund: Klasse/Namespace `DcMultilingualListType` tragen als letzte Stelle das alte `ListType`-Vokabular (Attribut ist bereits `#[AsListDriver]`).

**Entscheidung nötig: portieren oder entfernen.**

- `src/Integration/Terminal42Languages/EventListener/ChangelanguageListener.php:13-17,22` (tote Imports), `:92,116` (nie dispatchte Events), `:70,100-101,108-109,119-129` (entfernte API)
- `src/DependencyInjection/HeimrichHannotFlareExtension.php:43-45` (auskommentierter Loader)
- `phpstan.neon:13,18-20` · `src/Integration/Terminal42Languages/ListType/DcMultilingualListType.php:16-19`

## A-02: AGENTS.md/CLAUDE.md beschreiben nicht mehr existierende APIs — Minor (claude)

Doku-Drift gegen den aktuellen Code: `ListBuilderFactory` heißt `ListSpecBuilderFactory`; `#[AsListType]` heißt `AsListDriver`; `ListTypeRegistry` heißt `ListDriverRegistry`; `FilterElementResolver` existiert nicht; „EngineFactory creates Engine with appropriate Context" ist falsch — die Factory erhält den Context als Parameter (`src/Engine/Factory/EngineFactory.php:21-29`). Dazu Doc-Drift im Code: Verweis auf `DcaContract::configureDca()`, die Methode heißt `buildDca()` (`src/EventListener/Contao/ElementDcaListener.php:24` vs. `src/Contract/DcaContract.php:18`).

- `AGENTS.md:21,43,55,60,71`

> ## A-03: Registry-Duplikation und heterogene Lookup-Semantik — Minor (claude)
>
> `FilterElementRegistry` und `ListDriverRegistry` sind strukturell nahezu identisch (gleiches `add`/`remove`/`prune`/`typesByClass`-Muster) — Kandidat für Basis/Trait. Daneben drei weitere Stile: `FilterTypeRegistry` (TaggedIterator, Key = Klassenname), `EngineModRegistry` (TaggedIterator, `defaultIndexMethod: 'getType'`), `ProjectorRegistry` (`supports()`/`priority()`-Scan). Fünf Registries, vier Lookup-Semantiken.
>
> - `src/Registry/FilterElementRegistry.php:39-57` vs. `src/Registry/ListDriverRegistry.php:34-52` · `src/Registry/FilterTypeRegistry.php:25-28,53` · `src/Registry/EngineModRegistry.php:15` · `src/Registry/ProjectorRegistry.php:28-63`
>
> **Nutzer-Antwort: Das ist kein Design-Fehler, sondern eine Konvention. Einzelne Klassen sorgen für Typsicherheit. Die Klassen sind atomar und benötigen künftig keiner Feature-Erweiterung, daher keine gemeinsame Basisklasse.**

> ## A-04: `PaginatorConfig`: latenter `TypeError` in `count()` + deprecated `\Serializable` — Minor (claude)
>
> `count(): int` gibt `getLastPageNumber(): ?int` zurück — `TypeError` bei `itemsPerPage < 1` oder unbekanntem `totalItems`. Zusätzlich implementiert die Klasse das deprecated `\Serializable`-Interface mit `serialize()`/`unserialize()` neben `__serialize`/`__unserialize`.
>
> - `src/Paginator/PaginatorConfig.php:192-195` (`count()`), `:107-118` (`getLastPageNumber(): ?int`), `:7,197-205` (`\Serializable`)
>
> **Nutzer-Antwort: TypeError erledigt, \Serializable ist nicht deprecated, siehe folgende Notiz.**
> > As of PHP 8.1.0, a class which implements Serializable without also implementing __serialize() and __unserialize() will generate a deprecation warning.

> ## A-05: `InteractiveProjector`: COUNT-Query läuft vor der Invalid-Form-Prüfung — Minor (claude)
>
> Die Aggregations-COUNT-Query (`src/Engine/Projector/InteractiveProjector.php:50`) wird ausgeführt, bevor geprüft wird, ob das Formular invalid submitted wurde (`:56-58`) — pro invalidem Submit eine unnötige Query. Zudem wird `totalItems` unverändert an die View durchgereicht, sodass diese `totalItems > 0` bei leerem `InteractiveEmptyLoader` meldet (`:74-81`).
>
> **Nutzer-Antwort: Das ist kein Fehler. Da sich das Formular nicht auf die Aggregation-COUNT-Query auswirkt, muss die totale Anzahl der Elemente trotzdem berechnet werden.**

> ## A-06: Context-Verträge mit kleinen LSP/ISP-Brüchen — Minor (claude)
>
> `InteractiveContext::getPaginatorConfig(): PaginatorConfig` gibt das nullable Property ungeprüft zurück — `TypeError` bei programmatischer Konstruktion ohne Validator-Lauf (`src/Engine/Context/InteractiveContext.php:25,45-48`). Die readonly `ValidationContext` trägt einen No-op-Setter `setPaginatorQueryParameter()`, weil `PaginatedContextInterface` ihn erzwingt (`src/Engine/Context/ValidationContext.php:77-80`).
>
> **Nutzer-Antwort: PaginatorConfig nun korrekt null-safe, ValidationContext no-op-Setter ist korrekt für den Zweck.**

> ## A-07: Stille Alias-Kollision im Filter-Collector — Minor (claude)
>
> `$filters[$filter->alias] = $filter;` — zwei publizierte Filter derselben Liste mit gleichem Formular-Alias überschreiben sich kommentarlos; nur der letzte wird angewendet. Ein Kollisions-Warning fehlt (das Factory-Fehler-Warning existiert dagegen).
>
> - `src/List/Collector/ListModelFilterCollector.php:75`
>
> **Nutzer-Antwort: Im Backend wird nun ein Fehler ausgegeben, wenn zwei Filter mit demselben Alias publiziert werden.**

> ## A-08: `FlareException`: `method` vs. `source` inkonsistent — Minor (claude)
>
> Die Exception bietet beide Parameter (`src/Exception/FlareException.php:17-18`), der Code nutzt beide uneinheitlich mit demselben Inhalt (`__METHOD__`): Loader nutzen `method:` (`src/Engine/Loader/InteractiveLoader.php:52`, `AggregationLoader.php:52`), Projector/Views/Calendar-Integration `source:` (`src/Engine/Projector/AbstractProjector.php:124`, `src/Engine/View/HandlesModelsTrait.php:33,42,57,66,75`, `src/Integration/ContaoCalendar/Loader/EventsAggregationLoader.php:66`), `ValidationLoader` keins von beiden (`src/Engine/Loader/ValidationLoader.php:57,92`).
>
> **Nutzer-Antwort: Angeglichen -- method: __METHOD__, source, wenn verfügbar: table.id -- übertragen auf gesamte Codebase**

> ## A-09: `symfony/event-dispatcher` nicht direkt deklariert — Minor (claude, reduzierter Umfang)
>
> `FilterFormFactory` instanziiert direkt `new EventDispatcher()` (`src/Filter/Factory/FilterFormFactory.php:17,70`), deklariert ist aber nur `symfony/event-dispatcher-contracts` (`composer.json:17`); das konkrete Paket kommt nur transitiv über `contao/core-bundle`.
>
> **Nutzer-Antwort: Required in composer.json**

> ## A-10: `ValidationLoader::executeQuery()` liefert `[]` statt `null` bei abgebrochenem Query-Aufbau — Minor (claude)
>
> Bei `!$qb` wird `[]` zurückgegeben — harmlos (falsy), aber semantisch schief gegenüber dem `?array`-Vertrag, in dem `null` „nicht gefunden" bedeutet (`:117`: `return $entry ?: null;`).
>
> - `src/Engine/Loader/ValidationLoader.php:107-109`
>
> **Nutzer-Antwort: Return-type auf `array` angepasst.**

> ## A-11: Query-Assemblierung lebt in Event-Listener-Prioritäten ohne zentrale Übersicht — Info (claude)
>
> Select@490, Conditions@470, Page@430, Order@420, Join@-450; Integrations-Listener dazwischen (250/220/200/190/100). Die Gesamtordnung ist nirgends zentral dokumentiert (kein Pipeline-Kommentar im `ListQueryDirector`).
>
> - `src/EventListener/QueryStructModifier/SelectModifierListener.php:13`, `ConditionsModifierListener.php:11`, `PageModifierListener.php:11`, `OrderModifierListener.php:12`, `JoinModifierListener.php:10` · `src/Integration/ContaoCalendar/EventListener/CountEventsModifierListener.php:14` u. a.
>
> **Nutzer-Antwort: Das muss in einem zukünftigen PR nochmal überarbeitet werden.**

> ## A-12: `ViewInterface` ist leerer Marker; Aufrufer müssen downcasten — Info (claude)
>
> Das Interface ist leer (`src/Engine/View/ViewInterface.php:7-9`); `ReaderController` downcastet auf `ValidationView` (`src/Controller/ContentElement/ReaderController.php:127`). Die `@template`-Annotationen sind nur mit dem `generics.noParent`-Ignore in PHPStan haltbar.

> ## A-13: `#[TaggedIterator]` ist seit Symfony 7.1 deprecated — Info (claude)
>
> Genutzt in drei Registries; relevant für Deprecation-Logs bei Support-Matrix ^5.4|^6|^7. Nachfolger `AutowireIterator` existiert erst ab 6.3 → für die Matrix ggf. `!tagged_iterator` in YAML.
>
> - `src/Registry/EngineModRegistry.php:15` · `src/Registry/ProjectorRegistry.php:19` · `src/Registry/FilterTypeRegistry.php:18`
>
> **Nutzer-Antwort: Passt so.**

> ## A-14: Statische Contao-Aufrufe in Context-DTOs — Info (claude, reduzierter Umfang)
>
> `PageModel::findByPk` in wertartigen Context-Objekten — DB-Zugriffe, testfeindlich, aber Contao-idiomatisch.
>
> - `src/Engine/Context/ReaderUrlConfigCreatorTrait.php:18` · `src/Engine/Context/ValidationContext.php:44`
>
> **Nutzer-Antwort: Weiterhin statische Aufrufe, aber nun besser gekapselt.**

> ## A-15: Backend-Responses ohne Null-Check auf `$listModel` — Info (claude)
>
> `getRelated()` kann `null` liefern; der Catch deckt nur Exceptions ab. Danach werden `$listModel->title` / `trans($listModel->type)` ungeprüft dereferenziert — in beiden Controllern. (Gelöschte/fehlende Liste → Backend-Crash; siehe auch SEC-03 in [30-sicherheit.md](30-sicherheit.md).)
>
> - `src/Controller/ContentElement/ReaderController.php:220-236` (Zugriff `:232-233`) · `src/Controller/ContentElement/ListViewController.php:154-168` (Zugriff `:166-167`)
>
> **Nutzer-Antwort: Good Catch! Ist jetzt mit einer entsprechenden Warnung gesichert.**

> ## A-16: `Engine`-Mods-API mischt Semantiken — Info (claude)
>
> `addMod()` appendet numerisch, `setMod()`/`unsetMod()` arbeiten mit String-Keys im selben Array; `unsetMod()` kann appendete Mods nicht adressieren — öffentlicher `@api`-Punkt.
>
> - `src/Engine/Engine.php:66-93`
>
> **Nutzer-Antwort: Das ist kein Fehler sondern explizit so gewollt. Der Nutzer hat die Wahl, Filter für mehrfache veränderung überschreibbar zu machen, oder nicht. In den meisten Fällen wird das nicht gebraucht, daher reicht Listenindexierung ohne Möglichkeit zur Änderung.**
Loading
Loading