WEBD-325-45/week-03/project/libraries/src/EventListener/ErrorSubscriber.php

196 lines
4.4 KiB
PHP

<?php
/**
* Joomla! Framework Website
*
* @copyright Copyright (C) 2014 - 2017 Open Source Matters, Inc. All rights reserved.
* @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License Version 2 or Later
*/
namespace Octoleo\CMS\EventListener;
use Joomla\Application\ApplicationEvents;
use Joomla\Application\Event\ApplicationErrorEvent;
use Joomla\Console\ConsoleEvents;
use Joomla\Console\Event\ApplicationErrorEvent as ConsoleApplicationErrorEvent;
use Joomla\Event\SubscriberInterface;
use Octoleo\CMS\Application\SiteApplication;
use Joomla\Renderer\RendererInterface;
use Joomla\Router\Exception\MethodNotAllowedException;
use Joomla\Router\Exception\RouteNotFoundException;
use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
/**
* Error handling event subscriber
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/EventListener/ErrorSubscriber.php
*/
class ErrorSubscriber implements SubscriberInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
/**
* Layout renderer
*
* @var RendererInterface
*/
private $renderer;
/**
* Event subscriber constructor.
*
* @param RendererInterface $renderer Layout renderer
*/
public function __construct(RendererInterface $renderer)
{
$this->renderer = $renderer;
}
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
ApplicationEvents::ERROR => 'handleWebError',
ConsoleEvents::APPLICATION_ERROR => 'handleConsoleError',
];
}
/**
* Handle console application errors.
*
* @param ConsoleApplicationErrorEvent $event Event object
*
* @return void
*/
public function handleConsoleError(ConsoleApplicationErrorEvent $event): void
{
$this->logError($event->getError());
}
/**
* Handle web application errors.
*
* @param ApplicationErrorEvent $event Event object
*
* @return void
*/
public function handleWebError(ApplicationErrorEvent $event): void
{
/** @var SiteApplication $app */
$app = $event->getApplication();
switch (true)
{
case $event->getError() instanceof MethodNotAllowedException :
// Log the error for reference
$this->logger->error(
sprintf('Route `%s` not supported by method `%s`', $app->get('uri.route'), $app->input->getMethod()),
['exception' => $event->getError()]
);
$this->prepareResponse($event);
$app->setHeader('Allow', implode(', ', $event->getError()->getAllowedMethods()));
break;
case $event->getError() instanceof RouteNotFoundException :
// Log the error for reference
$this->logger->error(
sprintf('Route `%s` not found', $app->get('uri.route')),
['exception' => $event->getError()]
);
$this->prepareResponse($event);
break;
default:
$this->logError($event->getError());
$this->prepareResponse($event);
break;
}
}
/**
* Log the error.
*
* @param \Throwable $throwable The error being processed
*
* @return void
*/
private function logError(\Throwable $throwable): void
{
$this->logger->error(
sprintf('Uncaught Throwable of type %s caught.', \get_class($throwable)),
['exception' => $throwable]
);
}
/**
* Prepare the response for the event
*
* @param ApplicationErrorEvent $event Event object
*
* @return void
*/
private function prepareResponse(ApplicationErrorEvent $event): void
{
/** @var SiteApplication $app */
$app = $event->getApplication();
$app->allowCache(false);
switch (true)
{
case $app->input->getString('_format', 'html') === 'json' :
case $app->mimeType === 'application/json' :
case $app->getResponse() instanceof JsonResponse :
$data = [
'code' => $event->getError()->getCode(),
'message' => $event->getError()->getMessage(),
'error' => true,
];
$response = new JsonResponse($data);
break;
default :
$response = new HtmlResponse(
$this->renderer->render('exception.twig', ['exception' => $event->getError()])
);
break;
}
switch ($event->getError()->getCode())
{
case 404 :
$response = $response->withStatus(404);
break;
case 405 :
$response = $response->withStatus(405);
break;
case 500 :
default :
$response = $response->withStatus(500);
break;
}
$app->setResponse($response);
}
}