<?php
declare(strict_types=1);
namespace App\Service;
use App\Entity\Menu\Item;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use App\Event\Content\ContentDisplayEvent;
use App\Menu\MenuResolver;
use LogicException;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
/**
* Gatherer service
*
* @author Przemysław Chrupek <przemyslaw.chrupek@avt.pl>
* @package App\Service
*/
class Gatherer implements EventSubscriberInterface
{
protected MenuResolver $menuResolver;
protected CacheHelper $cacheHelper;
protected TagAwareCacheInterface $appCache;
protected ?Item $activeMenuItem;
protected bool $cacheEnabled;
private $data = [];
public function __construct(MenuResolver $menuResolver, CacheHelper $cacheHelper, TagAwareCacheInterface $appCache)
{
$this->menuResolver = $menuResolver;
$this->activeMenuItem = $this->menuResolver->getActiveMenuEntityItem();
$this->appCache = $appCache;
$this->cacheHelper = $cacheHelper;
$this->cacheEnabled = $this->cacheHelper->cacheEnabled();
$this->loadCache();
}
public static function getSubscribedEvents()
{
return [
ContentDisplayEvent::NAME => [
['preContentDisplay', 10],
]
];
}
public function preContentDisplay(ContentDisplayEvent $event): void
{
$this->add('content', $event->getContent());
}
public function add(string $key, $value, $cache = false): Gatherer
{
if (array_key_exists($key, $this->data))
throw new LogicException(sprintf('Can\'t override existing value: [%s]', $key));
$this->setDataValue($key, $value, $cache);
return $this;
}
public function addOrReplace(string $key, $value, $cache = false): Gatherer
{
if (!array_key_exists($key, $this->data)) {
$this->add($key, $value, $cache);
return $this;
}
$this->setDataValue($key, $value, $cache);
return $this;
}
public function remove(string $key): Gatherer
{
if (array_key_exists($key, $this->data)) {
unset($this->data[$key]);
$this->reloadCache();
}
return $this;
}
public function get(string $key)
{
return array_key_exists($key, $this->data) ? $this->data[$key]['value'] : null;
}
public function getData(): array
{
$data = [];
foreach ($this->data as $k => $d) {
$data[$k] = $d['value'];
}
return $data;
}
protected function setDataValue(string $key, $value, $cache = false): Gatherer
{
$this->data[$key] = [
'value' => $value,
'cache' => $cache
];
$this->reloadCache();
return $this;
}
protected function getCacheKey(): string
{
/**
* ID based on menu item id
* 0 for homepage
*/
$id = $this->activeMenuItem ? $this->activeMenuItem->getId() : 0;
return sprintf('%s_%d', $this->cacheHelper::TAG_GATHERER, $id);
}
/**
* If cache empty and data empty - load current data to cache (empty array).
* If cache hits - set data from cache.
* If cache miss and data not empty - save data to cache
*/
protected function loadCache(): void
{
if (!$this->cacheEnabled)
return;
$cachedData = $this->appCache->get($this->getCacheKey(), function (ItemInterface $item)
{
$item->tag(CacheHelper::TAG_GATHERER);
$item->tag($this->getCacheKey());
$cachedData = [];
foreach ($this->data as $k => $d) {
if (!$d['cache'])
continue;
$cachedData[$k] = $d;
}
return $cachedData; // Get current data value
});
$this->data = array_merge($this->data, $cachedData);
}
protected function reloadCache(): void
{
if (!$this->cacheEnabled)
return;
$this->appCache->delete($this->getCacheKey());
$this->loadCache();
}
}