Skip to content

Commit 4326e6a

Browse files
committed
Drastic refactoring of exception handling.
1 parent 309f5c9 commit 4326e6a

14 files changed

Lines changed: 465 additions & 295 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php namespace Illuminate\Exception;
2+
3+
use Exception;
4+
5+
interface ExceptionDisplayerInterface {
6+
7+
/**
8+
* Display the given exception to the user.
9+
*
10+
* @param \Exception $exception
11+
*/
12+
public function display(Exception $exception);
13+
14+
}

src/Illuminate/Exception/ExceptionServiceProvider.php

Lines changed: 42 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -4,113 +4,75 @@
44
use Whoops\Handler\PrettyPageHandler;
55
use Whoops\Handler\JsonResponseHandler;
66
use Illuminate\Support\ServiceProvider;
7-
use Symfony\Component\Debug\ErrorHandler;
87
use Symfony\Component\HttpFoundation\Response;
98
use Symfony\Component\Debug\ExceptionHandler as KernelHandler;
109

1110
class ExceptionServiceProvider extends ServiceProvider {
1211

1312
/**
14-
* Start the error handling facilities.
13+
* Register the service provider.
1514
*
16-
* @param \Illuminate\Foundation\Application $app
1715
* @return void
1816
*/
19-
public function startHandling($app)
17+
public function register()
2018
{
21-
$this->setExceptionHandler($app['exception.function']);
22-
23-
// By registering the error handler with a level of -1, we state that we want
24-
// all PHP errors converted into ErrorExceptions and thrown which provides
25-
// a very strict development environment but prevents any unseen errors.
26-
$app['kernel.error'] = ErrorHandler::register(-1);
19+
$this->registerDisplayers();
2720

28-
if (isset($app['env']) and $app['env'] != 'testing')
29-
{
30-
$this->registerShutdownHandler();
31-
}
21+
$this->registerHandler();
3222
}
3323

3424
/**
35-
* Register the service provider.
25+
* Register the exception displayers.
3626
*
3727
* @return void
3828
*/
39-
public function register()
29+
protected function registerDisplayers()
4030
{
41-
$this->registerKernelHandlers();
42-
43-
$this->app['exception'] = $this->app->share(function()
44-
{
45-
return new Handler;
46-
});
47-
48-
$this->registerExceptionHandler();
31+
$this->registerPlainDisplayer();
4932

50-
$this->registerWhoops();
33+
$this->registerDebugDisplayer();
5134
}
5235

5336
/**
54-
* Register the HttpKernel error and exception handlers.
37+
* Register the exception handler instance.
5538
*
5639
* @return void
5740
*/
58-
protected function registerKernelHandlers()
41+
protected function registerHandler()
5942
{
60-
$app = $this->app;
61-
62-
$this->app['kernel.exception'] = function() use ($app)
43+
$this->app['exception'] = $this->app->share(function($app)
6344
{
64-
return new KernelHandler($app['config']['app.debug']);
65-
};
45+
return new Handler($app, $app['exception.plain'], $app['exception.debug']);
46+
});
6647
}
6748

6849
/**
69-
* Register the PHP exception handler function.
50+
* Register the plain exception displayer.
7051
*
7152
* @return void
7253
*/
73-
protected function registerExceptionHandler()
54+
protected function registerPlainDisplayer()
7455
{
75-
list($me, $app) = array($this, $this->app);
76-
77-
$app['exception.function'] = function() use ($me, $app)
56+
$this->app['exception.plain'] = $this->app->share(function($app)
7857
{
79-
return function($exception) use ($me, $app)
80-
{
81-
$response = $app['exception']->handle($exception);
82-
83-
// If one of the custom error handlers returned a response, we will send that
84-
// response back to the client after preparing it. This allows a specific
85-
// type of exceptions to handled by a Closure giving great flexibility.
86-
if ( ! is_null($response))
87-
{
88-
$response = $app->prepareResponse($response, $app['request']);
89-
90-
$response->send();
91-
}
92-
else
93-
{
94-
$me->displayException($exception);
95-
}
96-
};
97-
};
58+
$handler = new KernelHandler($app['config']['app.debug']);
59+
60+
return new SymfonyDisplayer($handler);
61+
});
9862
}
9963

