Spaces:
No application file
No application file
namespace Mautic\DashboardBundle\Event; | |
use Mautic\CacheBundle\Cache\CacheProvider; | |
use Mautic\CoreBundle\Event\CommonEvent; | |
use Mautic\CoreBundle\Helper\CacheStorageHelper; | |
use Mautic\CoreBundle\Security\Permissions\CorePermissions; | |
use Mautic\DashboardBundle\Entity\Widget; | |
use Mautic\DashboardBundle\Exception\CouldNotFormatDateTimeException; | |
use Symfony\Contracts\Translation\TranslatorInterface; | |
class WidgetDetailEvent extends CommonEvent | |
{ | |
protected $type; | |
protected $template; | |
protected $templateData = []; | |
protected $errorMessage; | |
protected $uniqueId; | |
protected $cacheDir; | |
protected $uniqueCacheDir; | |
protected $cacheTimeout; | |
protected float $startTime; | |
protected $loadTime = 0; | |
private string $cacheKeyPath = 'dashboard.widget.'; | |
private bool $isPreview = false; | |
public function __construct(private TranslatorInterface $translator, private CorePermissions $security, protected Widget $widget, private ?CacheProvider $cacheProvider = null) | |
{ | |
$this->startTime = microtime(true); | |
$this->setWidget($widget); | |
} | |
/** | |
* Act as widget preview without data. | |
*/ | |
public function setPreview(bool $isPreview): void | |
{ | |
$this->isPreview = $isPreview; | |
} | |
/** | |
* Is preview without data? | |
*/ | |
public function isPreview(): bool | |
{ | |
return $this->isPreview; | |
} | |
/** | |
* Return unique key, uses legacy methods for BC. | |
*/ | |
public function getCacheKey(): string | |
{ | |
$cacheKey = [ | |
$this->getUniqueWidgetId(), | |
]; | |
$params = $this->getWidget()->getParams(); | |
foreach (['dateTo', 'dateFrom'] as $dateParameter) { | |
if (isset($params[$dateParameter])) { | |
try { | |
$date = $this->castDateTimeToString($params[$dateParameter]); | |
$cacheKey[] = $date; | |
} catch (CouldNotFormatDateTimeException) { | |
} | |
} | |
} | |
// If there are no additional parameters we return uniqueWidgetId as a cache key | |
// Otherwise we return hashed $cacheKey value | |
$cacheKey = (1 == count($cacheKey)) ? $this->getUniqueWidgetId() : substr(md5(implode('', $cacheKey)), 0, 16); | |
return $this->cacheKeyPath.$cacheKey; | |
} | |
/** | |
* Set the cache dir. | |
* | |
* @param string $cacheDir | |
* @param mixed|null $uniqueCacheDir | |
*/ | |
public function setCacheDir($cacheDir, $uniqueCacheDir = null): void | |
{ | |
$this->cacheDir = $cacheDir; | |
$this->uniqueCacheDir = $uniqueCacheDir; | |
} | |
/** | |
* Set the cache timeout. | |
* | |
* @param string $cacheTimeout | |
*/ | |
public function setCacheTimeout($cacheTimeout): void | |
{ | |
$this->cacheTimeout = (int) $cacheTimeout; | |
} | |
/** | |
* Set the widget type. | |
* | |
* @param string $type | |
*/ | |
public function setType($type): void | |
{ | |
$this->type = $type; | |
} | |
/** | |
* Get the widget type. | |
* | |
* @return string $type | |
*/ | |
public function getType() | |
{ | |
return $this->type; | |
} | |
/** | |
* Set the widget entity. | |
*/ | |
public function setWidget(Widget $widget): void | |
{ | |
$this->widget = $widget; | |
$params = $widget->getParams(); | |
// Set required params if undefined | |
if (!isset($params['timeUnit'])) { | |
$params['timeUnit'] = null; | |
} | |
if (!isset($params['amount'])) { | |
$params['amount'] = null; | |
} | |
if (!isset($params['dateFormat'])) { | |
$params['dateFormat'] = null; | |
} | |
if (!isset($params['filter'])) { | |
$params['filter'] = []; | |
} | |
$widget->setParams($params); | |
$this->setType($widget->getType()); | |
$this->setCacheTimeout($widget->getCacheTimeout()); | |
} | |
/** | |
* Returns the widget entity. | |
* | |
* @return Widget $widget | |
*/ | |
public function getWidget() | |
{ | |
return $this->widget; | |
} | |
/** | |
* Set the widget template. | |
* | |
* @param string $template | |
*/ | |
public function setTemplate($template): void | |
{ | |
$this->template = $template; | |
$this->widget->setTemplate($template); | |
} | |
/** | |
* Get the widget template. | |
* | |
* @return string $template | |
*/ | |
public function getTemplate() | |
{ | |
return $this->template; | |
} | |
/** | |
* Set the widget template data. | |
* | |
* @param bool|null $skipCache | |
* | |
* @throws \Psr\Cache\InvalidArgumentException | |
*/ | |
public function setTemplateData(array $templateData, $skipCache = false): void | |
{ | |
$this->templateData = $templateData; | |
$this->widget->setTemplateData($templateData); | |
$this->widget->setLoadTime(abs(microtime(true) - $this->startTime)); | |
if ($this->usesLegacyCache()) { | |
// Store the template data to the cache | |
if (!$skipCache && $this->cacheDir && $this->widget->getCacheTimeout() > 0) { | |
$cache = new CacheStorageHelper(CacheStorageHelper::ADAPTOR_FILESYSTEM, $this->uniqueCacheDir, null, $this->cacheDir); | |
// must pass a DateTime object or a int of seconds to expire as 3rd attribute to set(). | |
$expireTime = $this->widget->getCacheTimeout() * 60; | |
$cache->set($this->getUniqueWidgetId(), $templateData, (int) $expireTime); | |
} | |
} | |
$cItem = $this->cacheProvider->getItem($this->getCacheKey()); | |
if ($this->widget->getCacheTimeout()) { | |
$cItem->expiresAfter((int) $this->widget->getCacheTimeout() * 60); // This is in minutes | |
} | |
$cItem->set($templateData); | |
$this->cacheProvider->save($cItem); | |
} | |
/** | |
* Get the widget template data. | |
* | |
* @return array<mixed> $templateData | |
*/ | |
public function getTemplateData() | |
{ | |
return $this->templateData; | |
} | |
/** | |
* Set en error message. | |
* | |
* @param string $errorMessage | |
*/ | |
public function setErrorMessage($errorMessage): void | |
{ | |
$this->errorMessage = $errorMessage; | |
$this->widget->setErrorMessage($errorMessage); | |
} | |
/** | |
* Get an error message. | |
* | |
* @return string $errorMessage | |
*/ | |
public function getErrorMessage() | |
{ | |
return $this->errorMessage; | |
} | |
/** | |
* Build a unique ID from type and widget params. | |
* | |
* @return string | |
*/ | |
public function getUniqueWidgetId() | |
{ | |
if ($this->uniqueId) { | |
return $this->uniqueId; | |
} | |
$params = $this->getWidget()->getParams(); | |
// Unset dateFrom and dateTo since they constantly change | |
unset($params['dateFrom'], $params['dateTo']); | |
$uniqueSettings = [ | |
'params' => $params, | |
'width' => $this->getWidget()->getWidth(), | |
'height' => $this->getWidget()->getHeight(), | |
'locale' => $this->translator->getLocale(), | |
]; | |
return $this->uniqueId = $this->getType().'_'.substr(md5(json_encode($uniqueSettings)), 0, 16); | |
} | |
/** | |
* @throws \Psr\Cache\InvalidArgumentException | |
* Checks the cache for the widget data. | |
* If cache exists, it sets the TemplateData. | |
*/ | |
public function isCached(): bool | |
{ | |
if (!$this->cacheDir && $this->usesLegacyCache()) { | |
return false; | |
} | |
if ($this->usesLegacyCache()) { | |
$cache = new CacheStorageHelper(CacheStorageHelper::ADAPTOR_FILESYSTEM, $this->uniqueCacheDir, null, $this->cacheDir); | |
$data = $cache->get($this->getUniqueWidgetId(), $this->cacheTimeout); | |
if ($data) { | |
$this->widget->setCached(true); | |
$this->setTemplateData($data, true); | |
return true; | |
} | |
return false; | |
} | |
$cachedItem = $this->cacheProvider->getItem($this->getCacheKey()); | |
if (!$cachedItem->isHit()) { | |
return false; | |
} | |
$this->widget->setCached(true); | |
$this->setTemplateData($cachedItem->get()); | |
return true; | |
} | |
/** | |
* Get the Translator object. | |
* | |
* @return TranslatorInterface | |
*/ | |
public function getTranslator() | |
{ | |
return $this->translator; | |
} | |
/** | |
* Set security object to check the perimissions. | |
* | |
* @depreacated | |
*/ | |
public function setSecurity(CorePermissions $security): void | |
{ | |
$this->security = $security; | |
} | |
/** | |
* Check if the user has at least one permission of defined array of permissions. | |
*/ | |
public function hasPermissions(array $permissions): bool | |
{ | |
if (!$this->security) { | |
return true; | |
} | |
$perm = $this->security->isGranted($permissions, 'RETURN_ARRAY'); | |
return in_array(true, $perm); | |
} | |
/** | |
* Check if the user has defined permission to see the widgets. | |
* | |
* @param string $permission | |
* | |
* @return bool | |
*/ | |
public function hasPermission($permission) | |
{ | |
if (!$this->security) { | |
return true; | |
} | |
return $this->security->isGranted($permission); | |
} | |
/** | |
* Checks for cache type. This event should be created by factory thus not legacy approach. | |
*/ | |
private function usesLegacyCache(): bool | |
{ | |
return is_null($this->cacheProvider); | |
} | |
/** | |
* We need to cast DateTime objects to strings to use them in the cache key. | |
* | |
* @param mixed|null $value | |
* | |
* @throws CouldNotFormatDateTimeException | |
*/ | |
private function castDateTimeToString($value): string | |
{ | |
if ($value instanceof \DateTimeInterface) { | |
// We use RFC 2822 format because it includes timezone | |
return $value->format('r'); | |
} | |
try { | |
$value = strval($value); | |
} catch (\Exception) { | |
throw new CouldNotFormatDateTimeException(); | |
} | |
return $value; | |
} | |
} | |