Refactor Filter Processing Architecture and Introduce CQRS-Based Domain Model#5
Open
Refactor Filter Processing Architecture and Introduce CQRS-Based Domain Model#5
Conversation
ca566db to
61239dc
Compare
c63e51c to
2812721
Compare
…ctions and consistent naming
2812721 to
30d539e
Compare
…oach for improved flexibility
…rInterface for improved contract adherence
…ed architecture for improved flexibility and modularity
…ucture and organization
…atures and cleaner event-based structure
… for consistency with updated event naming conventions
…tency and modularity
…tions and exception handling descriptions
…pagination and form handling
…eamline codebase and align with view engine architecture
…rom documentation
…sibility options, and coding conventions
…sibility options, and coding conventions
…ions, stricter type hints, and deprecated method removals
…hance dynamic property handling in FilterModel
…ements, and event listeners
…FilterDefinition` and related classes for improved flexibility
…for method alignment and consistency across filter elements
…gsManagerFinderPass` with `CodefogTagsPass`, adding registry and resolver classes, and enhancing dependency injection alignment
…rays with typed objects for improved type safety and readability in CodefogTags integration
…place table alias attributes with a registry-based implementation in CodefogTags integration
…hing to associative array
…ment` and add value normalization logic
…to ensure array type consistency and handle numeric values as arrays
…gTagsChoiceElement`, update behavior in `PaginatorFactory` and event listeners
…ty and update method calls accordingly
- Updated `AGENTS.md` to document new Makefile commands for managing PHP and Composer tasks via Docker. - Added new `Dockerfile` for the PHP environment with required extensions and dependencies. - Introduced `docker-compose.yml` for containerized development. - Modified `Makefile` to include `php` and `composer` commands. - Added `.dockerignore` to exclude unnecessary files from Docker context.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR replaces the monolithic manager-based architecture with a layered, contract-driven domain model built around three core concerns: Specification (what a list is), Engine (how results are produced), and Query (how the database query is built).
Specification Layer
ListSpecificationdescribes a list via its type, data-container table, data source reference, and aFilterDefinitionCollectionFilterDefinitionrepresents a single filter rule with type, alias, target alias, intrinsic flag, and dynamic propertiesFilterCollectorInterface(withListModelFilterCollector) handles filter collection from various data sourcesListSpecificationFactoryorchestrates construction and dispatchesListSpecificationCreatedEventfor post-hoc filter injectionEngine (Projector / Context / View)
Engineis a thin orchestrator that pairs aContextInterfacewith aListSpecificationand delegates to aProjectorRegistryInteractiveContext— full frontend list with form, pagination, sorting, and reader linksAggregationContext— COUNT-only evaluation with filter valuesValidationContext— single-record lookup for the reader with lazy entry cachingProjectorInterface) implement the actual data fetching strategy.InteractiveProjectorhandles form building, runs an aggregation sub-projection for total count, builds the paginator, and returns a lazy view.AggregationProjectorandValidationProjectorhandle their respective contexts. Priority-based resolution allows integration modules to override projectors per list typeInteractiveView,AggregationView,ValidationView), with traits for model hydration (HandlesModelsTrait) and reader URL generation (LinksToReaderTrait)Query Subsystem
SqlQueryStructaccumulates all parts of a SELECT statement, thenQueryBuilderFactorymaterialises it into a Doctrine DBALQueryBuilderTableAliasRegistrymanages table aliases with activation, hiding, dependency tracking, and topological join resolutionFilterExecutoriterates filter definitions and delegates toFilterInvokerResolver, which supports context-specific overrides via#[AsFilterInvoker]attribute andFilterInvokerRegistryListQueryDirectororchestrates the full pipeline: execution context creation → filter invocation →ModifyListQueryStructEventdispatch → query builder materialisationIntrinsicValueContractandRuntimeValueContractstandardise filter value resolutionPaginator
PaginatorConfigas an immutable value object with computed page metadataPaginatorextends config with URL generation, window-based navigation, and ellipsis supportPaginatorFactoryreplacesPaginatorBuilderwith request-aware constructionIntegration Modules
EventsInteractiveProjectorandEventsAggregationProjectoroverride default projectors for event-specific logic (multi-day/recurring event grouping viaGroupsEntriesTrait)src/Integration/ContaoComments/src/Integration/Terminal42Changelanguage/Removed
The following components have been removed in favour of the new architecture:
ListViewManager,ListView,ListViewBuilder,ListViewResolver— replaced by Engine/Projector/ViewReaderManager— replaced byValidationProjector+ValidationViewListQueryManager,ListQueryBuilder— replaced byListQueryDirector+SqlQueryStruct+QueryBuilderFactoryFilterContextManager,FilterContext,FilterContextBuilder,FilterContextCollection— replaced byFilterExecutor+FilterInvocationListItemProvider,ListItemProviderManager,ListItemProviderInterface— inlined into projectorsTemplateManager,TranslationManager— no longer neededContentContext,SqlQuery,ParameterizedSqlQuery,FilterInvocationDto, etc.)ArrayFieldChoice,SortDescriptor,PresetFiltersConfigAdded
src/Engine/— full Context/Projector/View layersrc/Query/— struct-based query subsystem withTableAliasRegistry,FilterExecutor,ListQueryDirectorsrc/Specification/—ListSpecification,FilterDefinition, and factoriessrc/FilterCollector/— pluggable filter collection interfacesrc/Integration/— relocated and restructured integration modulessrc/Sort/—SortOrderandSortOrderSequencereplacingSortDescriptorsrc/DataCollector/FlareCollector.php— Symfony profiler integration#[AsFilterInvoker]attribute and compiler pass for context-specific filter invocationConfigureQueryContractfor list types to register joins and base query modificationsBreaking Changes
This is a full architectural rewrite. All public APIs from the removed components are gone. Consumers must migrate to the Engine/Projector/View pattern. Key migration points:
ListViewManager::render()→EngineFactory+Engine::createView()withInteractiveContextReaderManager→Engine::createView()withValidationContextListQueryManager/ListQueryBuilder→ListQueryDirector(internal, typically not called directly)FilterContextManager→ filter values are now resolved automatically byAbstractProjector::gatherFilterValues()ListItemProviderInterfaceimplementations → implementConfigureQueryContracton the list type and/or use#[AsFilterInvoker]for context-specific filter behaviourIntrinsicValueContract/RuntimeValueContractas needed; the__invokemethod signature now receives(FilterInvocation, FilterQueryBuilder)Test Plan