Fix exception handling, rank fallthrough, and add statusRoute()#176
Fix exception handling, rank fallthrough, and add statusRoute()#176alganet merged 1 commit intoRespect:masterfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #176 +/- ##
============================================
+ Coverage 96.67% 96.91% +0.24%
- Complexity 430 437 +7
============================================
Files 31 32 +1
Lines 1082 1103 +21
============================================
+ Hits 1046 1069 +23
+ Misses 36 34 -2 ☔ 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 updates the router/dispatch pipeline to (1) propagate unhandled exceptions instead of converting them to generic 500 responses, (2) prevent routine validation failures from falling through to lower-priority “ANY” routes, and (3) introduce a new statusRoute() API to customize framework-generated status responses (404/405/400/etc.), including supporting content negotiation.
Changes:
- Add
statusRoute()and a newRoutes\Statusside-route type, plus dispatch-time plumbing to forward prepared status responses to those handlers. - Change exception route matching to use
is_a()(inheritance +Throwablesupport) and stop swallowing unhandled exceptions inhandle(). - Fix route selection so routine failures at a higher method-rank do not fall through to lower-rank catch-all routes.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/Routes/Status.php |
Adds a new side-route type for handling prepared HTTP status responses. |
src/DispatchContext.php |
Adds forwarding of prepared status responses to status side-routes; changes exception matching to is_a(). |
src/DispatchEngine.php |
Stops catching Throwable in handle(); injects side-routes into the dispatch context. |
src/RouteProvider.php |
Extends the provider contract with getSideRoutes(). |
src/Router.php |
Adds statusRoute() and exposes side-routes via getSideRoutes(). |
tests/Routes/StatusTest.php |
New tests for statusRoute() behavior (404/405/400, JSON responses, dispatch/handle). |
tests/Routes/ExceptionTest.php |
Adds tests for inheritance matching and Throwable exception routes. |
tests/DispatchEngineTest.php |
Updates expected behavior to propagate unhandled exceptions. |
tests/RouterTest.php |
Updates expected behavior to propagate unhandled exceptions. |
Comments suppressed due to low confidence (1)
src/DispatchContext.php:282
- Switching exception route matching to
is_a($e, $sideRoute->class)changes the previous special-casing whereexceptionRoute('Exception', ...)would catch any Throwable (including PHPError). Withis_a, anExceptionhandler will no longer catchErrorinstances; users must registerThrowableexplicitly. If this behavior change is intended, it likely needs a compatibility shim (treat 'Exception'/'\Exception' as 'Throwable') or documentation/tests to avoid surprising upgrades.
continue;
}
if (is_a($e, $sideRoute->class)) {
$sideRoute->exception = $e;
return $this->forward($sideRoute);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Exception routes now use is_a() for class matching, supporting inheritance and Throwable. handle() no longer swallows exceptions silently — unhandled exceptions propagate per PSR-15. routineMatch() no longer falls through from exact-method (rank 0) to any-method (rank 1) routes when a when() routine fails, preventing validation bypass via catch-all routes. New statusRoute() API lets users handle framework-generated HTTP status codes (404, 405, 400, etc.) with custom callbacks, including content negotiation via accept(). Passing null as status code creates a catch-all handler for any status.
Exception routes now use is_a() for class matching, supporting inheritance and Throwable. handle() no longer swallows exceptions silently — unhandled exceptions propagate per PSR-15.
routineMatch() no longer falls through from exact-method (rank 0) to any-method (rank 1) routes when a when() routine fails, preventing validation bypass via catch-all routes.
New statusRoute() API lets users handle framework-generated HTTP status codes (404, 405, 400, etc.) with custom callbacks, including content negotiation via accept(). Passing null as status code creates a catch-all handler for any status.