Skip to content

Commit

Permalink
Add Http Error Log on Exception Level (#59)
Browse files Browse the repository at this point in the history
* add http error log on exception level
  • Loading branch information
solverat committed Apr 28, 2020
1 parent a1f90eb commit 13f3eb1
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 42 deletions.
3 changes: 3 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
After every update you should check the pimcore extension manager.
Just click the "update" button or execute the migration command to finish the bundle update.

#### Update from Version 3.2.1 to Version 3.2.2
- **[ENHANCEMENT]**: Log http exception to `http_error_log` table [@59](https://github.com/dachcom-digital/pimcore-i18n/pull/59).

#### Update from Version 3.2.0 to Version 3.2.1
- **[ENHANCEMENT]**: Pimcore 6.6.0 ready
- **[ENHANCEMENT]**: Remove empty attributes from alternate links (`link href="http://pimcore.test/de" rel="alternate" type="" title="" hreflang="de"` becomes `link href="http://pimcore.test/de" rel="alternate" hreflang="de"`)
Expand Down
134 changes: 92 additions & 42 deletions src/I18nBundle/EventListener/Frontend/ResponseExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use I18nBundle\Manager\PathGeneratorManager;
use I18nBundle\Manager\ZoneManager;
use Pimcore\Cache;
use Pimcore\Db\ConnectionInterface;
use Pimcore\Http\Exception\ResponseException;
use Pimcore\Model\DataObject;
use Pimcore\Http\Request\Resolver\SiteResolver;
Expand Down Expand Up @@ -60,13 +61,19 @@ class ResponseExceptionListener implements EventSubscriberInterface
*/
protected $pimcoreConfig;

/**
* @var ConnectionInterface
*/
protected $db;

/**
* @param ActionRenderer $actionRenderer
* @param ZoneManager $zoneManager
* @param ContextManager $contextManager
* @param PathGeneratorManager $pathGeneratorManager
* @param SiteResolver $siteResolver
* @param Document\Service $documentService
* @param ConnectionInterface $db
* @param array $pimcoreConfig
*/
public function __construct(
Expand All @@ -76,6 +83,7 @@ public function __construct(
PathGeneratorManager $pathGeneratorManager,
SiteResolver $siteResolver,
Document\Service $documentService,
ConnectionInterface $db,
array $pimcoreConfig
) {
$this->actionRenderer = $actionRenderer;
Expand All @@ -84,6 +92,7 @@ public function __construct(
$this->pathGeneratorManager = $pathGeneratorManager;
$this->siteResolver = $siteResolver;
$this->documentService = $documentService;
$this->db = $db;
$this->pimcoreConfig = $pimcoreConfig;
}

Expand Down Expand Up @@ -127,22 +136,57 @@ public function onKernelException(GetResponseForExceptionEvent $event)
*/
protected function handleErrorPage(GetResponseForExceptionEvent $event)
{
if (\Pimcore::inDebugMode() || PIMCORE_DEVMODE) {
if (\Pimcore::inDebugMode()) {
return;
}

// re-init zones since we're in a kernelException.
$zoneDomains = $this->zoneManager->getCurrentZoneDomains(true);

$exception = $event->getException();
$document = $this->detectDocument($event, $zoneDomains);

$this->setRuntime($event->getRequest(), $document->getProperty('language'));
$this->contextManager->getContext()->setDocument($document);

try {
$response = $this->actionRenderer->render($document);
} catch (\Exception $e) {
// we are even not able to render the error page, so we send the client a unicorn
$response = 'Page not found (' . $e->getMessage() . ') 🦄';
}

$statusCode = 500;
$headers = [];

if ($exception instanceof HttpExceptionInterface) {
$statusCode = $exception->getStatusCode();
$headers = $exception->getHeaders();
}

$this->logToHttpErrorLog($event->getRequest(), $statusCode);

$event->setResponse(new Response($response, $statusCode, $headers));
}

/**
* @param GetResponseForExceptionEvent $event
* @param array $zoneDomains
*
* @return Document
*/
protected function detectDocument(GetResponseForExceptionEvent $event, array $zoneDomains)
{
$defaultErrorDocument = null;
$localizedErrorDocument = null;
$nearestDocumentLocale = null;
$document = null;

$host = preg_replace('/^www./', '', $event->getRequest()->getHost());

// 1. get default system error page ($defaultErrorPath)
$defaultErrorPath = $this->pimcoreConfig['documents']['error_pages']['default'];
$defaultErrorDocument = null;
$localizedErrorDocument = null;

$newDocumentLocale = null;
if ($this->siteResolver->isSiteRequest($event->getRequest())) {
$path = $this->siteResolver->getSitePath($event->getRequest());
// 2. get site error page
Expand All @@ -158,13 +202,11 @@ protected function handleErrorPage(GetResponseForExceptionEvent $event)
$defaultErrorDocument = Document::getByPath($defaultErrorPath);
}

$nearestDocumentLocale = null;
$nearestDocument = $this->documentService->getNearestDocumentByPath($path, true, ['page', 'hardlink']);

// 3. find localized error from current path
if ($nearestDocument instanceof Document) {
$nearestDocumentLocale = $nearestDocument->getProperty('language');
$newDocumentLocale = $nearestDocumentLocale;

$validElements = array_keys(array_filter(
$zoneDomains,
Expand Down Expand Up @@ -211,7 +253,6 @@ function ($v) use ($host, $nearestSourceDocumentLocale) {
}
}

$document = null;
if ($localizedErrorDocument instanceof Document) {
$document = $localizedErrorDocument;
} elseif ($defaultErrorDocument instanceof Document) {
Expand All @@ -220,64 +261,73 @@ function ($v) use ($host, $nearestSourceDocumentLocale) {
$document = Document::getById(1);
}

if (empty($newDocumentLocale)) {
$newDocumentLocale = $document->getProperty('language');
}

$this->setRuntime($event->getRequest(), $document, $newDocumentLocale);
$locale = $document->getProperty('language');

$this->contextManager->getContext()->setDocument($document);

try {
$response = $this->actionRenderer->render($document);
} catch (\Exception $e) {
// we are even not able to render the error page, so we send the client a unicorn
$response = 'Page not found (' . $e->getMessage() . ') 🦄';
if (!empty($nearestDocumentLocale)) {
$locale = $nearestDocumentLocale;
}

$statusCode = 500;
$headers = [];

if ($exception instanceof HttpExceptionInterface) {
$statusCode = $exception->getStatusCode();
$headers = $exception->getHeaders();
if (empty($locale)) {
$locale = 'en';
}

$event->setResponse(new Response($response, $statusCode, $headers));
$document->setProperty('language', 'text', $locale);

return $document;
}

/**
* @param Request $request
* @param Document $document
* @param string $newDocumentLocale
* @param Request $request
* @param string $locale
*/
private function setRuntime(Request $request, Document $document, $newDocumentLocale)
private function setRuntime(Request $request, string $locale)
{
// Pimcore does not initialize context in exception.
Document::setHideUnpublished(true);
DataObject\AbstractObject::setHideUnpublished(true);
DataObject\AbstractObject::setGetInheritedValues(true);
DataObject\Localizedfield::setGetFallbackValues(true);

$saveLocale = is_null($newDocumentLocale) ? 'en' : $newDocumentLocale;

$request->setLocale($saveLocale);
$request->setDefaultLocale($saveLocale);
$request->attributes->set('_locale', $saveLocale);
$document->setProperty('language', 'string', $saveLocale);

//fix i18n language / country context.
Cache\Runtime::set('i18n.locale', $saveLocale);

$docLang = explode('_', $saveLocale);
Cache\Runtime::set('i18n.languageIso', strtolower($docLang[0]));
$request->attributes->set('_locale', $locale);
$request->setLocale($locale);
$request->setDefaultLocale($locale);

$docLang = explode('_', $locale);
$countryIso = Definitions::INTERNATIONAL_COUNTRY_NAMESPACE;

if (count($docLang) > 1) {
$countryIso = $docLang[1];
}

//fix i18n language / country context.
Cache\Runtime::set('i18n.locale', $locale);
Cache\Runtime::set('i18n.languageIso', strtolower($docLang[0]));
Cache\Runtime::set('i18n.countryIso', $countryIso);
}

/**
* @param Request $request
* @param int $statusCode
*/
protected function logToHttpErrorLog(Request $request, $statusCode)
{
$uri = $request->getUri();
$exists = $this->db->fetchOne('SELECT `date` FROM http_error_log WHERE uri = ?', $uri);

if ($exists !== false) {
$this->db->executeQuery('UPDATE http_error_log SET `count` = `count` + 1, `date` = ? WHERE uri = ?', [time(), $uri]);
return;
}

$this->db->insert('http_error_log', [
'uri' => $uri,
'code' => (int) $statusCode,
'parametersGet' => serialize($request->query->all()),
'parametersPost' => serialize($request->request->all()),
'cookies' => serialize($request->cookies->all()),
'serverVars' => serialize($request->server->all()),
'date' => time(),
'count' => 1
]);
}
}

0 comments on commit 13f3eb1

Please sign in to comment.