Skip to content

Feat/filter types - #20

Open
ericges wants to merge 71 commits into
mainfrom
feat/filter-types
Open

Feat/filter types#20
ericges wants to merge 71 commits into
mainfrom
feat/filter-types

Conversation

@ericges

@ericges ericges commented May 1, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces significant refactoring and cleanup to the codebase, focusing on backend configuration, dependency injection, and code quality. The main changes include the removal of several legacy or redundant contracts, the introduction of a new DCA (Data Container Array) configuration API, and updates to service definitions and code quality settings.

Backend configuration and DCA API:

  • Introduced a new DCA configuration API with DcaBuilder, DcaBuilderInterface, and DcaContext to standardize and streamline backend configuration for filter elements and list types. This includes the new DcaContract interface for elements that configure their Contao backend appearance. (src/DataContainer/Builder/DcaBuilder.php [1] src/DataContainer/Builder/DcaBuilderInterface.php [2] src/DataContainer/Builder/DcaContext.php [3] src/Contract/DcaContract.php [4]

  • Removed the legacy PaletteContract and related configuration classes, as well as several filter element contracts, in favor of the new DCA API. (src/Contract/PaletteContract.php [1] src/Contract/Config/PaletteConfig.php [2] src/Contract/Config/ListItemProviderConfig.php [3] src/Contract/FilterElement/FormDataContract.php [4] src/Contract/FilterElement/FormTypeOptionsContract.php [5] src/Contract/FilterElement/HydrateFormContract.php [6] src/Contract/FilterElement/IntrinsicValueContract.php [7] src/Contract/FilterElement/RuntimeValueContract.php [8]

Dependency injection and service configuration:

  • Updated services.yaml to exclude new directories (DataContainer/Builder, a filter element file) from autowiring and removed the now-unneeded FilterInvokerResolver service definition. (config/services.yaml [1] [2] [3]

Code quality and static analysis:

  • Updated mago.toml to restrict source paths to only src/, add an assertion style rule, and improve static analysis configuration. (mago.toml [1] [2]

Collection and utility classes:

  • Removed the now-unused AbstractCollection and FilterDefinitionCollection classes, likely as part of the refactoring and simplification. (src/Collection/AbstractCollection.php [1] src/Collection/FilterDefinitionCollection.php [2]

These changes collectively modernize the backend configuration approach, remove dead code, and improve maintainability.This pull request introduces a significant refactor of the filter system, focusing on renaming and replacing the FilterDefinition concept with ConfiguredFilter, and removing the custom filter invoker attribute/registration system. It also cleans up configuration and code style, and removes now-unnecessary files related to filter invoker registration.

Key changes:

Filter System Refactor

  • Replaced all uses of FilterDefinition with ConfiguredFilter throughout the codebase, including type hints, method signatures, and documentation. The collection class was renamed from FilterDefinitionCollection to ConfiguredFilterCollection, with corresponding updates to methods and type annotations. (src/Collection/ConfiguredFilterCollection.php, [1] [2] [3] [4] [5] [6]; src/Contract/FilterElement/HydrateFormContract.php, [7]; src/Contract/FilterElement/IntrinsicValueContract.php, [8] [9]; src/Contract/FilterElement/RuntimeValueContract.php, [10] [11]; src/DataContainer/FilterContainer.php, [12] [13] [14] [15]

  • Removed the AsFilterInvoker attribute and the compiler pass RegisterFilterInvokersPass, effectively eliminating custom filter invoker registration via attributes. Related service configuration and autoconfiguration were also cleaned up. (src/DependencyInjection/Attribute/AsFilterInvoker.php, [1]; src/DependencyInjection/Compiler/RegisterFilterInvokersPass.php, [2]; config/services.yaml, [3]; src/DependencyInjection/HeimrichHannotFlareExtension.php, [4] [5]

Configuration and Code Style

  • Updated mago.toml to only include the src/ directory in the source paths and added a rule for assertion style. (mago.toml, [1] [2]

  • Minor code cleanup, such as removing unnecessary comments and ignoring obsolete PHPStan directives. (src/DependencyInjection/Configuration.php, src/DependencyInjection/Configuration.phpL17)


These changes modernize and streamline the filter system, making it more consistent and easier to maintain by relying on the new ConfiguredFilter model and removing legacy invoker registration code.

@ericges
ericges force-pushed the feat/filter-types branch from bc68fe1 to 5122442 Compare May 1, 2026 18:00
@ericges
ericges force-pushed the feat/filter-types branch from 374d0e0 to 43c7da1 Compare May 28, 2026 14:14
@ericges
ericges force-pushed the feat/filter-types branch from 43c7da1 to bb30f1f Compare July 13, 2026 11:51
ericges added 9 commits July 13, 2026 13:55
Filter elements now own their entire lifecycle: form building on native
Symfony FormBuilderInterface sub-builders, config schema + DCA-row
translation via ConfigContract (OptionsResolver), data-to-options
transformation in buildFilter(builder, context, data), and backend DCA
configuration via DcaContract::configureDca() on both tl_flare_filter
and tl_flare_list.

- Replace ConfiguredFilter/ConfiguredFilterCollection with immutable
  Filter DTO held as plain keyed array on ListSpecification
- Remove FilterInvocation, FilterFormBuilder, Hydrate/FormData/
  Intrinsic/RuntimeValue/FormTypeOptions contracts, and the entire
  AsFlareCallback/palette machinery (PaletteContract, PaletteEvent,
  callback registry, MethodInjector)
- Add standalone filter channels: Filter::fromCallback()/fromType()
  and flare_make_filter() Twig function
- Nest filter GET params as ?list[alias][value]=x (BC break)
- Add unit tests for Filter, FilterConfigResolver, ListSpecification
Restructure the filter subsystem under the Filter\ namespace and align
class/interface names with their roles. No behavior changes.

- Move filter elements to Filter\Element\ and collectors to
  Filter\Collector\; suffix element classes consistently
  (PublishedFilterElement, SearchKeywordsFilterElement, ...)
- Rename ConfigContract -> FilterElementOptionsInterface
  (configureConfig -> configureOptions) and FilterConfigResolver ->
  Filter\OptionsResolver\FilterOptionsResolver
- Rename DcaContract::configureDca -> buildDca; introduce
  DcaBuilderInterface and DcaFieldBuilderInterface
- Rename Form\Type\DateRangeFilterType -> DateRangeFormType, resolving
  the name collision with the query-side filter type
- Drop unused ListItemProviderConfig; update translations
- Add unit tests for Filter, FilterOptionsResolver, and
  ListSpecification; restore FilterFormListener named dispatch
… and ListSpecification classes

<!-- This aligns with the existing commit style from the history while mentioning the main action and specific additions. -->
…ent` and update references

Revised all occurrences of `AbstractFilterFilterElement` to streamline naming conventions and align with the filter subsystem structure.
…d update references

Aligned filter element naming with established conventions (`ArchiveElement` -> `ArchiveFilterElement`, etc.) and adjusted translations accordingly.
…Test` and update method/exception references
ericges added a commit that referenced this pull request Jul 13, 2026
Rewrites the developer documentation for the v0.2 filter subsystem rework:

- Delete pages for removed subsystems: DCA callbacks (callbacks.mdx),
  filter invokers (spec/invoker.md), and the six removed filter-element
  contracts (form-data, form-type-options, hydrate-form, intrinsic-value,
  runtime-value, palette).
- New pages: dev/filter-types (custom filter types guide), dev/dca-builder
  (backend DCA building via DcaContract/DcaBuilder/ElementDcaEvent),
  dev/contracts/dca-contract, spec/filtering (filter pipeline architecture),
  reference/filter-types (built-in type catalog), migrating-from-v0.1,
  removed-in-v0.2, and an unlisted preflight-v0.2 release checklist.
- Rewrite dev/filter-elements around the buildForm/buildFilter/buildDca/
  configureOptions lifecycle, dev/events for the new event set and named
  aliases (.building/.built/.form_built/.dca), spec/specifications around
  the immutable Filter value object and the keyed addFilter() API, and
  dev/contracts/index for the new contract layout.
- Update attribute docs (#[AsFilterElement] without palette/formType/method,
  #[AsListType] without palette), engine-mods examples to
  SimpleEquationFilterElement::define() + addFilter(), Twig docs for the
  new flare_make_filter() helper, and reference tables for the new
  Filter\Element namespace and per-element form controls.
- flare_enclosure_files is documented as removed (code removal tracked on
  the preflight page).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ericges added 9 commits July 14, 2026 12:21
Moved `FilterOptionsResolver` and `FilterElementResolver` to `Filter\Resolver\` namespace, adjusted imports and references accordingly.
Introduce `ConfigBuilder` (fluent canonical-config accumulator), `TransformerBuilder`
(source-class to transformer map), the `TransformerContract` (`configureTransformers()`),
and `FilterTransformerResolver` (per-element-class memoized transformer execution).
Transformer maps are extensible via `FilterTransformerEvent`, re-dispatched as
`flare.filter_element.{type}.transformers`.
…rogrammatic sugar

- Elements now implement `configureTransformers()` (via `AbstractFilterElement`, which
  registers `transformFilterModel(FilterModel, ConfigBuilder)` for the FilterModel source);
  `FilterElementOptionsInterface` and `configFromRow()` are gone. `FilterOptionsResolver`
  checks the generic `OptionsInterface`.
- `ListModelFilterCollector` translates via `FilterTransformerResolver`; elements without
  a matching transformer keep the raw-row passthrough.
- New `FilterContextFactory` dedupes the identical `FilterContext` construction in
  `FilterFormFactory` and `FilterExecutor`.
- Removed programmatic sugar: all static `define()` factories, `Filter::fromType()`,
  `Filter::fromCallback()`, `CallbackFilterElement`, and the `flare_make_filter` Twig
  function. Internal call sites construct `new Filter(element:, config:)` directly.
  A proper engine-extending API is a follow-up.
… options

- `Lists\ListSpec`: immutable list DTO (type, dc, filters, canonical config, source)
  with `with*()` modifiers, `getAutoItemField()` (validated), and a config-based `hash()`.
- `ListBuilder` owns the list build lifecycle: type's `BuildListContract::buildList()`
  hook, `ListBuildEvent` (named dispatch `flare.list.{type}.build`), base + type
  transformer config assembly, schema resolution via `ListOptionsResolver`.
- `BaseListOptions`: framework-owned base schema/translation for tl_flare_list columns,
  applied unconditionally; `genericPageMeta` replaces the dynamic `eval_generic_page_meta`.
- `AbstractListType` now implements `ListTypeInterface`, `OptionsInterface`, and
  `TransformerContract` (`transformListModel()` override point).
- `ListBuilderFactory` replaces `ListSpecificationFactory` (old path still in place
  until the consumer sweep).
… by `ListBuilder`

- All consumers now use `Lists\ListSpec`; construction goes through
  `ListBuilderFactory::createFromListModel()->build()` (controllers, reader attribute
  factory, backend DCA path, breadcrumb listener, filter field options callbacks).
- Dynamic properties are gone: `src/Specification/` deleted entirely (row-dump bag,
  `#[\AllowDynamicProperties]`, `AutoItemFieldGetterTrait`, `ListDataSourceInterface`,
  `ListSpecificationFactory`). Consumers read the canonical `ListSpec::$config`
  (page meta, comments, ptable inference, context factories, sort factory, reader
  attribute marshalling).
- List types own their lifecycle: News/Events add their published filter in
  `buildList()` instead of `ListSpecificationCreatedEvent` listeners (event deleted,
  `ListBuildEvent` + `flare.list.{type}.build` replace it); Generic/DcMultilingual set
  `genericPageMeta` in `transformListModel()` (replaces `EnableGenericPageMetaListener`
  and the DcMultilingual listener, whose `isPageMetaGeneric` key was never read — this
  fixes DcMultilingual generic page meta).
- `ListSpec` is fully immutable: `Engine::setList()` added, `Engine::__clone` no longer
  clones the list, `ValidationLoader`/`SimpleEquationMod` use `withFilter()`.
- `FilterCollectorInterface`/`FilterCollectorRegistry` deleted; `ListModelFilterCollector`
  stays as the concrete collector consumed by `ListBuilderFactory`.
- `ListExecutionContextFactory` supports inline list type instances.
- `getAutoItemField()` now always validates against the DCA (was unvalidated in the
  trait variant used by ChangelanguageListener).
`configureTableRegistry()` / `configureBaseQuery()` become `buildTableRegistry()` /
`buildBaseQuery()`, aligning the list-type query hooks with the build* lifecycle family
(configure* = declarative setup, build* = per-invocation construction).
New tests: ConfigBuilder, TransformerBuilder, FilterTransformerResolver (memoization +
event extensibility), SimpleEquation/Archive `transformFilterModel()` round-trips through
their own schemas, ListSpec (immutability, filter keying, hash), ListBuilder (hook, event,
override precedence, source provenance), BaseListOptions. AGENTS.md architecture section
now describes the Lists domain, the transformer cycle, and the current attribute/event
surface; the stale no-test-suite claim is corrected.
…finish `OptionsContract` rename

resolve() now checks the source's exact class first (O(1), most-specific registration
wins) before falling back to the instanceof scan that covers subclass/interface
registrations — previously an earlier base-class registration shadowed a later, more
specific one. Also completes the `OptionsInterface` → `OptionsContract` rename
(`AbstractFilterElement` still implemented the old name) and fixes a stale docblock.
`HeimrichHannot\FlareBundle\Lists` → `HeimrichHannot\FlareBundle\List` (src/List/,
tests/List/). `List` is a valid namespace segment on PHP >= 8.0 (the bundle requires
^8.2); only a bare `class List` would be reserved.
ericges and others added 22 commits July 15, 2026 17:50
… adapt tests

Missed usages: `ChangelanguageListener` still called the removed
`ListSpec::getTypeAlias()`; `ListSpecFactory` accepted a nullable `$dc` that
`ListSpec` rejects; `ListTransformerEvent::$typeService` renamed to `$driver`;
stale inline-element wording in `Filter`/`FilterElementResolver` docblocks and
the `fingerprint()` key. Tests adapted to the new APIs: `ListDriverReference`
construction, string-only `Filter::$type` (form-factory elements now register
in the `FilterElementRegistry`), `ListBuilderTest` renamed to
`ListSpecBuilderTest`.
Renamed all occurrences of `ListType` to `ListDriver`, including class names, interfaces, namespaces, attributes, and references. Updated tests, translation files, and documentation accordingly for consistency.
…onstruction with static factory methods

Replaced ad-hoc construction of `ListDriverReference` with static factory methods `registered()` and `inline()` for clearer intent and better type management. Updated event dispatchers, listeners, transformers, and tests to use the new structure. Refined `ListTransformerEvent` and related named event handling accordingly.
Introduced `phpunit.yaml` GitHub Actions workflow for running unit tests. Added `phpunit.xml.dist` configuration file and updated documentation to reflect the new setup.
Added a line break after badges for better readability and emphasized the bundle description with bold formatting.
…aContainerName` to `resolveDataContainerTable`
…t, remove obsolete variants, and enhance immutability
… across events and related classes for improved consistency and immutability
…elated APIs for improved consistency and immutability
… and ListDriver registration, streamline type handling via `TypeNameFactory`
…ltiple components, improve tag registration, and fix minor logic inconsistencies
… ensure better type consistency and enhance filters and projector logic across components
@ericges
ericges force-pushed the feat/filter-types branch from 1a8bea5 to 9eca4d4 Compare July 19, 2026 13:08
@ericges
ericges force-pushed the feat/filter-types branch from ae0b057 to 5940ad6 Compare July 19, 2026 13:11
ericges and others added 5 commits July 20, 2026 01:43
…ryCache` utility

Made `PaginatorConfig` non-nullable in `InteractiveContext` for improved null safety. Introduced a new `EntryCache` utility for handling cached entries in a more structured manner. Replaced positional entry lookups with ID-based indexing. Updated `ValidationLoader` and removed stale `entryCache` logic from `ValidationContextFactory`. Adjusted `composer.json` to require `doctrine/dbal` `^3.6 || ^4.0`. Refined `count()` in `PaginatorConfig` to return `1` by default if `totalItems` is unknown.
…olution mechanics

Implemented detection for duplicate filter aliases in `ListModel` and introduced backend error messages for better user feedback. Refactored `ListDriver` resolution with a dedicated `ListDriverResolver` class to centralize logic. Updated `ListSpecBuilder`, `ListSpecFactory`, and related classes to use the resolver. Enhanced backend filter info template to display alias conflicts. Added corresponding translations and adjusted `ElementDcaListener` for alias check logic.
…codebase

Aligned all `FlareException` instantiations to use the `method: __METHOD__` parameter for consistency. Updated exception messages and adjusted formatting where necessary to ensure compliance with the revised standard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant