Skip to content

Commit

Permalink
#49 Extract notification from PhpExceptionStorageHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
spotman committed Jan 5, 2018
1 parent a34fe1d commit 8e64af1
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
namespace BetaKiller\Error;

use BetaKiller\Config\AppConfigInterface;
use BetaKiller\Helper\IFaceHelper;
use BetaKiller\Helper\NotificationHelper;
use BetaKiller\Model\IFaceZone;
use BetaKiller\Model\PhpExceptionModelInterface;
use BetaKiller\Model\UserInterface;
use BetaKiller\Repository\PhpExceptionRepository;
Expand Down Expand Up @@ -58,30 +56,22 @@ class PhpExceptionStorageHandler extends AbstractProcessingHandler
*/
private $user;

/**
* @var \BetaKiller\Helper\IFaceHelper
*/
private $ifaceHelper;

/**
* PhpExceptionStorageHandler constructor.
*
* @param \BetaKiller\Repository\PhpExceptionRepository $repository
* @param \BetaKiller\Helper\IFaceHelper $ifaceHelper
* @param \BetaKiller\Model\UserInterface $user
* @param \BetaKiller\Config\AppConfigInterface $appConfig
* @param \BetaKiller\Helper\NotificationHelper $notificationHelper
*/
public function __construct(
PhpExceptionRepository $repository,
IFaceHelper $ifaceHelper,
UserInterface $user,
AppConfigInterface $appConfig,
NotificationHelper $notificationHelper
) {
$this->repository = $repository;
$this->user = $user;
$this->ifaceHelper = $ifaceHelper;
$this->appConfig = $appConfig;
$this->notificationHelper = $notificationHelper;

Expand Down Expand Up @@ -196,36 +186,17 @@ public function storeException(\Throwable $exception): ?PhpExceptionModelInterfa
$model->addModule($module);
}

// Saving
$this->repository->save($model);

$isNotificationNeeded = $this->isNotificationNeededFor($model, static::REPEAT_COUNT, static::REPEAT_DELAY);

// $this->logger->debug('Notification needed is :value', [':value' => $isNotificationNeeded ? 'true' : 'false']);

// Notify developers if needed
if ($isNotificationNeeded) {
$data = [
'message' => $model->getMessage(),
'urls' => $model->getUrls(),
'paths' => $model->getPaths(),
'adminUrl' => $this->ifaceHelper->getReadEntityUrl($model, IFaceZone::ADMIN_ZONE),
];

$message = $this->notificationHelper->createMessage('developer/error/php-exception');

$this->notificationHelper->toDevelopers($message);

$message
->setSubj('BetaKiller exception')
->setTemplateData($data)
->send();

// Saving last notification timestamp
$model->setLastNotifiedAt($currentTime);
$this->repository->save($model);
$model->notificationRequired();
}

// Saving
$this->repository->save($model);

return $model;
}

Expand Down
45 changes: 36 additions & 9 deletions modules/error/classes/BetaKiller/Model/PhpException.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ protected function createErrorsTableIfNotExists()
resolved_by INTEGER UNSIGNED NULL,
status VARCHAR(16) NOT NULL,
message TEXT NOT NULL,
total INTEGER UNSIGNED NOT NULL DEFAULT 0
total INTEGER UNSIGNED NOT NULL DEFAULT 0,
notification_required UNSIGNED INTEGER(1) NOT NULL DEFAULT 0
)')->execute($this->_db_group);
}

