Repository navigation
Issue/537 structured runtime pipelines for web and console - #574
Conversation
Add WebAppAdapter tests, driven only through start(), that record how the web flow behaves today so the pipeline refactor can be proven not to change it: OPTIONS preflight, JSON and HTML 404 responses, the matched route response, a view cache hit, and a dispatch exception that leaves the request uncleaned. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…factor Add ConsoleAppAdapter tests that record how the console flow behaves today so the pipeline refactor can be proven not to change it: a missing command name fails, core and app commands are registered and really executed through a non-exiting Symfony Application, and the core:env command boots with the reduced stages while regular commands boot the environment, error handler and app config. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Introduce RequestStageInterface, RequestContext and RequestPipeline as the foundation for running the web request as stages. RequestContext carries the matched route, response, view cache and a stopped flag for one request, while AppContext stays unchanged. The pipeline runs stages in order, rejects anything that is not a request stage, and leaves skipping to the stages. Nothing uses these classes yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add HandlePreflightStage, which answers an OPTIONS request with an empty 204 response and stops the remaining stages, and SendResponseStage, which applies the CORS headers, sends the response, and always clears the request state afterwards, even when sending fails. The stages are not wired into WebAppAdapter yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add ResolveRouteStage, which finds the route for the current request and stores it on the request context and the request, and HandleRouteNotFoundStage, which answers a request with no matched route with the page not found response and stops the remaining stages. Both skip when the context is already stopped. The stages are not wired into WebAppAdapter yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tion test The view cache hit test creates cache/views and cache/views/test through ViewCache::setup() and used to leave them behind. Record whether the folders existed before the test and remove only the ones it created. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add PrepareRequestStage, which loads the language, logs the registered event listeners to the debugbar when debug is on, and sets up the view cache and stores it on the request context, in the same order as the former WebAppAdapter flow. It skips when the context is stopped, so an OPTIONS or not found request does none of this work. The stage is not wired into WebAppAdapter yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add DispatchRequestStage, which produces the response of a matched request: the cached view if there is one, otherwise the dispatched route, wrapped by the module and framework middlewares, and stores it on the request context. It skips when the context is stopped and fails clearly when the matched route or the view cache was not set. The stage is not wired into WebAppAdapter yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WebAppAdapter::start() now builds a RequestContext and runs a RequestPipeline of the preflight, route, not found, prepare, dispatch and send stages instead of the flat sequence of trait methods, and WebAppTrait is removed. Behavior is unchanged: the characterization tests written before the refactor pass without edits. Only the four tests that reached private trait methods by reflection are removed, as the stage tests now cover them. Two tests are added to pin that preflight and not found requests do not load the language. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Introduce ConsoleStageInterface, ConsoleContext and ConsolePipeline as the foundation for running a console command as stages. ConsoleContext carries the Symfony application, input and output and the exit code of one run, using the input and output interfaces so stages can be tested with array input and buffered output. The pipeline runs stages in order and rejects anything that is not a console stage. Nothing uses these classes yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add the stages that run a console command: RegisterCoreCommandsStage and RegisterAppCommandsStage, which share a base that discovers the commands of a folder and adds them to the application, ValidateCommandStage, which fails for a missing or unknown command, and RunCommandStage, which runs the application with the context input and output and stores the exit code. Stage tests use a real non-exiting Symfony application, array input and buffered output. The stages are not wired into ConsoleAppAdapter yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ConsoleAppAdapter::start() now builds a ConsoleContext and runs a ConsolePipeline of the register core commands, register app commands, validate and run stages instead of the flat sequence of trait methods. createApplication() moves into the adapter and stays overridable, and ConsoleAppTrait is removed because it only held that one method. Behavior is unchanged: the characterization tests written before the refactor pass without edits. One test is added to pin that core commands are registered before app commands. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
AppAdapter only held the AppContext property and its constructor, and nothing referred to it except the two adapters, which are used through AppInterface. WebAppAdapter and ConsoleAppAdapter now implement AppInterface directly and keep their own context. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ges into folders Group each flow in its own folder. The adapter, context and pipeline of the web flow move to App/Adapters/Web and those of the console flow to App/Adapters/Console, and the boot stages move to App/Stages/Boot next to the existing Stages/Request and Stages/Console. Namespaces and imports are updated, the tests move to mirror the source, and LoadHelpersStage now resolves the source root one level higher. Behavior is unchanged: the moved characterization and stage tests keep their assertions and only their namespace and import lines differ. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Add characterization tests for the command registration done by the console adapter: an app command overrides a core command with the same name, a missing app commands directory is tolerated, and only instantiable commands are registered. They pass on the current code and guard the upcoming rework of the register stages. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add a CommandRegistrar in the Console package that discovers the commands of a directory and adds them to the console application. It is the single place that connects the native command discovery to the Symfony application. Nothing uses it yet; the register stages will call it in the next commit. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…gistrar Give RegisterCoreCommandsStage and RegisterAppCommandsStage their own process() that calls the CommandRegistrar with their directory and namespace, and remove the abstract RegisterCommandsStage they used to inherit it from. Behavior is unchanged: core commands are still registered before app commands. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Move the directory and the namespace of the core and app register stages into private helpers, so process() only reads as the call to the CommandRegistrar. Behavior is unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reject a missing or unknown command at the start of RunCommandStage and remove ValidateCommandStage, which was a guard clause and not a stage of its own. The exception and its message are unchanged, and nothing runs before the check. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The console pipeline no longer has a validate stage: the run stage rejects a missing or unknown command, and the commands are registered through the new CommandRegistrar. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Closes #537
What changed
WebAppAdapter::start()now runs aRequestPipelineof six stages with aRequestContext: preflight, route resolution, not found, prepare (language, debug info, view cache), dispatch (cached view or route, wrapped by middleware), and send. Stages that must be skipped checkRequestContext::isStopped(); the send stage always runs and still clears the request state in afinally, as before.ConsoleAppAdapter::start()now runs aConsolePipelineof four stages with aConsoleContext: register core commands, register app commands, validate, and run. The constructor, thecore:envreduced boot and the publiccreateApplication()are unchanged.App/Adapters/Web, the console ones inApp/Adapters/Console, and the stages are grouped inApp/Stages/Boot,App/Stages/RequestandApp/Stages/Console. Stage interfaces are inApp/Contracts.AppAdapterbase class and theWebAppTraitandConsoleAppTraittraits. Both adapters implementAppInterfacedirectly.Why
The boot flow was already a staged pipeline, while the runtime flows were flat call sequences. Giving them stages and context objects is the structure #538 needs to attach lifecycle events. This PR is a pure refactor: behavior is unchanged, and no runtime events are dispatched yet.
Breaking changes
The namespaces of the two adapters, the contexts, the pipelines and the boot stages changed, and
AppAdapter,WebAppTraitandConsoleAppTraitare removed. Code that goes throughAppFactoryis unaffected; code that references these classes directly must update its imports. Documented inCHANGELOG.md.How behavior was proven unchanged
core:envreduced boot, core commands registered before app commands).Validation
vendor/bin/phpunit: 1642 tests, 4013 assertions, 4 skipped (optional Twig not installed)composer cs:checkandcomposer phpstanpassedquantum-php-project:php qt list,core:versionandroute:list;/,/enand/api/postsrespond; a 404 in HTML and JSON; OPTIONS returns 204 with the CORS headers; the debugbar rendersNotes for reviewers
composer rector:checkreports 22 findings, none introduced here.request()andresponse()helpers, as the rest of the framework does.Summary by CodeRabbit
AppFactoryare unaffected.