<?php declare(strict_types=1);
/*
* (c) webpiloten. <kontakt@web-piloten.de>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Spno\ActivityLog\Framework\ActivityLog\Subscriber;
use Shopware\Core\Framework\Api\Context\AdminApiSource;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Write\EntityExistence;
use Shopware\Core\Framework\Uuid\Uuid;
use Spno\ActivityLog\Framework\ActivityLog\Serializer\KebabCaseToCamelCaseNameConverter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
class EntityWrittenSubscriber implements EventSubscriberInterface
{
const EVENT_CREATED = 'created';
const EVENT_WRITTEN = 'written';
const EVENT_DELETED = 'deleted';
const ENTITY_ID = 0;
const ENTITY_ASSOCIATION = 1;
const ENTITY_ASSOCIATION_ID = 2;
private EntityRepositoryInterface $activityLogRepository;
private RequestStack $requestStack;
public function __construct(
EntityRepositoryInterface $activityLogRepository,
RequestStack $requestStack
) {
$this->activityLogRepository = $activityLogRepository;
$this->requestStack = $requestStack;
}
public static function getSubscribedEvents(): array
{
return EntityEvents::ENTITY_EVENTS;
}
public function onEntityDeleted(EntityDeletedEvent $event): void
{
if (!$this->requestStack->getCurrentRequest() instanceof Request) {
return;
}
if (!$event->getContext()->getSource() instanceof AdminApiSource) {
return;
}
$requestBag = $this->requestStack->getCurrentRequest()->request;
$this->prepareDeleteEvent($event, $requestBag);
}
public function onEntityWritten(EntityWrittenEvent $event): void
{
if (!$this->requestStack->getCurrentRequest() instanceof Request) {
return;
}
if (!$event->getContext()->getSource() instanceof AdminApiSource) {
return;
}
if (empty($event->getWriteResults()) || !array_key_exists(0, $event->getWriteResults())) {
return;
}
$requestBag = $this->requestStack->getCurrentRequest()->request;
$writeResult = $event->getWriteResults()[0];
if (!$writeResult instanceof EntityWriteResult) {
return;
}
$primaryKeys = [];
if ($this->requestStack->getCurrentRequest()->getRealMethod() === Request::METHOD_DELETE) {
$this->prepareDeleteEvent($event, $requestBag);
return;
}
if ($writeResult->getExistence() instanceof EntityExistence) {
$primaryKeys = $writeResult->getExistence()->getPrimaryKey();
if ($writeResult->getExistence()->exists()) {
$this->createLog($event, $requestBag, self::EVENT_WRITTEN, $primaryKeys);
return;
}
}
if ($writeResult->getPayload()) {
$primaryKeys = array_merge($primaryKeys, $writeResult->getPayload());
}
$this->createLog($event, $requestBag, self::EVENT_CREATED, $primaryKeys);
}
private function prepareDeleteEvent(EntityWrittenEvent $event, ParameterBag $requestBag): void
{
if (!$this->requestStack->getCurrentRequest() instanceof Request) {
return;
}
if (!$this->requestStack->getCurrentRequest()->attributes->has('_route_params')) {
return;
}
$kebabCaseConverter = new KebabCaseToCamelCaseNameConverter();
$attrRouteParams = $this->requestStack->getCurrentRequest()->attributes->get('_route_params');
if (!is_array($attrRouteParams) || !array_key_exists('path', $attrRouteParams)) {
return;
}
$path = $attrRouteParams['path'];
$routeParams = explode('/', $path);
foreach ($routeParams as &$param) {
if (Uuid::isValid($param)) {
continue;
}
$param = $kebabCaseConverter->normalize($param);
}
if (
!array_key_exists(self::ENTITY_ID, $routeParams) ||
!array_key_exists(self::ENTITY_ASSOCIATION, $routeParams) ||
!array_key_exists(self::ENTITY_ASSOCIATION_ID, $routeParams)
) {
return;
}
$primaryKeys = [
'id' => $routeParams[self::ENTITY_ID],
];
$requestBag->add([
$routeParams[self::ENTITY_ASSOCIATION] => [
'id' => $routeParams[self::ENTITY_ASSOCIATION_ID],
],
]);
$this->createLog($event, $requestBag, self::EVENT_DELETED, $primaryKeys);
}
private function createLog(EntityWrittenEvent $event, ParameterBag $requestBag, string $eventName, array $primaryKeys): void
{
if (!$primaryKeys) {
return;
}
$source = $event->getContext()->getSource();
if (!$source instanceof AdminApiSource) {
return;
}
$userId = $source->getUserId();
$integrationId = $source->getIntegrationId();
$message = sprintf('%s.%s', $event->getEntityName(), $eventName);
$this->activityLogRepository->create([
[
'userId' => $userId,
'integrationId' => $integrationId,
'message' => $message,
'context' => [
'entity' => [
'name' => $event->getEntityName(),
'primaryKey' => $primaryKeys,
],
'languageId' => $event->getContext()->getLanguageId(),
'result' => $requestBag->all(),
],
],
], $event->getContext());
}
}