vendor/pimcore/portal-engine/src/EventSubscriber/StatisticsSubscriber.php line 346

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under following license:
  6.  * - Pimcore Commercial License (PCL)
  7.  *
  8.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  9.  *  @license    http://www.pimcore.org/license     PCL
  10.  */
  11. namespace Pimcore\Bundle\PortalEngineBundle\EventSubscriber;
  12. use Carbon\Carbon;
  13. use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
  14. use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;
  15. use ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery;
  16. use ONGR\ElasticsearchDSL\Search;
  17. use Pimcore\Bundle\PortalEngineBundle\Enum\ElasticSearchFields;
  18. use Pimcore\Bundle\PortalEngineBundle\Enum\Statistics;
  19. use Pimcore\Bundle\PortalEngineBundle\Model\Configuration\DataPool\AssetConfig;
  20. use Pimcore\Bundle\PortalEngineBundle\Model\Configuration\DataPool\DataObjectConfig;
  21. use Pimcore\Bundle\PortalEngineBundle\Service\DataPool\DataPoolConfigService;
  22. use Pimcore\Bundle\PortalEngineBundle\Service\Element\NameExtractorService;
  23. use Pimcore\Bundle\PortalEngineBundle\Service\Element\UrlExtractorService;
  24. use Pimcore\Bundle\PortalEngineBundle\Service\PortalConfig\PortalConfigService;
  25. use Pimcore\Bundle\PortalEngineBundle\Service\SearchIndex\Asset;
  26. use Pimcore\Bundle\PortalEngineBundle\Service\SearchIndex\DataObject;
  27. use Pimcore\Bundle\PortalEngineBundle\Service\SearchIndex\ElasticSearchConfigService;
  28. use Pimcore\Bundle\PortalEngineBundle\Service\SearchIndex\Search\PreConditionService;
  29. use Pimcore\Bundle\PortalEngineBundle\Service\Security\PermissionService;
  30. use Pimcore\Bundle\PortalEngineBundle\Service\Security\SecurityService;
  31. use Pimcore\Bundle\StatisticsExplorerBundle\Events\DataFilterModificationEvent;
  32. use Pimcore\Bundle\StatisticsExplorerBundle\Events\DataResultEvent;
  33. use Pimcore\Bundle\StatisticsExplorerBundle\Events\StatisticsServiceInitEvent;
  34. use Pimcore\Bundle\StatisticsExplorerBundle\Events\TableRenderEvent;
  35. use Pimcore\Bundle\StatisticsExplorerBundle\Model\StatisticsResult;
  36. use Pimcore\Bundle\StatisticsExplorerBundle\StatisticsStorageAdapter\ElasticsearchAdapter;
  37. use Pimcore\Bundle\StatisticsExplorerBundle\StatisticsStorageAdapter\StatisticsStorageAdapterInterface;
  38. use Pimcore\Bundle\StatisticsExplorerBundle\StatisticsStorageAdapter\Worker\ElasticsearchListWorker;
  39. use Pimcore\Bundle\StatisticsExplorerBundle\StatisticsStorageAdapter\Worker\ElasticsearchStatisticWorker;
  40. use Pimcore\Bundle\StatisticsExplorerBundle\Tools\ElasticsearchClientFactory;
  41. use Pimcore\Model\DataObject\ClassDefinition;
  42. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  43. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  44. class StatisticsSubscriber implements EventSubscriberInterface
  45. {
  46.     /**
  47.      * @var DataObject\Search\WorkspaceService
  48.      */
  49.     protected $dataObjectWorkspaceService;
  50.     /**
  51.      * @var Asset\Search\WorkspaceService
  52.      */
  53.     protected $assetWorkspaceService;
  54.     /**
  55.      * @var DataPoolConfigService $dataPoolConfigService
  56.      */
  57.     protected $dataPoolConfigService;
  58.     /**
  59.      * @var PermissionService
  60.      */
  61.     protected $permissionService;
  62.     /**
  63.      * @var SecurityService
  64.      */
  65.     protected $securityService;
  66.     /**
  67.      * @var PreConditionService
  68.      */
  69.     protected $preConditionService;
  70.     /**
  71.      * @var PortalConfigService
  72.      */
  73.     protected $portalConfigService;
  74.     /**
  75.      * @var ElasticsearchClientFactory
  76.      */
  77.     protected $elasticsearchClientFactory;
  78.     /**
  79.      * @var ElasticsearchStatisticWorker
  80.      */
  81.     protected $statisticWorker;
  82.     /**
  83.      * @var ElasticsearchListWorker
  84.      */
  85.     protected $listWorker;
  86.     /**
  87.      * @var EventDispatcherInterface
  88.      */
  89.     protected $eventDispatcher;
  90.     /**
  91.      * @var ElasticSearchConfigService
  92.      */
  93.     protected $elasticSearchConfigService;
  94.     /**
  95.      * @var NameExtractorService
  96.      */
  97.     protected $nameExtractorService;
  98.     /**
  99.      * @var UrlExtractorService
  100.      */
  101.     protected $urlExtractorService;
  102.     /**
  103.      * StatisticsSubscriber constructor.
  104.      *
  105.      * @param DataObject\Search\WorkspaceService $dataObjectWorkspaceService
  106.      * @param Asset\Search\WorkspaceService $assetWorkspaceService
  107.      * @param DataPoolConfigService $dataPoolConfigService
  108.      * @param PermissionService $permissionService
  109.      * @param SecurityService $securityService
  110.      * @param PreConditionService $preConditionService
  111.      * @param PortalConfigService $portalConfigService
  112.      * @param ElasticsearchClientFactory $elasticsearchClientFactory
  113.      * @param ElasticsearchStatisticWorker $statisticWorker
  114.      * @param ElasticsearchListWorker $listWorker
  115.      * @param EventDispatcherInterface $eventDispatcher
  116.      * @param ElasticSearchConfigService $elasticSearchConfigService
  117.      * @param NameExtractorService $nameExtractorService
  118.      * @param UrlExtractorService $urlExtractorService
  119.      */
  120.     public function __construct(
  121.         DataObject\Search\WorkspaceService $dataObjectWorkspaceService,
  122.         Asset\Search\WorkspaceService $assetWorkspaceService,
  123.         DataPoolConfigService $dataPoolConfigService,
  124.         PermissionService $permissionService,
  125.         SecurityService $securityService,
  126.         PreConditionService $preConditionService,
  127.         PortalConfigService $portalConfigService,
  128.         ElasticsearchClientFactory $elasticsearchClientFactory,
  129.         ElasticsearchStatisticWorker $statisticWorker,
  130.         ElasticsearchListWorker $listWorker,
  131.         EventDispatcherInterface $eventDispatcher,
  132.         ElasticSearchConfigService $elasticSearchConfigService,
  133.         NameExtractorService $nameExtractorService,
  134.         UrlExtractorService $urlExtractorService
  135.     ) {
  136.         $this->dataObjectWorkspaceService $dataObjectWorkspaceService;
  137.         $this->assetWorkspaceService $assetWorkspaceService;
  138.         $this->dataPoolConfigService $dataPoolConfigService;
  139.         $this->permissionService $permissionService;
  140.         $this->securityService $securityService;
  141.         $this->preConditionService $preConditionService;
  142.         $this->portalConfigService $portalConfigService;
  143.         $this->elasticsearchClientFactory $elasticsearchClientFactory;
  144.         $this->statisticWorker $statisticWorker;
  145.         $this->listWorker $listWorker;
  146.         $this->eventDispatcher $eventDispatcher;
  147.         $this->elasticSearchConfigService $elasticSearchConfigService;
  148.         $this->nameExtractorService $nameExtractorService;
  149.         $this->urlExtractorService $urlExtractorService;
  150.     }
  151.     public static function getSubscribedEvents()
  152.     {
  153.         return [
  154.             DataFilterModificationEvent::class => 'modifyStatisticsFilter',
  155.             DataResultEvent::class => 'modifyDataResult',
  156.             StatisticsServiceInitEvent::class => 'addDataObjectClassSources',
  157.             TableRenderEvent::class => 'renderAssetListing'
  158.         ];
  159.     }
  160.     /**
  161.      * @param DataFilterModificationEvent $event
  162.      *
  163.      * @throws \Exception
  164.      */
  165.     public function modifyStatisticsFilter(DataFilterModificationEvent $event)
  166.     {
  167.         if ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::ASSET_STATISTICS)) {
  168.             $this->applyAssetDataPoolFilter($event);
  169.         } elseif ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::DATA_OBJECT_STATISTICS)) {
  170.             $this->applyDataObjectDataPoolFilter($event);
  171.         } elseif ($event->getConfiguration() && $event->getConfiguration()->getName() === Statistics::ALL_LOGINS_LAST_SIX_MONTHS) {
  172.             $this->applyLoginsFilter($event);
  173.         }
  174.         if ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::ADD_6_MONTHS_CONDITION)) {
  175.             $this->addLast6MonthsFilter($event);
  176.         }
  177.         if ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::ADD_USER_CONDITION)) {
  178.             $this->addUserFilter($event);
  179.         }
  180.     }
  181.     public function modifyDataResult(DataResultEvent $event)
  182.     {
  183.         if ($event->getConfiguration() && $event->getConfiguration()->getName() === Statistics::ASSET_STORAGE_BY_TYPES) {
  184.             $statisticResult $event->getStatisticsResult();
  185.             $data $statisticResult->getData();
  186.             foreach ($data as $key => $row) {
  187.                 $data[$key]['value'] = ceil($row['value'] / 1000 1000);
  188.                 $data[$key]['label'] = str_replace(' system_fields.fileSize sum'''$row['label']);
  189.             }
  190.             $statisticResult = new StatisticsResult(
  191.                 $data,
  192.                 $statisticResult->getColumnHeaders(),
  193.                 $statisticResult->getRowHeaders()
  194.             );
  195.             $event->setStatisticsResult($statisticResult);
  196.         }
  197.         if ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::FORMAT_TIMESTAMP_STATISTICS)) {
  198.             $statisticResult $event->getStatisticsResult();
  199.             $data $statisticResult->getData();
  200.             foreach ($data as $key => $row) {
  201.                 $data[$key]['timestamp'] = date('Y-m-d H:i:s'strtotime($row['timestamp']));
  202.             }
  203.             $statisticResult = new StatisticsResult(
  204.                 $data,
  205.                 $statisticResult->getColumnHeaders(),
  206.                 $statisticResult->getRowHeaders()
  207.             );
  208.             $event->setStatisticsResult($statisticResult);
  209.         }
  210.     }
  211.     /**
  212.      * @param DataFilterModificationEvent $event
  213.      *
  214.      * @throws \Exception
  215.      */
  216.     protected function applyAssetDataPoolFilter(DataFilterModificationEvent $event)
  217.     {
  218.         $boolQuery = new BoolQuery();
  219.         foreach ($this->dataPoolConfigService->getDataPoolConfigsFromSite() as $dataPoolConfig) {
  220.             if ($dataPoolConfig instanceof AssetConfig) {
  221.                 $this->dataPoolConfigService->setCurrentDataPoolConfig($dataPoolConfig);
  222.                 $mustQuery = new BoolQuery();
  223.                 $mustQuery->add($this->assetWorkspaceService->getElasticSearchWorkspaceQuery(), BoolQuery::MUST);
  224.                 $search = new Search();
  225.                 $this->preConditionService->applyElasticSearchPreConditions($search);
  226.                 /* @phpstan-ignore-next-line */
  227.                 if ($search->getQueries()) {
  228.                     $mustQuery->add($search->getQueries(), BoolQuery::MUST);
  229.                 }
  230.                 $boolQuery->add($mustQueryBoolQuery::SHOULD);
  231.             }
  232.         }
  233.         $excludeFolderQuery = new TermQuery(ElasticSearchFields::SYSTEM_FIELDS '.' ElasticSearchFields::SYSTEM_FIELDS_TYPE'folder');
  234.         $boolQuery->add($excludeFolderQueryBoolQuery::MUST_NOT);
  235.         $event->setFilter($boolQuery->toArray());
  236.     }
  237.     /**
  238.      * @param DataFilterModificationEvent $event
  239.      *
  240.      * @throws \Exception
  241.      */
  242.     protected function applyDataObjectDataPoolFilter(DataFilterModificationEvent $event)
  243.     {
  244.         $boolQuery = new BoolQuery();
  245.         foreach ($this->dataPoolConfigService->getDataPoolConfigsFromSite() as $dataPoolConfig) {
  246.             if ($dataPoolConfig instanceof DataObjectConfig) {
  247.                 $this->dataPoolConfigService->setCurrentDataPoolConfig($dataPoolConfig);
  248.                 $mustQuery = new BoolQuery();
  249.                 $mustQuery->add($this->dataObjectWorkspaceService->getElasticSearchWorkspaceQuery(), BoolQuery::MUST);
  250.                 $classDefinition ClassDefinition::getById($dataPoolConfig->getDataObjectClass());
  251.                 $className $classDefinition $classDefinition->getName() : '-1';
  252.                 $classNameQuery = new TermQuery(ElasticSearchFields::SYSTEM_FIELDS '.' ElasticSearchFields::SYSTEM_FIELDS_CLASS_NAME '.keyword'$className);
  253.                 $mustQuery->add($classNameQueryBoolQuery::MUST);
  254.                 $search = new Search();
  255.                 $this->preConditionService->applyElasticSearchPreConditions($search);
  256.                 /* @phpstan-ignore-next-line */
  257.                 if ($search->getQueries()) {
  258.                     $mustQuery->add($search->getQueries(), BoolQuery::MUST);
  259.                 }
  260.                 $boolQuery->add($mustQueryBoolQuery::SHOULD);
  261.             }
  262.         }
  263.         $event->setFilter($boolQuery->toArray());
  264.     }
  265.     /**
  266.      * @param DataFilterModificationEvent $event
  267.      *
  268.      * @throws \Exception
  269.      */
  270.     protected function applyLoginsFilter(DataFilterModificationEvent $event)
  271.     {
  272.         $filter = new TermQuery('portalId'$this->portalConfigService->getCurrentPortalConfig()->getPortalId()); // @phpstan-ignore-line
  273.         $event->setFilter($filter->toArray());
  274.     }
  275.     protected function addLast6MonthsFilter(DataFilterModificationEvent $event)
  276.     {
  277.         $timestampQuery = new RangeQuery(
  278.             'timestamp', [
  279.                 RangeQuery::GTE => Carbon::createFromTimestamp(strtotime(date('Y-m-1')))->subMonths(6)->format(
  280.                     'Y-m-d\TH:i:sO'
  281.                 ),
  282.             ]
  283.         );
  284.         $event->setFilter([
  285.            'bool' => [
  286.                'must' => [
  287.                    $timestampQuery->toArray(),
  288.                    $event->getFilter()
  289.                ]
  290.            ]
  291.         ]);
  292.     }
  293.     protected function addUserFilter(DataFilterModificationEvent $event)
  294.     {
  295.         $timestampQuery = new TermQuery(
  296.             'userId'$this->securityService->getPortalUser()->getId()
  297.         );
  298.         $event->setFilter([
  299.            'bool' => [
  300.                'must' => [
  301.                    $timestampQuery->toArray(),
  302.                    $event->getFilter()
  303.                ]
  304.            ]
  305.         ]);
  306.     }
  307.     public function addDataObjectClassSources(StatisticsServiceInitEvent $event)
  308.     {
  309.         $statisticsService $event->getStatisticsService();
  310.         $dataPools $this->dataPoolConfigService->getDataPoolConfigsFromSite();
  311.         $classIds = [];
  312.         foreach ($dataPools as $dataPool) {
  313.             if ($dataPool instanceof DataObjectConfig) {
  314.                 $classIds[] = $dataPool->getDataObjectClass();
  315.             }
  316.         }
  317.         $classes = [];
  318.         foreach (array_unique($classIds) as $classId) {
  319.             $classes[] = ClassDefinition::getById($classId);
  320.         }
  321.         foreach ($classes as $class) {
  322.             $indexName $this->elasticSearchConfigService->getIndexName($class->getName());
  323.             $label 'DataObject `' $class->getName() . '`';
  324.             $adapter = new ElasticsearchAdapter($this->elasticsearchClientFactory$indexName$this->statisticWorker$this->listWorker$this->eventDispatcher$label);
  325.             $statisticsService->addDataSourceAdapter('pimcoreportalengine_' $class->getId(), 'portal'$adapter);
  326.         }
  327.     }
  328.     public function renderAssetListing(TableRenderEvent $event)
  329.     {
  330.         if ($event->getConfiguration() && in_array($event->getConfiguration()->getName(), Statistics::RENDER_AS_ASSET_TABLE)) {
  331.             $params $event->getParameters();
  332.             $newParams = [];
  333.             if ($event->getStatisticsMode() === StatisticsStorageAdapterInterface::STATISTICS_MODE_LIST) {
  334.                 if (($params['columnHeaders']['0']['value'] ?? null) === 'system_fields.id') {
  335.                     $newParams = [
  336.                         'labels' => ['asset' => 'Asset''timestamp' => 'Timestamp'],
  337.                         'data' => []
  338.                     ];
  339.                     foreach ($params['data'] as $dataEntry) {
  340.                         $asset \Pimcore\Model\Asset::getById($dataEntry['system_fields.id']);
  341.                         if (empty($asset)) {
  342.                             $dataEntry['asset_name'] = $dataEntry['path'];
  343.                             $dataEntry['asset_url'] = false;
  344.                         } else {
  345.                             $dataEntry['asset_name'] = $this->nameExtractorService->extractName($asset);
  346.                             $dataEntry['asset_url'] = $this->urlExtractorService->extractUrl($asset);
  347.                         }
  348.                         $newParams['data'][] = $dataEntry;
  349.                     }
  350.                 }
  351.             } else {
  352.                 $newParams = [
  353.                     'labels' => ['asset' => 'Asset''result' => 'Result'],
  354.                     'data' => []
  355.                 ];
  356.                 foreach ($params['rowHeaders'] as $row) {
  357.                     $dataEntry = [];
  358.                     $rowHeaders $row['rowHeaders'];
  359.                     $asset \Pimcore\Model\Asset::getById($rowHeaders[0]['value']);
  360.                     if (empty($asset)) {
  361.                         $dataEntry['asset_name'] = $rowHeaders[1]['value'];
  362.                         $dataEntry['asset_url'] = false;
  363.                     } else {
  364.                         $dataEntry['asset_name'] = $this->nameExtractorService->extractName($asset);
  365.                         $dataEntry['asset_url'] = $this->urlExtractorService->extractUrl($asset);
  366.                     }
  367.                     $dataEntry['result'] = $params['data'][$row['dataKey']]['value'] ?? '-';
  368.                     $newParams['data'][] = $dataEntry;
  369.                 }
  370.             }
  371.             $event->setParameters($newParams);
  372.             $event->setTemplate('@PimcorePortalEngine/statistic_explorer/asset-data-list.html.twig');
  373.         }
  374.     }
  375. }