Expand Down Expand Up @@ -414,7 +415,7 @@ public function getResolvedBy(): ?UserInterface
*/
public function markAsNew(UserInterface $user)
{
$this->setStatus(PhpExceptionModelInterface::STATE_NEW);
$this->setStatus(self::STATE_NEW);
$this->addHistoryRecord($user);

return $this;
Expand All @@ -436,7 +437,7 @@ public function markAsRepeated(UserInterface $user)

// Reset resolved_by
$this->setResolvedBy(null);
$this->setStatus(PhpExceptionModelInterface::STATE_REPEATED);
$this->setStatus(self::STATE_REPEATED);
$this->addHistoryRecord($user);

return $this;
Expand All @@ -453,7 +454,7 @@ public function markAsResolvedBy(UserInterface $user)
{
// Reset resolved_by
$this->setResolvedBy($user);
$this->setStatus(PhpExceptionModelInterface::STATE_RESOLVED);
$this->setStatus(self::STATE_RESOLVED);
$this->addHistoryRecord($user);

return $this;
Expand All @@ -470,7 +471,7 @@ public function markAsIgnoredBy(UserInterface $user)
{
// Reset resolved_by
$this->setResolvedBy(null);
$this->setStatus(PhpExceptionModelInterface::STATE_IGNORED);
$this->setStatus(self::STATE_IGNORED);
$this->addHistoryRecord($user);

return $this;
Expand All @@ -483,7 +484,7 @@ public function markAsIgnoredBy(UserInterface $user)
*/
public function isResolved(): bool
{
return $this->getStatus() === PhpExceptionModelInterface::STATE_RESOLVED;
return $this->getStatus() === self::STATE_RESOLVED;
}

/**
Expand All @@ -493,7 +494,7 @@ public function isResolved(): bool
*/
public function isRepeated(): bool
{
return $this->getStatus() === PhpExceptionModelInterface::STATE_REPEATED;
return $this->getStatus() === self::STATE_REPEATED;
}

/**
Expand All @@ -503,7 +504,7 @@ public function isRepeated(): bool
*/
public function isNew(): bool
{
return !$this->getID() || $this->getStatus() === PhpExceptionModelInterface::STATE_NEW;
return !$this->getID() || $this->getStatus() === self::STATE_NEW;
}

/**
Expand All @@ -513,7 +514,7 @@ public function isNew(): bool
*/
public function isIgnored(): bool
{
return $this->getStatus() === PhpExceptionModelInterface::STATE_IGNORED;
return $this->getStatus() === self::STATE_IGNORED;
}

/**
Expand Down Expand Up @@ -552,6 +553,32 @@ public function getHistoricalRecords(): array
return $this->getHistoryRelation()->get_all();
}

/**
* Marks current exception instance as "notification required"
*/
public function notificationRequired(): void
{
$this->set('notification_required', true);
}

/**
* Marks current exception instance as "notification required" = 0
*/
public function wasNotified(): void
{
$this->set('notification_required', false);
}

/**
* Returns true if someone needs to be notified about current exception instance
*
* @return bool
*/
public function isNotificationRequired(): bool
{
return (bool)$this->get('notification_required');
}

/**
* Adds record to history
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

interface PhpExceptionModelInterface extends DispatchableEntityInterface
{
const STATE_NEW = 'new';
const STATE_RESOLVED = 'resolved';
const STATE_REPEATED = 'repeated';
const STATE_IGNORED = 'ignored';
public const STATE_NEW = 'new';
public const STATE_RESOLVED = 'resolved';
public const STATE_REPEATED = 'repeated';
public const STATE_IGNORED = 'ignored';

/**
* @return string
Expand Down Expand Up @@ -211,4 +211,21 @@ public function getResolvedBy(): ?UserInterface;
* @return PhpExceptionHistoryModelInterface[]
*/
public function getHistoricalRecords(): array;

/**
* Marks current exception instance as "notification required" = 1
*/
public function notificationRequired(): void;

/**
* Marks current exception instance as "notification required" = 0
*/
public function wasNotified(): void;

/**
* Returns true if someone needs to be notified about current exception instance
*
* @return bool
*/
public function isNotificationRequired(): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ public function getResolvedPhpExceptions(): array
return $orm->get_all();
}

/**
* @return PhpExceptionModelInterface[]
*/
public function getRequiredNotification(): array
{
$orm = $this->getOrmInstance();

$this->filterNotificationRequired($orm)->orderByCreatedAt($orm);

return $orm->get_all();
}

/**
* @param string $hash
*
Expand Down Expand Up @@ -84,6 +96,13 @@ private function filterResolved(OrmInterface $orm)
return $this;
}

private function filterNotificationRequired(OrmInterface $orm)
{
$orm->where('notification_required', '=', true);

return $this;
}

/**
* @param \BetaKiller\Utils\Kohana\ORM\OrmInterface $orm
* @param bool|null $asc
Expand Down
70 changes: 70 additions & 0 deletions modules/error/classes/Task/Error/Notify.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

use BetaKiller\Model\PhpExceptionModelInterface;
use BetaKiller\Task\AbstractTask;
use BetaKiller\Model\IFaceZone;

class Task_Error_Notify extends AbstractTask
{
/**
* @Inject
* @var \BetaKiller\Repository\PhpExceptionRepository
*/
private $repository;

/**
* @Inject
* @var \BetaKiller\Helper\NotificationHelper
*/
private $notificationHelper;

/**
* @Inject
* @var \BetaKiller\Helper\IFaceHelper
*/
private $ifaceHelper;

protected function _execute(array $params)
{
// Repository returns filtered notifications
$exceptions = $this->repository->getRequiredNotification();

if (!\count($exceptions)) {
$this->logger->debug('No one exception needs notification');
return;
}

foreach ($exceptions as $exception) {
$this->notifyAboutException($exception);
}
}

/**
* @param \BetaKiller\Model\PhpExceptionModelInterface $model
*/
private function notifyAboutException(PhpExceptionModelInterface $model): void
{
// Notify developers if needed
$data = [
'message' => $model->getMessage(),
'urls' => $model->getUrls(),
'paths' => $model->getPaths(),
'adminUrl' => $this->ifaceHelper->getReadEntityUrl($model, IFaceZone::ADMIN_ZONE),
];

$message = $this->notificationHelper->createMessage('developer/error/php-exception');

$this->notificationHelper->toDevelopers($message);

$message
->setSubj('BetaKiller exception')
->setTemplateData($data)
->send();

// Saving last notification timestamp
$model->setLastNotifiedAt(new DateTimeImmutable);
$model->wasNotified();

$this->repository->save($model);
}
}
Loading

0 comments on commit 8e64af1

Please sign in to comment.