10064
/**
101-
* Register the shutdown handler Closure.
65+
* Register the Whoops exception displayer.
10266
*
10367
* @return void
10468
*/
105-
protected function registerShutdownHandler()
69+
protected function registerDebugDisplayer()
10670
{
107-
$app = $this->app;
71+
$this->registerWhoops();
10872

109-
register_shutdown_function(function() use ($app)
73+
$this->app['exception.debug'] = $this->app->share(function($app)
11074
{
111-
set_exception_handler(array(new StubShutdownHandler($app), 'handle'));
112-
113-
$app['kernel.error']->handleFatal();
75+
return new WhoopsDisplayer($app['whoops']);
11476
});
11577
}
11678

@@ -125,11 +87,10 @@ protected function registerWhoops()
12587

12688
$this->app['whoops'] = $this->app->share(function($app)
12789
{
128-
$whoops = new \Whoops\Run;
129-
130-
$whoops->writeToOutput(false);
131-
132-
$whoops->allowQuit(false);
90+
// We will instruct Whoops to not exit after it displays the exception as it
91+
// will otherwise run out before we can do anything else. We just want to
92+
// let the framework go ahead and finish a request on this end instead.
93+
with($whoops = new \Whoops\Run)->allowQuit(false);
13394

13495
return $whoops->pushHandler($app['whoops.handler']);
13596
});
@@ -165,7 +126,13 @@ protected function registerPrettyWhoopsHandler()
165126
{
166127
with($handler = new PrettyPageHandler)->setEditor('sublime');
167128

168-
if ( ! is_null($path = $me->resourcePath())) $handler->setResourcesPath($path);
129+
// If the resource path exists, we will register the resource path with Whoops
130+
// so our custom Laravel branded exception pages will be used when they are
131+
// displayed back to the developer. Otherwise, the default pages are run.
132+
if ( ! is_null($path = $me->resourcePath()))
133+
{
134+
$handler->setResourcesPath($path);
135+
}
169136

170137
return $handler;
171138
};
@@ -178,52 +145,19 @@ protected function registerPrettyWhoopsHandler()
178145
*/
179146
public function resourcePath()
180147
{
181-
if (is_dir($path = $this->app['path.base'].'/vendor/laravel/framework/src/Illuminate/Exception/resources'))
182-
{
183-
return $path;
184-
}
148+
if (is_dir($path = $this->getResourcePath())) return $path;
185149
}
186150

187151
/**
188-
* Display the given exception.
152+
* Get the Whoops custom resource path.
189153
*
190-
* @param \Exception $exception
191-
* @return void
192-
*/
193-
public function displayException($exception)
194-
{
195-
if ($this->app['config']['app.debug'])
196-
{
197-
return $this->displayWhoopsException($exception);
198-
}
199-
200-
$this->app['kernel.exception']->handle($exception);
201-
}
202-
203-
/**
204-
* Display a exception using the Whoops library.
205-
*
206-
* @param \Exception $exception
207-
* @return void
154+
* @return string
208155
*/
209-
protected function displayWhoopsException($exception)
156+
protected function getResourcePath()
210157
{
211-
$response = $this->app['whoops']->handleException($exception);
212-
213-
with(new Response($response, 500))->send();
214-
}
158+
$base = $this->app['path.base'];
215159

216-
/**
217-
* Set the given Closure as the exception handler.
218-
*
219-
* This function is mainly needed for mocking purposes.
220-
*
221-
* @param Closure $handler
222-
* @return mixed
223-
*/
224-
protected function setExceptionHandler(Closure $handler)
225-
{
226-
return set_exception_handler($handler);
160+
return $base.'/vendor/laravel/framework/src/Illuminate/Exception/resources';
227161
}
228162

229163
}

0 commit comments

Comments
 (0)