323 lines
9.9 KiB
PHP
Executable File
323 lines
9.9 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Mautic\DashboardBundle\Model;
|
|
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Mautic\CacheBundle\Cache\CacheProviderTagAwareInterface;
|
|
use Mautic\CoreBundle\Helper\CacheStorageHelper;
|
|
use Mautic\CoreBundle\Helper\CoreParametersHelper;
|
|
use Mautic\CoreBundle\Helper\Filesystem;
|
|
use Mautic\CoreBundle\Helper\InputHelper;
|
|
use Mautic\CoreBundle\Helper\PathsHelper;
|
|
use Mautic\CoreBundle\Helper\UserHelper;
|
|
use Mautic\CoreBundle\Model\FormModel;
|
|
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
|
|
use Mautic\CoreBundle\Translation\Translator;
|
|
use Mautic\DashboardBundle\DashboardEvents;
|
|
use Mautic\DashboardBundle\Entity\Widget;
|
|
use Mautic\DashboardBundle\Entity\WidgetRepository;
|
|
use Mautic\DashboardBundle\Event\WidgetDetailEvent;
|
|
use Mautic\DashboardBundle\Factory\WidgetDetailEventFactory;
|
|
use Mautic\DashboardBundle\Form\Type\WidgetType;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
use Symfony\Component\Filesystem\Exception\IOException;
|
|
use Symfony\Component\Form\FormFactoryInterface;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|
|
|
/**
|
|
* @extends FormModel<Widget>
|
|
*/
|
|
class DashboardModel extends FormModel
|
|
{
|
|
public function __construct(
|
|
CoreParametersHelper $coreParametersHelper,
|
|
private PathsHelper $pathsHelper,
|
|
private WidgetDetailEventFactory $widgetEventFactory,
|
|
private Filesystem $filesystem,
|
|
private RequestStack $requestStack,
|
|
EntityManagerInterface $em,
|
|
CorePermissions $security,
|
|
EventDispatcherInterface $dispatcher,
|
|
UrlGeneratorInterface $router,
|
|
Translator $translator,
|
|
UserHelper $userHelper,
|
|
LoggerInterface $mauticLogger,
|
|
private CacheProviderTagAwareInterface $cacheProvider,
|
|
) {
|
|
parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $mauticLogger, $coreParametersHelper);
|
|
}
|
|
|
|
public function getRepository(): WidgetRepository
|
|
{
|
|
return $this->em->getRepository(Widget::class);
|
|
}
|
|
|
|
public function getPermissionBase(): string
|
|
{
|
|
return 'dashboard:widgets';
|
|
}
|
|
|
|
/**
|
|
* Get a specific entity or generate a new one if id is empty.
|
|
*/
|
|
public function getEntity($id = null): ?Widget
|
|
{
|
|
if (null === $id) {
|
|
return new Widget();
|
|
}
|
|
|
|
return parent::getEntity($id);
|
|
}
|
|
|
|
/**
|
|
* Load widgets for the current user from database.
|
|
*
|
|
* @param bool $ignorePaginator
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getWidgets($ignorePaginator = false)
|
|
{
|
|
return $this->getEntities([
|
|
'orderBy' => 'w.ordering',
|
|
'filter' => [
|
|
'force' => [
|
|
[
|
|
'column' => 'w.createdBy',
|
|
'expr' => 'eq',
|
|
'value' => $this->userHelper->getUser()->getId(),
|
|
],
|
|
],
|
|
],
|
|
'ignore_paginator' => $ignorePaginator,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Creates an array that represents the dashboard and all its widgets.
|
|
* Useful for dashboard exports.
|
|
*
|
|
* @param string $name
|
|
*/
|
|
public function toArray($name): array
|
|
{
|
|
return [
|
|
'name' => $name,
|
|
'description' => $this->generateDescription(),
|
|
'widgets' => array_map(
|
|
fn ($widget) => $widget->toArray(),
|
|
$this->getWidgets(true)
|
|
),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Saves the dashboard snapshot to the user folder.
|
|
*
|
|
* @param string $name
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
public function saveSnapshot($name): void
|
|
{
|
|
$dir = $this->pathsHelper->getSystemPath('dashboard.user');
|
|
$filename = InputHelper::filename($name, 'json');
|
|
$path = $dir.'/'.$filename;
|
|
$this->filesystem->dumpFile($path, json_encode($this->toArray($name)));
|
|
}
|
|
|
|
/**
|
|
* Generates a translatable description for a dashboard.
|
|
*/
|
|
public function generateDescription(): string
|
|
{
|
|
return $this->translator->trans(
|
|
'mautic.dashboard.generated_by',
|
|
[
|
|
'%name%' => $this->userHelper->getUser()->getName(),
|
|
'%date%' => (new \DateTime())->format('Y-m-d H:i:s'),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fill widgets with their empty content.
|
|
*
|
|
* @param array<mixed> $widgets
|
|
*/
|
|
public function populateWidgetPreviews(&$widgets): void
|
|
{
|
|
if (count($widgets)) {
|
|
foreach ($widgets as &$widget) {
|
|
$this->populateWidgetPreview($widget);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fill widgets with their content.
|
|
*
|
|
* @param array $widgets
|
|
* @param array $filter
|
|
*/
|
|
public function populateWidgetsContent(&$widgets, $filter = []): void
|
|
{
|
|
if (count($widgets)) {
|
|
foreach ($widgets as &$widget) {
|
|
if (!($widget instanceof Widget)) {
|
|
$widget = $this->populateWidgetEntity($widget);
|
|
}
|
|
$this->populateWidgetContent($widget, $filter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new Widget object from an array data.
|
|
*/
|
|
public function populateWidgetEntity(array $data): Widget
|
|
{
|
|
$entity = new Widget();
|
|
|
|
foreach ($data as $property => $value) {
|
|
$method = 'set'.ucfirst($property);
|
|
if (method_exists($entity, $method)) {
|
|
$entity->$method($value);
|
|
}
|
|
unset($data[$property]);
|
|
}
|
|
|
|
return $entity;
|
|
}
|
|
|
|
/**
|
|
* Populate widget preview.
|
|
*/
|
|
public function populateWidgetPreview(Widget $widget): void
|
|
{
|
|
$event = $this->widgetEventFactory->create($widget);
|
|
|
|
$this->dispatcher->dispatch($event, DashboardEvents::DASHBOARD_ON_MODULE_DETAIL_PRE_LOAD);
|
|
}
|
|
|
|
/**
|
|
* Load widget content from the onWidgetDetailGenerate event.
|
|
*
|
|
* @param array $filter
|
|
*/
|
|
public function populateWidgetContent(Widget $widget, $filter = []): void
|
|
{
|
|
$defaultTimeout = $this->coreParametersHelper->get('cached_data_timeout');
|
|
|
|
// Timeout 0 will be interpreted as endless cache, so we set it to -1 which will be interpreted as no cache
|
|
if (0 === $defaultTimeout) {
|
|
$defaultTimeout = -1;
|
|
}
|
|
|
|
if (null === $widget->getCacheTimeout() || -1 === $widget->getCacheTimeout()) {
|
|
$widget->setCacheTimeout($defaultTimeout);
|
|
}
|
|
|
|
// Merge global filter with widget params
|
|
$widgetParams = $widget->getParams();
|
|
$resultParams = array_merge($widgetParams, $filter);
|
|
|
|
// Add the user timezone
|
|
if (empty($resultParams['timezone'])) {
|
|
$resultParams['timezone'] = $this->userHelper->getUser()->getTimezone();
|
|
}
|
|
|
|
// Clone the objects in param array to avoid reference issues if some subscriber changes them
|
|
foreach ($resultParams as &$param) {
|
|
if (is_object($param)) {
|
|
$param = clone $param;
|
|
}
|
|
}
|
|
|
|
$widget->setParams($resultParams);
|
|
|
|
$this->dispatcher->dispatch(
|
|
$this->widgetEventFactory->create($widget),
|
|
DashboardEvents::DASHBOARD_ON_MODULE_DETAIL_GENERATE
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Clears the temporary widget cache.
|
|
*/
|
|
public function clearDashboardCache(): void
|
|
{
|
|
$cacheDir = $this->coreParametersHelper->get('cached_data_dir', $this->pathsHelper->getSystemPath('cache', true));
|
|
$cacheStorage = new CacheStorageHelper(CacheStorageHelper::ADAPTOR_FILESYSTEM, $this->userHelper->getUser()->getId(), null, $cacheDir);
|
|
|
|
$cacheStorage->clear();
|
|
|
|
$this->cacheProvider->invalidateTags([WidgetDetailEvent::DASHBOARD_CACHE_TAG]);
|
|
}
|
|
|
|
/**
|
|
* @param Widget $entity
|
|
* @param string|null $action
|
|
* @param array $options
|
|
*
|
|
* @return \Symfony\Component\Form\FormInterface<mixed>
|
|
*
|
|
* @throws MethodNotAllowedHttpException
|
|
*/
|
|
public function createForm($entity, FormFactoryInterface $formFactory, $action = null, $options = []): \Symfony\Component\Form\FormInterface
|
|
{
|
|
if (!$entity instanceof Widget) {
|
|
throw new MethodNotAllowedHttpException(['Widget'], 'Entity must be of class Widget()');
|
|
}
|
|
|
|
if (!empty($action)) {
|
|
$options['action'] = $action;
|
|
}
|
|
|
|
return $formFactory->create(WidgetType::class, $entity, $options);
|
|
}
|
|
|
|
/**
|
|
* Create/edit entity.
|
|
*
|
|
* @param object $entity
|
|
* @param bool $unlock
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function saveEntity($entity, $unlock = true): void
|
|
{
|
|
// Set widget name from widget type if empty
|
|
if (!$entity->getName()) {
|
|
$entity->setName($this->translator->trans('mautic.widget.'.$entity->getType()));
|
|
}
|
|
|
|
$entity->setDateModified(new \DateTime());
|
|
|
|
parent::saveEntity($entity, $unlock);
|
|
}
|
|
|
|
/**
|
|
* Generate default date range filter and time unit.
|
|
*/
|
|
public function getDefaultFilter(): array
|
|
{
|
|
$dateRangeDefault = $this->coreParametersHelper->get('default_daterange_filter', '-1 month');
|
|
$dateRangeStart = new \DateTime();
|
|
$dateRangeStart->modify($dateRangeDefault);
|
|
|
|
$session = $this->requestStack->getSession();
|
|
$today = new \DateTime();
|
|
$dateFrom = new \DateTime($session->get('mautic.daterange.form.from', $dateRangeStart->format('Y-m-d 00:00:00')));
|
|
$dateTo = new \DateTime($session->get('mautic.daterange.form.to', $today->format('Y-m-d 23:59:59')));
|
|
|
|
return [
|
|
'dateFrom' => $dateFrom,
|
|
'dateTo' => $dateTo->modify('23:59:59'), // till end of the 'to' date selected
|
|
];
|
|
}
|
|
}
|