Make DispatchContext externally immutable#181
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #181 +/- ##
============================================
- Coverage 96.40% 96.35% -0.05%
+ Complexity 407 398 -9
============================================
Files 31 31
Lines 1028 1016 -12
============================================
- Hits 991 979 -12
Misses 37 37 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR refactors the router dispatch flow to make DispatchContext externally immutable (no direct property mutation) and to make DispatchEngine stateless with fully-initialized contexts per dispatch, while adding regression tests to ensure handler state (errors/exceptions) does not leak between dispatches.
Changes:
- Switch
DispatchContextto constructor injection for pipeline/handlers/basePath and replace direct mutations with methods likeconfigureRoute()/withRequest(). - Remove router per-request state (
Router::$context,Router::__toString()) and removeDispatchEngine::$onContextReadycallback coupling. - Move routine negotiation bookkeeping from
SplObjectStorageto request attributes; add tests for handler state isolation across dispatches.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Routines/AuthBasicTest.php | Updates test to use configureRoute() instead of mutating $context->route. |
| tests/RoutinePipelineTest.php | Updates route setup to use configureRoute() consistently. |
| tests/Routes/ExceptionTest.php | Adds regression test ensuring exception handler state does not leak between dispatches. |
| tests/Routes/ErrorTest.php | Adds regression test ensuring collected PHP error state does not leak between dispatches. |
| tests/RouterTest.php | Removes reliance on Router::$context / __toString() and updates expectations accordingly. |
| tests/DispatchEngineTest.php | Removes test for the deleted $onContextReady callback behavior. |
| tests/DispatchContextTest.php | Adapts tests to configureRoute() and updated params handling. |
| src/Routines/UserAgent.php | Switches request mutation to DispatchContext::withRequest(). |
| src/Routines/FileExtension.php | Moves negotiation storage from SplObjectStorage to request attributes. |
| src/Routines/ContentType.php | Switches request mutation to DispatchContext::withRequest(). |
| src/Routines/AbstractCallbackMediator.php | Reworks negotiated callback storage to request attributes (but introduces shared mutable decline state). |
| src/Routes/AbstractRoute.php | Uses withRequest() when writing request attributes during match. |
| src/Router.php | Removes per-request state and injects pipeline/handlers/basePath when creating contexts. |
| src/DispatchEngine.php | Stateless context creation; exposes pipeline getter; removes basePath mutation and callback coupling. |
| src/DispatchContext.php | Implements externally immutable properties, constructor injection, basePath handling, and handler state reset logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
DispatchContext: - Constructor injection for RoutinePipeline, handlers, and basePath (removes setRoutinePipeline, setHandlers, setPath) - All public properties use private(set), readable externally, writable only through internal methods (configureRoute, withRequest) - Eliminate transient route mutations in matchRoute/routineMatch - Move SplObjectStorage negotiation to request attributes - Add handler state reset and error/exception isolation tests DispatchEngine: - Remove $onContextReady closure, no callback coupling - Pure stateless dispatcher: creates fully-initialized contexts - Expose routinePipeline() getter for Router::createDispatchContext Router: - Remove public $context property and __toString() - No per-request state, immutable after route registration
DispatchContext:
DispatchEngine:
Router: