Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save geerteltink/717d8c8218ebcc3cc16b695074fa7075 to your computer and use it in GitHub Desktop.
Save geerteltink/717d8c8218ebcc3cc16b695074fa7075 to your computer and use it in GitHub Desktop.
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @see https://github.com/zendframework/zend-expressive for the canonical source repository
* @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-expressive/blob/master/LICENSE.md New BSD License
*/
namespace Zend\Expressive\Container;
use Interop\Container\ContainerInterface;
use Whoops\Handler\JsonResponseHandler;
use Zend\Expressive\WhoopsErrorHandler;
use Whoops\Run as Whoops;
/**
* Create and return an instance of the whoops error handler.
*
* Register this factory as the service `Zend\Expressive\FinalHandler` in
* the container of your choice.
*
* This factory has optional dependencies on the following services:
*
* - 'Zend\Expressive\Template\TemplateRendererInterface', which should return an
* implementation of that interface. If not present, the error handler
* will not create templated responses.
* - 'config' (which should return an array or array-like object with a
* "zend-expressive" top-level key, and an "error_handler" subkey,
* containing the configuration for the error handler).
*
* This factory has required dependencies on the following services:
*
* - Zend\Expressive\Whoops, which should return a Whoops\Run instance.
* - Zend\Expressive\WhoopsPageHandler, which should return a
* Whoops\Handler\PrettyPageHandler instance.
*
* Configuration should look like the following:
*
* <code>
* 'zend-expressive' => [
* 'error_handler' => [
* 'template_404' => 'name of 404 template',
* 'template_error' => 'name of error template',
* ],
* ]
* </code>
*
* If any of the keys are missing, default values will be used.
*
* The whoops configuration can contain:
*
* <code>
* 'whoops' => [
* 'json_exceptions' => [
* 'display' => true,
* 'show_trace' => true,
* 'ajax_only' => true,
* ]
* ]
* </code>
*
* All values are booleans; omission of any implies boolean false.
*/
class WhoopsErrorHandlerFactory
{
public function __invoke(ContainerInterface $container)
{
$template = $container->has('Zend\Expressive\Template\TemplateRendererInterface')
? $container->get('Zend\Expressive\Template\TemplateRendererInterface')
: null;
$config = $container->has('config')
? $container->get('config')
: [];
$expressiveConfig = isset($config['zend-expressive']['error_handler'])
? $config['zend-expressive']['error_handler']
: [];
$whoopsConfig = isset($config['whoops'])
? $config['whoops']
: [];
$whoops = $container->get('Zend\Expressive\Whoops');
$whoops->pushHandler($container->get('Zend\Expressive\WhoopsPageHandler'));
$this->registerJsonHandler($whoops, $whoopsConfig);
return new WhoopsErrorHandler(
$whoops,
null,
$template,
(isset($expressiveConfig['template_404']) ? $expressiveConfig['template_404'] : 'error/404'),
(isset($expressiveConfig['template_error']) ? $expressiveConfig['template_error'] : 'error/error')
);
}
/**
* If configuration indicates a JsonResponseHandler, configure and register it.
*
* @param Whoops $whoops
* @param array|\ArrayAccess $config
*/
private function registerJsonHandler(Whoops $whoops, $config)
{
if (! isset($config['json_exceptions']['display'])
|| empty($config['json_exceptions']['display'])
) {
return;
}
$handler = new JsonResponseHandler();
if (isset($config['json_exceptions']['ajax_only'])) {
if (method_exists(\Whoops\Util\Misc::class, 'isAjaxRequest')) {
// Whoops 2.x
if (! \Whoops\Util\Misc::isAjaxRequest()) {
return;
}
} elseif (method_exists($handler, 'onlyForAjaxRequests')) {
// Whoops 1.x
$handler->onlyForAjaxRequests(true);
}
}
if (isset($config['json_exceptions']['show_trace'])) {
$handler->addTraceToOutput(true);
}
$whoops->pushHandler($handler);
}
}
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @see http://github.com/zendframework/zend-expressive for the canonical source repository
* @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-expressive/blob/master/LICENSE.md New BSD License
*/
namespace Zend\Expressive;
use Psr\Http\Message\RequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run as Whoops;
use Zend\Stratigility\Http\Request as StratigilityRequest;
/**
* Final handler with templated page capabilities plus Whoops exception reporting.
*
* Extends from TemplatedErrorHandler in order to provide templated error and 404
* pages; for exceptions, it delegates to Whoops to provide a user-friendly
* interface for navigating an exception stack trace.
*
* @see http://filp.github.io/whoops/
*/
class WhoopsErrorHandler extends TemplatedErrorHandler
{
/**
* Whoops runner instance to use when returning exception details.
*
* @var Whoops
*/
private $whoops;
/**
* Whoops PrettyPageHandler; injected to allow runtime configuration with
* request information.
*
* @var PrettyPageHandler
*/
private $whoopsHandler;
/**
* @param Whoops $whoops
* @param PrettyPageHandler $whoopsHandler
* @param null|Template\TemplateRendererInterface $renderer
* @param null|string $template404
* @param null|string $templateError
* @param null|Response $originalResponse
*/
public function __construct(
Whoops $whoops,
PrettyPageHandler $whoopsHandler = null,
Template\TemplateRendererInterface $renderer = null,
$template404 = 'error/404',
$templateError = 'error/error',
Response $originalResponse = null
) {
$this->whoops = $whoops;
$this->whoopsHandler = $whoopsHandler;
parent::__construct($renderer, $template404, $templateError, $originalResponse);
}
/**
* Handle an exception.
*
* Calls on prepareWhoopsHandler() to inject additional data tables into
* the generated payload, and then injects the response with the result
* of whoops handling the exception.
*
* @param \Throwable $exception
* @param Request $request
* @param Response $response
* @return Response
*/
protected function handleException($exception, Request $request, Response $response)
{
// Push the whoops handler if any
if (null !== $this->whoopsHandler) {
$this->whoops->pushHandler($this->whoopsHandler);
}
// Walk through all handlers
foreach ($this->whoops->getHandlers() as $handler) {
// Add fancy data for the PrettyPageHandler
if ($handler instanceof PrettyPageHandler) {
$this->prepareWhoopsHandler($request, $handler);
}
}
$response
->getBody()
->write($this->whoops->handleException($exception));
return $response;
}
/**
* Prepare the Whoops page handler with a table displaying request information
*
* @param Request $request
* @param PrettyPageHandler $handler
*/
private function prepareWhoopsHandler(Request $request, PrettyPageHandler $handler)
{
if ($request instanceof StratigilityRequest) {
$request = $request->getOriginalRequest();
}
$uri = $request->getUri();
$handler->addDataTable('Expressive Application Request', [
'HTTP Method' => $request->getMethod(),
'URI' => (string) $uri,
'Script' => $request->getServerParams()['SCRIPT_NAME'],
'Headers' => $request->getHeaders(),
'Cookies' => $request->getCookieParams(),
'Attributes' => $request->getAttributes(),
'Query String Arguments' => $request->getQueryParams(),
'Body Params' => $request->getParsedBody(),
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment