<?php namespace Illuminate\Routing; use Closure; use Throwable; use Exception; use Illuminate\Http\Request; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Pipeline\Pipeline as BasePipeline; use Symfony\Component\Debug\Exception\FatalThrowableError; /** * This extended pipeline catches any exceptions that occur during each slice. * * The exceptions are converted to HTTP responses for proper middleware handling. */ class Pipeline extends BasePipeline { /** * Get a Closure that represents a slice of the application onion. * * @return \Closure */ protected function getSlice() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { try { $slice = parent::getSlice(); return call_user_func($slice($stack, $pipe), $passable); } catch (Exception $e) { return $this->handleException($passable, $e); } catch (Throwable $e) { return $this->handleException($passable, new FatalThrowableError($e)); } }; }; } /** * Get the initial slice to begin the stack call. * * @param \Closure $destination * @return \Closure */ protected function getInitialSlice(Closure $destination) { return function ($passable) use ($destination) { try { return call_user_func($destination, $passable); } catch (Exception $e) { return $this->handleException($passable, $e); } catch (Throwable $e) { return $this->handleException($passable, new FatalThrowableError($e)); } }; } /** * Handle the given exception. * * @param mixed $passable * @param \Exception $e * @return mixed * * @throws \Exception */ protected function handleException($passable, Exception $e) { if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) { throw $e; } $handler = $this->container->make(ExceptionHandler::class); $handler->report($e); $response = $handler->render($passable, $e); if (method_exists($response, 'withException')) { $response->withException($e); } return $response; } }