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

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