I have a laravel controller that can throw an exception, and a global middleware that catches that exception. In semi pseudo code:
// App\Controllers\...
class Controller {
function store() {
throw new FormException; // via validation etc, but it's thrown here
}
}
// App\Http\Middleware\...
class Middleware {
function handle(Closure $next) {
try {
// Breakpoint 1
return $next(); // $response
// Breakpoint 2
}
catch (FormException $ex) {
// Breakpoint 3
exit('FormException caught!');
}
}
}
The problem is that the exception is never caught. Somwhere in the pipeline, the application catches the exception and prints a pretty error page, but it should be caught by my middleware so it can handle it properly.
The only way I can imagine my middleware not catching it, is if it's caught somewhere deeper inside the pipeline, not further up/around, but I can't find any try/catch in other middleware, or in the pipeline execution code.
Where is this exception caught? Why?
This might not be a great pattern, but I don't care about that now. I'm more curious than anything else. Do I completely misunderstand Laravel's middleware?
My own super simple middleware test does what I expected: https://3v4l.org/Udr84 - catch and handle exception inside middleware.
Notes:
$response
object (return value of $next()
) is the handled exception page, so it has already been handled. Where and why?App\Exceptions\Handler::render()
works, but I want all logic to be in a middleware package, not in app code.Relevant Laravel code:
Kernel::handle()
starts the middleware pipeline << this has a catch-all catch(), but my catch() comes first, right?Pipeline::then()
starts the middleware executionPipeline::getSlice()
handles and creates the $next
closuresApparently this is by design:
Yes, this is the beavhiour starting from L5.2. Throwing an exception causes the response to be set as that returned from the exception handler, and then the middleware is allowed to backout from that point.
I think that's very strange. Pluggable middleware would be perfect for catching exceptions.
Two ways to still do this:
App\Exceptions\Handler
, which is not good enough, because a package can't touch thatFunky: take the original exception object from the response object:
$response = $next($request);
$exception = $response->exception;