<?php declare(strict_types=1);
namespace Dvdw\Events\Framework\Adapter\Cache;
use Doctrine\DBAL\Connection;
use Dvdw\Events\Content\DvdwEvent\Aggregate\DvdwEventUsp\DvdwEventUspDefinition;
use Dvdw\Events\Content\DvdwEvent\DvdwEventDefinition;
use Dvdw\Events\Content\DvdwEvent\SalesChannel\CachedDvdwEventRoute;
use Dvdw\Events\Content\DvdwProduct\DvdwProductDefinition;
use Dvdw\Events\Content\DvdwProduct\SalesChannel\CachedDvdwProductRoute;
use Dvdw\Events\Content\DvdwPromotion\Aggregate\DvdwPromotionLimitation\DvdwPromotionLimitationDefinition;
use Dvdw\Events\Content\DvdwPromotion\DvdwPromotionDefinition;
use Dvdw\Events\Content\DvdwPromotion\SalesChannel\CachedDvdwPromotionRoute;
use Dvdw\Events\Content\DvdwTicket\DvdwTicketDefinition;
use Dvdw\Events\Content\DvdwTicket\SalesChannel\CachedDvdwTicketRoute;
use Shopware\Core\Framework\Adapter\Cache\CacheInvalidator;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CacheInvalidationSubscriber implements EventSubscriberInterface
{
private CacheInvalidator $cacheInvalidator;
private Connection $connection;
public function __construct(
CacheInvalidator $cacheInvalidator,
Connection $connection
)
{
$this->cacheInvalidator = $cacheInvalidator;
$this->connection = $connection;
}
public static function getSubscribedEvents(): iterable
{
return [
EntityWrittenContainerEvent::class => [
['invalidateDvdwEventIds', 2001],
['invalidateDvdwProductIds', 2002],
['invalidateDvdwPromotionIds', 2003],
['invalidateDvdwTicketIds', 2004]
]
];
}
public function invalidateDvdwEventIds(EntityWrittenContainerEvent $event): void
{
$this->cacheInvalidator->invalidate($this->getChangedDvdwEvents($event));
}
public function invalidateDvdwProductIds(EntityWrittenContainerEvent $event): void
{
$this->cacheInvalidator->invalidate($this->getChangedDvdwProducts($event));
}
public function invalidateDvdwPromotionIds(EntityWrittenContainerEvent $event): void
{
$this->cacheInvalidator->invalidate($this->getChangedDvdwPromotions($event));
}
public function invalidateDvdwTicketIds(EntityWrittenContainerEvent $event): void
{
$this->cacheInvalidator->invalidate($this->getChangedDvdwTickets($event));
}
private function getChangedDvdwEvents(EntityWrittenContainerEvent $event): array
{
$ids = array_merge(
$this->getRelevantIds($event, DvdwEventDefinition::ENTITY_NAME),
$this->getIdsFromAssociation($event, DvdwEventUspDefinition::ENTITY_NAME, 'dvdw_event_id')
);
if (empty($ids)) {
return [];
}
return $this->buildRouteNames(CachedDvdwEventRoute::class, $ids);
}
private function getChangedDvdwProducts(EntityWrittenContainerEvent $event): array
{
return $this->getChanged(
$event,
DvdwProductDefinition::ENTITY_NAME,
CachedDvdwProductRoute::class
);
}
private function getChangedDvdwPromotions(EntityWrittenContainerEvent $event): array
{
$ids = array_merge(
$this->getRelevantIds($event, DvdwPromotionDefinition::ENTITY_NAME),
$this->getIdsFromAssociation($event, DvdwPromotionLimitationDefinition::ENTITY_NAME, 'dvdw_promotion_id')
);
if (empty($ids)) {
return [];
}
return $this->buildRouteNames(CachedDvdwPromotionRoute::class, $ids);
}
private function getChangedDvdwTickets(EntityWrittenContainerEvent $event): array
{
return $this->getChanged(
$event,
DvdwTicketDefinition::ENTITY_NAME,
CachedDvdwTicketRoute::class
);
}
private function getChanged(EntityWrittenContainerEvent $event, string $entity, string $cachedRouteClass): array
{
$ids = $this->getRelevantIds($event, $entity);
if (empty($ids)) {
return [];
}
return $this->buildRouteNames($cachedRouteClass, $ids);
}
private function getRelevantIds(EntityWrittenContainerEvent $event, string $entity): array
{
return array_merge($event->getPrimaryKeys($entity), $event->getDeletedPrimaryKeys($entity));
}
private function buildRouteNames(string $cachedRouteClass, array $ids): array
{
return array_map([$cachedRouteClass, 'buildName'], $ids);
}
private function getIdsFromAssociation(EntityWrittenContainerEvent $event, string $association, string $column): array
{
$ids = $this->getRelevantIds($event, $association);
if (empty($ids)) {
return [];
}
return $this->connection->fetchFirstColumn(
sprintf('SELECT DISTINCT LOWER(HEX(%s)) FROM %s WHERE id IN (:ids)', $column, $association),
['ids' => Uuid::fromHexToBytesList($ids)],
['ids' => Connection::PARAM_STR_ARRAY]
);
}
}