summaryrefslogtreecommitdiff
path: root/src/Exceptions
diff options
context:
space:
mode:
authorIgor Scheller <igor.scheller@igorshp.de>2017-11-24 15:08:43 +0100
committerIgor Scheller <igor.scheller@igorshp.de>2017-11-25 11:27:38 +0100
commit25e434bce4986b48bd72729a55aa1096e5a76be3 (patch)
treeb254fafaf789b4ebcc980fec8281675415706750 /src/Exceptions
parent6eea072376cc9fd1034342a0e1d2173681268138 (diff)
Refactored ExceptionHandler
Diffstat (limited to 'src/Exceptions')
-rw-r--r--src/Exceptions/BasicHandler.php119
-rw-r--r--src/Exceptions/ExceptionsServiceProvider.php46
-rw-r--r--src/Exceptions/Handler.php100
-rw-r--r--src/Exceptions/Handlers/HandlerInterface.php21
-rw-r--r--src/Exceptions/Handlers/Legacy.php42
-rw-r--r--src/Exceptions/Handlers/LegacyDevelopment.php57
-rw-r--r--src/Exceptions/Handlers/Whoops.php85
7 files changed, 344 insertions, 126 deletions
diff --git a/src/Exceptions/BasicHandler.php b/src/Exceptions/BasicHandler.php
deleted file mode 100644
index 2ba960a2..00000000
--- a/src/Exceptions/BasicHandler.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-
-namespace Engelsystem\Exceptions;
-
-use ErrorException;
-use Throwable;
-
-class BasicHandler extends Handler
-{
- /**
- * Activate the error handler
- */
- public function register()
- {
- set_error_handler([$this, 'errorHandler']);
- set_exception_handler([$this, 'exceptionHandler']);
- }
-
- /**
- * @param int $number
- * @param string $message
- * @param string $file
- * @param int $line
- */
- public function errorHandler($number, $message, $file, $line)
- {
- $exception = new ErrorException($message, 0, $number, $file, $line);
- $this->exceptionHandler($exception);
- }
-
- /**
- * @param Throwable $e
- */
- public function exceptionHandler($e)
- {
- $this->handle(
- $e->getCode(),
- get_class($e) . ': ' . $e->getMessage(),
- $e->getFile(),
- $e->getLine(),
- ['exception' => $e]
- );
- }
-
- /**
- * @param int $number
- * @param string $string
- * @param string $file
- * @param int $line
- * @param array $context
- * @param array $trace
- */
- protected function handle($number, $string, $file, $line, $context = [], $trace = [])
- {
- error_log(sprintf('Exception: Number: %s, String: %s, File: %s:%u, Context: %s',
- $number,
- $string,
- $file,
- $line,
- json_encode($context)
- ));
-
- $file = $this->stripBasePath($file);
-
- if ($this->environment == self::ENV_DEVELOPMENT) {
- echo '<pre style="background-color:#333;color:#ccc;z-index:1000;position:fixed;bottom:1em;padding:1em;width:97%;max-height: 90%;overflow-y:auto;">';
- echo sprintf('%s: (%s)' . PHP_EOL, ucfirst($type), $number);
- var_export([
- 'string' => $string,
- 'file' => $file . ':' . $line,
- 'context' => $context,
- 'stacktrace' => $this->formatStackTrace($trace),
- ]);
- echo '</pre>';
- die();
- }
-
- echo 'An <del>un</del>expected error occurred, a team of untrained monkeys has been dispatched to deal with it.';
- die();
- }
-
- /**
- * @param array $stackTrace
- * @return array
- */
- protected function formatStackTrace($stackTrace)
- {
- $return = [];
-
- foreach ($stackTrace as $trace) {
- $path = '';
- $line = '';
-
- if (isset($trace['file']) && isset($trace['line'])) {
- $path = $this->stripBasePath($trace['file']);
- $line = $trace['line'];
- }
-
- $functionName = $trace['function'];
-
- $return[] = [
- 'file' => $path . ':' . $line,
- $functionName => $trace['args'],
- ];
- }
-
- return $return;
- }
-
- /**
- * @param string $path
- * @return string
- */
- protected function stripBasePath($path)
- {
- $basePath = realpath(__DIR__ . '/../..') . '/';
- return str_replace($basePath, '', $path);
- }
-}
diff --git a/src/Exceptions/ExceptionsServiceProvider.php b/src/Exceptions/ExceptionsServiceProvider.php
index 8eeccf61..a9bc2b17 100644
--- a/src/Exceptions/ExceptionsServiceProvider.php
+++ b/src/Exceptions/ExceptionsServiceProvider.php
@@ -3,14 +3,56 @@
namespace Engelsystem\Exceptions;
use Engelsystem\Container\ServiceProvider;
+use Engelsystem\Exceptions\Handlers\HandlerInterface;
+use Engelsystem\Exceptions\Handlers\Legacy;
+use Engelsystem\Exceptions\Handlers\LegacyDevelopment;
+use Engelsystem\Exceptions\Handlers\Whoops;
+use Whoops\Run as WhoopsRunner;
class ExceptionsServiceProvider extends ServiceProvider
{
public function register()
{
- $errorHandler = $this->app->make(BasicHandler::class);
- $errorHandler->register();
+ $errorHandler = $this->app->make(Handler::class);
+ $this->addProductionHandler($errorHandler);
+ $this->addDevelopmentHandler($errorHandler);
$this->app->instance('error.handler', $errorHandler);
$this->app->bind(Handler::class, 'error.handler');
+ $errorHandler->register();
+ }
+
+ public function boot()
+ {
+ /** @var Handler $handler */
+ $handler = $this->app->get('error.handler');
+ $request = $this->app->get('request');
+
+ $handler->setRequest($request);
+ }
+
+ /**
+ * @param Handler $errorHandler
+ */
+ protected function addProductionHandler($errorHandler)
+ {
+ $handler = $this->app->make(Legacy::class);
+ $this->app->instance('error.handler.production', $handler);
+ $errorHandler->setHandler(Handler::ENV_PRODUCTION, $handler);
+ $this->app->bind(HandlerInterface::class, 'error.handler.production');
+ }
+
+ /**
+ * @param Handler $errorHandler
+ */
+ protected function addDevelopmentHandler($errorHandler)
+ {
+ $handler = $this->app->make(LegacyDevelopment::class);
+
+ if (class_exists(WhoopsRunner::class)) {
+ $handler = $this->app->make(Whoops::class);
+ }
+
+ $this->app->instance('error.handler.development', $handler);
+ $errorHandler->setHandler(Handler::ENV_DEVELOPMENT, $handler);
}
}
diff --git a/src/Exceptions/Handler.php b/src/Exceptions/Handler.php
index cdf94e32..ee15717a 100644
--- a/src/Exceptions/Handler.php
+++ b/src/Exceptions/Handler.php
@@ -2,18 +2,29 @@
namespace Engelsystem\Exceptions;
-abstract class Handler
+use Engelsystem\Exceptions\Handlers\HandlerInterface;
+use Engelsystem\Http\Request;
+use ErrorException;
+use Throwable;
+
+class Handler
{
/** @var string */
protected $environment;
+ /** @var HandlerInterface[] */
+ protected $handler = [];
+
+ /** @var Request */
+ protected $request;
+
const ENV_PRODUCTION = 'prod';
const ENV_DEVELOPMENT = 'dev';
/**
* Handler constructor.
*
- * @param string $environment production|development
+ * @param string $environment prod|dev
*/
public function __construct($environment = self::ENV_PRODUCTION)
{
@@ -25,14 +36,47 @@ abstract class Handler
*/
public function register()
{
+ set_error_handler([$this, 'errorHandler']);
+ set_exception_handler([$this, 'exceptionHandler']);
}
/**
- * @param string $environment
+ * @param int $number
+ * @param string $message
+ * @param string $file
+ * @param int $line
*/
- public function setEnvironment($environment)
+ public function errorHandler($number, $message, $file, $line)
{
- $this->environment = $environment;
+ $exception = new ErrorException($message, 0, $number, $file, $line);
+ $this->exceptionHandler($exception);
+ }
+
+ /**
+ * @param Throwable $e
+ */
+ public function exceptionHandler($e)
+ {
+ if (!$this->request instanceof Request) {
+ $this->request = new Request();
+ }
+
+ $handler = $this->handler[$this->environment];
+ $handler->report($e);
+ $handler->render($this->request, $e);
+ $this->die();
+ }
+
+ /**
+ * Exit the application
+ *
+ * @codeCoverageIgnore
+ * @param string $message
+ */
+ protected function die($message = '')
+ {
+ echo $message;
+ die();
}
/**
@@ -42,4 +86,50 @@ abstract class Handler
{
return $this->environment;
}
+
+ /**
+ * @param string $environment
+ */
+ public function setEnvironment($environment)
+ {
+ $this->environment = $environment;
+ }
+
+ /**
+ * @param string $environment
+ * @return HandlerInterface|HandlerInterface[]
+ */
+ public function getHandler($environment = null)
+ {
+ if (!is_null($environment)) {
+ return $this->handler[$environment];
+ }
+
+ return $this->handler;
+ }
+
+ /**
+ * @param string $environment
+ * @param HandlerInterface $handler
+ */
+ public function setHandler($environment, HandlerInterface $handler)
+ {
+ $this->handler[$environment] = $handler;
+ }
+
+ /**
+ * @return Request
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * @param Request $request
+ */
+ public function setRequest(Request $request)
+ {
+ $this->request = $request;
+ }
}
diff --git a/src/Exceptions/Handlers/HandlerInterface.php b/src/Exceptions/Handlers/HandlerInterface.php
new file mode 100644
index 00000000..9de33e1f
--- /dev/null
+++ b/src/Exceptions/Handlers/HandlerInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Engelsystem\Exceptions\Handlers;
+
+use Engelsystem\Http\Request;
+use Throwable;
+
+interface HandlerInterface
+{
+ /**
+ * @param Request $request
+ * @param Throwable $e
+ */
+ public function render($request, Throwable $e);
+
+ /**
+ * @param Throwable $e
+ * @return
+ */
+ public function report(Throwable $e);
+}
diff --git a/src/Exceptions/Handlers/Legacy.php b/src/Exceptions/Handlers/Legacy.php
new file mode 100644
index 00000000..39683f72
--- /dev/null
+++ b/src/Exceptions/Handlers/Legacy.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Engelsystem\Exceptions\Handlers;
+
+use Engelsystem\Http\Request;
+use Throwable;
+
+class Legacy implements HandlerInterface
+{
+ /**
+ * @param Request $request
+ * @param Throwable $e
+ */
+ public function render($request, Throwable $e)
+ {
+ echo 'An <del>un</del>expected error occurred, a team of untrained monkeys has been dispatched to deal with it.';
+ }
+
+ /**
+ * @param Throwable $e
+ */
+ public function report(Throwable $e)
+ {
+ error_log(sprintf('Exception: Code: %s, Message: %s, File: %s:%u, Trace: %s',
+ $e->getCode(),
+ $e->getMessage(),
+ $this->stripBasePath($e->getFile()),
+ $e->getLine(),
+ json_encode($e->getTrace())
+ ));
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ protected function stripBasePath($path)
+ {
+ $basePath = realpath(__DIR__ . '/../../..') . '/';
+ return str_replace($basePath, '', $path);
+ }
+}
diff --git a/src/Exceptions/Handlers/LegacyDevelopment.php b/src/Exceptions/Handlers/LegacyDevelopment.php
new file mode 100644
index 00000000..86f86f4c
--- /dev/null
+++ b/src/Exceptions/Handlers/LegacyDevelopment.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Engelsystem\Exceptions\Handlers;
+
+use Engelsystem\Http\Request;
+use Throwable;
+
+class LegacyDevelopment extends Legacy
+{
+ /**
+ * @param Request $request
+ * @param Throwable $e
+ */
+ public function render($request, Throwable $e)
+ {
+ $file = $this->stripBasePath($e->getFile());
+
+ echo '<pre style="background-color:#333;color:#ccc;z-index:1000;position:fixed;bottom:1em;padding:1em;width:97%;max-height: 90%;overflow-y:auto;">';
+ echo sprintf('%s: (%s)' . PHP_EOL, get_class($e), $e->getCode());
+ $data = [
+ 'string' => $e->getMessage(),
+ 'file' => $file . ':' . $e->getLine(),
+ 'stacktrace' => $this->formatStackTrace($e->getTrace()),
+ ];
+ var_dump($data);
+ echo '</pre>';
+ }
+
+ /**
+ * @param array $stackTrace
+ * @return array
+ */
+ protected function formatStackTrace($stackTrace)
+ {
+ $return = [];
+ $stackTrace = array_reverse($stackTrace);
+
+ foreach ($stackTrace as $trace) {
+ $path = '';
+ $line = '';
+
+ if (isset($trace['file']) && isset($trace['line'])) {
+ $path = $this->stripBasePath($trace['file']);
+ $line = $trace['line'];
+ }
+
+ $functionName = $trace['function'];
+
+ $return[] = [
+ 'file' => $path . ':' . $line,
+ $functionName => isset($trace['args']) ? $trace['args'] : null,
+ ];
+ }
+
+ return $return;
+ }
+}
diff --git a/src/Exceptions/Handlers/Whoops.php b/src/Exceptions/Handlers/Whoops.php
new file mode 100644
index 00000000..807f5eb0
--- /dev/null
+++ b/src/Exceptions/Handlers/Whoops.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Engelsystem\Exceptions\Handlers;
+
+use Engelsystem\Application;
+use Engelsystem\Container\Container;
+use Engelsystem\Http\Request;
+use Throwable;
+use Whoops\Handler\JsonResponseHandler;
+use Whoops\Handler\PrettyPageHandler;
+use Whoops\Run as WhoopsRunner;
+
+class Whoops extends Legacy implements HandlerInterface
+{
+ /** @var Application */
+ protected $app;
+
+ public function __construct(Container $app)
+ {
+ $this->app = $app;
+ }
+
+ /**
+ * @param Request $request
+ * @param Throwable $e
+ */
+ public function render($request, Throwable $e)
+ {
+ $whoops = $this->app->make(WhoopsRunner::class);
+ $handler = $this->getPrettyPageHandler($e);
+ $whoops->pushHandler($handler);
+
+ if ($request->isXmlHttpRequest()) {
+ $handler = $this->getJsonResponseHandler();
+ $whoops->pushHandler($handler);
+ }
+
+ echo $whoops->handleException($e);
+ }
+
+ /**
+ * @param Throwable $e
+ * @return PrettyPageHandler
+ */
+ protected function getPrettyPageHandler(Throwable $e)
+ {
+ $handler = $this->app->make(PrettyPageHandler::class);
+
+ $handler->setPageTitle('Just another ' . get_class($e) . ' to fix :(');
+ $handler->setApplicationPaths([realpath(__DIR__ . '/../..')]);
+
+ $data = $this->getData();
+ $handler->addDataTable('Application', $data);
+
+ return $handler;
+ }
+
+ /**
+ * @return JsonResponseHandler
+ */
+ protected function getJsonResponseHandler()
+ {
+ $handler = $this->app->make(JsonResponseHandler::class);
+ $handler->setJsonApi(true);
+ $handler->addTraceToOutput(true);
+
+ return $handler;
+ }
+
+ /**
+ * Aggregate application data
+ *
+ * @return array
+ */
+ protected function getData()
+ {
+ global $user;
+
+ $data = [];
+ $data['user'] = $user;
+ $data['Booted'] = $this->app->isBooted();
+
+ return $data;
+ }
+}