vendor/pimcore/data-hub-simple-rest/src/Service/IndexService.php line 190

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\DataHubSimpleRestBundle\Service;
  12. use Pimcore\Bundle\DataHubSimpleRestBundle\MappingAndDataExtractor\AbstractMappingAndDataExtractor;
  13. use Pimcore\Bundle\DataHubSimpleRestBundle\MappingAndDataExtractor\DataExtractorFactory;
  14. class IndexService extends AbstractService
  15. {
  16.     const LOCK_NAME_PREFIX 'datahub-simplerest-indexservice-';
  17.     /**
  18.      * @param string $configName
  19.      *
  20.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  21.      */
  22.     protected function checkAndCreateIndexAlias(string $configName)
  23.     {
  24.         foreach ($this->getDataExtractorsForConfig($configName) as $type => $mappingAndDataExtractor) {
  25.             $this->indexHandler->checkAndCreateIndexAlias($mappingAndDataExtractor);
  26.         }
  27.     }
  28.     /**
  29.      * @param string|null $configName
  30.      *
  31.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  32.      */
  33.     public function createOrUpdateMapping(string $configName null)
  34.     {
  35.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  36.             $lockname self::LOCK_NAME_PREFIX $configName;
  37.             $lock $this->lockFactory->createLock($lockname);
  38.             if (!$lock->acquire()) {
  39.                 throw new \Exception("IndexService for config '$configName' already locked.");
  40.             }
  41.             try {
  42.                 $usedIndices = [];
  43.                 $this->checkAndCreateIndexAlias($configName);
  44.                 foreach ($this->getDataExtractorsForConfig($configName) as $type => $mappingAndDataExtractor) {
  45.                     $this->indexHandler->createOrUpdateMapping($mappingAndDataExtractor);
  46.                     $usedIndices[] = $mappingAndDataExtractor->getIndexName();
  47.                 }
  48.                 $this->indexHandler->cleanupUnusedEsIndices($this->indexNamePrefix '_' $configName$usedIndices);
  49.             } finally {
  50.                 $lock->release();
  51.             }
  52.         }
  53.     }
  54.     /**
  55.      * @param string $configName
  56.      *
  57.      * @return array
  58.      *
  59.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  60.      */
  61.     public function getLabelKeysFromIndex(string $configName): array
  62.     {
  63.         $allAttributes = [];
  64.         foreach ($this->getDataExtractorsForConfig($configName) as $type => $mappingAndDataExtractor) {
  65.             $allAttributes array_merge(
  66.                 $allAttributes,
  67.                 $this->indexHandler->getLabelKeysFromIndex($mappingAndDataExtractor->getIndexName(), $mappingAndDataExtractor->getLabelBlackList())
  68.             );
  69.         }
  70.         return array_unique($allAttributes);
  71.     }
  72.     /**
  73.      * @param string $configName
  74.      */
  75.     public function cleanupIndicesForConfig(string $configName)
  76.     {
  77.         $this->indexHandler->cleanupUnusedEsIndices($this->indexNamePrefix '_' $configName, []);
  78.     }
  79.     /**
  80.      * @param int $elementId
  81.      * @param string $entityType
  82.      * @param string|null $configName
  83.      *
  84.      * @return bool
  85.      *
  86.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  87.      */
  88.     public function doIndexData($elementIdstring $entityTypestring $configName null): bool
  89.     {
  90.         $originalConfigName $configName;
  91.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  92.             $mappingAndDataExtractor $this->getDataExtractorForConfigAndEntityType($configName$entityType);
  93.             if ($mappingAndDataExtractor) {
  94.                 $data $mappingAndDataExtractor->extractData($elementId);
  95.                 $dataExtractorCollection $this->getDataExtractorCollectionForConfigAndType($configName$entityType);
  96.                 $possibleElementIndices = [];
  97.                 foreach ($dataExtractorCollection as $dataExtractor) {
  98.                     $possibleElementIndices[] = $dataExtractor->getIndexName();
  99.                 }
  100.                 //get existing item from index - theoretical max count is number of indices
  101.                 $indexElements $this->indexHandler->queryIndexById($possibleElementIndices$elementIdcount($possibleElementIndices));
  102.                 //add old parent element to queue - to update or delete it
  103.                 if ($indexElements['total_count'] > 0) {
  104.                     foreach ($indexElements['items'] as $indexElement) {
  105.                         $parentIndexElement $this->indexHandler->queryIndexById($possibleElementIndices$indexElement['system']['parentId']);
  106.                         if ($parentIndexElement) {
  107.                             $this->addItemToQueue($parentIndexElement['system']['id'], $parentIndexElement['system'][AbstractMappingAndDataExtractor::INTERNAL_ENTITY_TYPE], $originalConfigName == null null $configName);
  108.                         }
  109.                     }
  110.                 }
  111.                 if (empty($data)) {
  112.                     if ($indexElements['total_count'] > 0) {
  113.                         // if there is no child element, delete
  114.                         // if there is one, it might be a virtual parent folder that must not be deleted - except if there is more than one element with same ID in index (might be left over of virtual parents)
  115.                         if (!$this->indexHandler->hasChildElementInIndex($possibleElementIndices$elementId) || $indexElements['total_count'] > 1) {
  116.                             $this->indexHandler->deleteItem($mappingAndDataExtractor->getIndexName(), $elementId);
  117.                         }
  118.                     }
  119.                 } else {
  120.                     if ($entityType === DataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET || $entityType == DataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET_FOLDER) {
  121.                         //parents are in asset folder
  122.                         $folderMappingExtractor $this->getDataExtractorForConfigAndEntityType($configNameDataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET_FOLDER);
  123.                     } else {
  124.                         //parents are in object folder
  125.                         $folderMappingExtractor $this->getDataExtractorForConfigAndEntityType($configNameDataExtractorFactory::DATA_EXTRACTOR_TYPE_OBJECT_FOLDER);
  126.                     }
  127.                     //check if element is in folder index and if entity type is not folder -> delete from index to avoid duplicate entries
  128.                     foreach ($indexElements['items'] as $indexElement) {
  129.                         if (
  130.                             !in_array($entityType, [DataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET_FOLDERDataExtractorFactory::DATA_EXTRACTOR_TYPE_OBJECT_FOLDER]) &&
  131.                             $indexElement && in_array($indexElement['system'][AbstractMappingAndDataExtractor::INTERNAL_ENTITY_TYPE], [DataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET_FOLDERDataExtractorFactory::DATA_EXTRACTOR_TYPE_OBJECT_FOLDER])
  132.                         ) {
  133.                             $this->indexHandler->deleteItem($folderMappingExtractor->getIndexName(), $elementId);
  134.                         }
  135.                     }
  136.                     //add new element
  137.                     $this->indexHandler->indexItem($mappingAndDataExtractor->getIndexName(), $elementId$data);
  138.                     //check if parent element is in any index of config ... if not add a virutal folder to folder index
  139.                     $virtualParentArray $mappingAndDataExtractor->getVirtualParentArray($elementId);
  140.                     if ($virtualParentArray) {
  141.                         //check if new parent(s) are already in index - add or update them
  142.                         foreach ($virtualParentArray as $virtualParent) {
  143.                             if ($newParentIndexElement $this->indexHandler->queryIndexById($possibleElementIndices$virtualParent['id'])) {
  144.                                 $this->addItemToQueue($newParentIndexElement['system']['id'], $newParentIndexElement['system'][AbstractMappingAndDataExtractor::INTERNAL_ENTITY_TYPE], $originalConfigName == null null $configName);
  145.                                 break;
  146.                             } else {
  147.                                 $this->indexHandler->indexItem($folderMappingExtractor->getIndexName(), $virtualParent['id'], $virtualParent['data']);
  148.                             }
  149.                         }
  150.                     }
  151.                 }
  152.             }
  153.         }
  154.         return true;
  155.     }
  156.     /**
  157.      * @param int $elementId
  158.      * @param string $entityType
  159.      * @param string|null $configName
  160.      */
  161.     public function addItemToQueue($elementIdstring $entityTypestring $configName null)
  162.     {
  163.         $this->queueService->addItemToQueue($elementId$entityType$configName);
  164.     }
  165.     /**
  166.      * @param int $limit
  167.      *
  168.      * @return array
  169.      */
  170.     public function getAllQueueEntries($limit 100000): array
  171.     {
  172.         return $this->queueService->getAllQueueEntries($limit);
  173.     }
  174.     /**
  175.      * @param int $elementId
  176.      * @param string $entityType
  177.      * @param string $configName
  178.      *
  179.      * @return bool
  180.      *
  181.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  182.      */
  183.     public function processQueueEntry($elementId$entityType$configName): bool
  184.     {
  185.         $success false;
  186.         try {
  187.             $success $this->doIndexData($elementId$entityType$configName);
  188.             if ($success) {
  189.                 $this->queueService->markQueueEntryAsProcessed($elementId$entityType$configName);
  190.             }
  191.         } catch (\Exception $e) {
  192.             $this->logger->error($e->getMessage());
  193.         }
  194.         return $success;
  195.     }
  196.     /**
  197.      * @param string|null $configName
  198.      *
  199.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  200.      */
  201.     public function initIndex(string $configName null)
  202.     {
  203.         $originalConfigName $configName;
  204.         $this->invalidateIndexAll($configName);
  205.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  206.             foreach ($this->getDataExtractorsForConfig($configName) as $type => $mappingAndDataExtractor) {
  207.                 //do not init folders as they are initialized implicitly with parents that are added
  208.                 //so we avoid empty folders in index
  209.                 if ($type !== DataExtractorFactory::DATA_EXTRACTOR_TYPE_OBJECT_FOLDER && $type !== DataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET_FOLDER) {
  210.                     $ids $mappingAndDataExtractor->calculateAllElementIds();
  211.                     foreach ($ids as $id) {
  212.                         $this->queueService->addItemToQueue($id$type$originalConfigName == null null $configName);
  213.                     }
  214.                 }
  215.             }
  216.         }
  217.     }
  218.     public function invalidateDuplicateIndexEntries(string $configName null)
  219.     {
  220.         $originalConfigName $configName;
  221.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  222.             //for assets
  223.             $dataExtractorCollection $this->getDataExtractorCollectionForConfigAndType($configNameDataExtractorFactory::DATA_EXTRACTOR_TYPE_ASSET);
  224.             if ($dataExtractorCollection) {
  225.                 $indexNames = [];
  226.                 foreach ($dataExtractorCollection as $dataExtractor) {
  227.                     $indexNames[] = $dataExtractor->getIndexName();
  228.                 }
  229.                 $duplicateEntries $this->indexHandler->findDuplicateElements($indexNames);
  230.                 foreach ($duplicateEntries as $entry) {
  231.                     $this->queueService->addItemToQueue($entry['id'], $entry[AbstractMappingAndDataExtractor::INTERNAL_ENTITY_TYPE], $originalConfigName == null null $configName);
  232.                 }
  233.             }
  234.             //for objects
  235.             $dataExtractorCollection $this->getDataExtractorCollectionForConfigAndType($configNameDataExtractorFactory::DATA_EXTRACTOR_TYPE_OBJECT_FOLDER);
  236.             if ($dataExtractorCollection) {
  237.                 $indexNames = [];
  238.                 foreach ($dataExtractorCollection as $dataExtractor) {
  239.                     $indexNames[] = $dataExtractor->getIndexName();
  240.                 }
  241.                 $duplicateEntries $this->indexHandler->findDuplicateElements($indexNames);
  242.                 foreach ($duplicateEntries as $entry) {
  243.                     $this->queueService->addItemToQueue($entry['id'], $entry[AbstractMappingAndDataExtractor::INTERNAL_ENTITY_TYPE], $originalConfigName == null null $configName);
  244.                 }
  245.             }
  246.         }
  247.     }
  248.     /**
  249.      * @param string|null $configName
  250.      *
  251.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  252.      */
  253.     public function invalidateIndexAll(string $configName null)
  254.     {
  255.         $originalConfigName $configName;
  256.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  257.             foreach ($this->getDataExtractorsForConfig($configName) as $type => $mappingAndDataExtractor) {
  258.                 $allIds $this->indexHandler->getAllIdsFromIndex($mappingAndDataExtractor->getIndexName());
  259.                 foreach ($allIds as $id) {
  260.                     $this->addItemToQueue($id$type$originalConfigName == null null $configName);
  261.                 }
  262.             }
  263.         }
  264.     }
  265.     /**
  266.      * @param string $path
  267.      * @param string $entityType
  268.      * @param string|null $configName
  269.      *
  270.      * @throws \Pimcore\Bundle\DataHubSimpleRestBundle\Exception\InvalidRequestException
  271.      */
  272.     public function invalidateIndexByOriginalPath(string $pathstring $entityTypestring $configName null)
  273.     {
  274.         $originalConfigName $configName;
  275.         foreach ($this->getConfigsToProcess($configName) as $configName) {
  276.             foreach ($this->getDataExtractorCollectionForConfigAndType($configName$entityType) as $type => $mappingAndDataExtractor) {
  277.                 $allIds $this->indexHandler->getAllIdsFromIndexByOriginalPath($mappingAndDataExtractor->getIndexName(), $path);
  278.                 foreach ($allIds as $id) {
  279.                     $this->addItemToQueue($id$type$originalConfigName == null null $configName);
  280.                 }
  281.             }
  282.         }
  283.     }
  284. }