![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Action/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Action; use Magento\Catalog\Api\Data\ProductInterface; use Magento\CatalogSearch\Model\Indexer\Fulltext; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; /** * Class provides iterator through number of products suitable for fulltext indexation * * To be suitable for fulltext index product must meet set of requirements: * - to be visible on frontend * - to be enabled * - in case product is composite at least one sub product must be visible and enabled * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @api * @since 100.0.2 */ class Full { /** * Scope identifier */ public const SCOPE_FIELD_NAME = 'scope'; /** * Searchable attributes cache * * @var \Magento\Eav\Model\Entity\Attribute[] */ protected $searchableAttributes; /** * Index values separator * * @var string * @deprecated 100.1.0 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::$separator */ protected $separator = ' | '; /** * Array of \DateTime objects per store * * @var \DateTime[] * @deprecated 100.1.0 Not used anymore */ protected $dates = []; /** * Product Type Instances cache * * @var array * @deprecated 100.1.0 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::$productTypes */ protected $productTypes = []; /** * Product Emulators cache * * @var array * @deprecated 100.1.0 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::$productEmulators */ protected $productEmulators = []; /** * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory */ protected $productAttributeCollectionFactory; /** * * @var \Magento\Catalog\Model\Product\Attribute\Source\Status */ protected $catalogProductStatus; /** * * @var \Magento\Eav\Model\Config */ protected $eavConfig; /** * * @var \Magento\Catalog\Model\Product\Type * @deprecated 100.1.0 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::$catalogProductType */ protected $catalogProductType; /** * Core event manager proxy * * @var \Magento\Framework\Event\ManagerInterface */ protected $eventManager; /** * Core store config * * @var \Magento\Framework\App\Config\ScopeConfigInterface * @deprecated 100.1.0 Not used anymore */ protected $scopeConfig; /** * * @var \Magento\Store\Model\StoreManagerInterface * @deprecated 100.1.0 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::$storeManager */ protected $storeManager; /** * @var \Magento\CatalogSearch\Model\ResourceModel\EngineInterface */ protected $engine; /** * @var \Magento\Framework\Indexer\SaveHandler\IndexerInterface * @deprecated 100.1.0 As part of self::cleanIndex() */ protected $indexHandler; /** * @var \Magento\Framework\Stdlib\DateTime * @deprecated 100.1.0 Not used anymore */ protected $dateTime; /** * @var \Magento\Framework\Locale\ResolverInterface * @deprecated 100.1.0 Not used anymore */ protected $localeResolver; /** * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface * @deprecated 100.1.0 Not used anymore */ protected $localeDate; /** * @var Resource */ protected $resource; /** * @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext * @deprecated 100.1.0 Not used anymore */ protected $fulltextResource; /** * @var \Magento\Framework\Search\Request\Config * @deprecated 100.1.0 As part of self::reindexAll() */ protected $searchRequestConfig; /** * @var \Magento\Framework\Search\Request\DimensionFactory * @deprecated 100.1.0 As part of self::cleanIndex() */ private $dimensionFactory; /** * @var \Magento\Framework\DB\Adapter\AdapterInterface */ protected $connection; /** * @var \Magento\Framework\EntityManager\MetadataPool */ private $metadataPool; /** * @var DataProvider */ private $dataProvider; /** * Batch size for searchable product ids * * @var int */ private $batchSize; /** * @var DeploymentConfig|null */ private $deploymentConfig; /** * Deployment config path * * @var string */ private const DEPLOYMENT_CONFIG_INDEXER_BATCHES = 'indexer/batch_size/'; /** * Full constructor. * @param ResourceConnection $resource * @param \Magento\Catalog\Model\Product\Type $catalogProductType * @param \Magento\Eav\Model\Config $eavConfig * @param \Magento\Framework\Search\Request\Config $searchRequestConfig * @param \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttributeCollectionFactory * @param \Magento\CatalogSearch\Model\ResourceModel\EngineProvider $engineProvider * @param \Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory $indexHandlerFactory * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Framework\Locale\ResolverInterface $localeResolver * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext $fulltextResource * @param \Magento\Framework\Search\Request\DimensionFactory $dimensionFactory * @param \Magento\Framework\Indexer\ConfigInterface $indexerConfig * @param mixed $indexIteratorFactory * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param DataProvider|null $dataProvider * @param int $batchSize * @param DeploymentConfig|null $deploymentConfig * * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( ResourceConnection $resource, \Magento\Catalog\Model\Product\Type $catalogProductType, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Search\Request\Config $searchRequestConfig, \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus, \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttributeCollectionFactory, \Magento\CatalogSearch\Model\ResourceModel\EngineProvider $engineProvider, \Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory $indexHandlerFactory, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\Stdlib\DateTime $dateTime, \Magento\Framework\Locale\ResolverInterface $localeResolver, \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, \Magento\CatalogSearch\Model\ResourceModel\Fulltext $fulltextResource, \Magento\Framework\Search\Request\DimensionFactory $dimensionFactory, \Magento\Framework\Indexer\ConfigInterface $indexerConfig, $indexIteratorFactory = null, \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, DataProvider $dataProvider = null, $batchSize = 1000, ?DeploymentConfig $deploymentConfig = null ) { $this->resource = $resource; $this->connection = $resource->getConnection(); $this->catalogProductType = $catalogProductType; $this->eavConfig = $eavConfig; $this->searchRequestConfig = $searchRequestConfig; $this->catalogProductStatus = $catalogProductStatus; $this->productAttributeCollectionFactory = $prodAttributeCollectionFactory; $this->eventManager = $eventManager; $this->scopeConfig = $scopeConfig; $this->storeManager = $storeManager; $this->engine = $engineProvider->get(); $configData = $indexerConfig->getIndexer(Fulltext::INDEXER_ID); $this->indexHandler = $indexHandlerFactory->create(['data' => $configData]); $this->dateTime = $dateTime; $this->localeResolver = $localeResolver; $this->localeDate = $localeDate; $this->fulltextResource = $fulltextResource; $this->dimensionFactory = $dimensionFactory; $this->metadataPool = $metadataPool ?: ObjectManager::getInstance() ->get(\Magento\Framework\EntityManager\MetadataPool::class); $this->dataProvider = $dataProvider ?: ObjectManager::getInstance()->get(DataProvider::class); $this->batchSize = $batchSize; $this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class); } /** * Rebuild whole fulltext index for all stores * * @deprecated 100.1.6 Please use \Magento\CatalogSearch\Model\Indexer\Fulltext::executeFull instead * @see \Magento\CatalogSearch\Model\Indexer\Fulltext::executeFull * @return void */ public function reindexAll() { $storeIds = array_keys($this->storeManager->getStores()); foreach ($storeIds as $storeId) { $this->cleanIndex($storeId); $this->rebuildStoreIndex($storeId); } $this->searchRequestConfig->reset(); } /** * Return validated table name * * @param string|string[] $table * @return string */ protected function getTable($table) { return $this->resource->getTableName($table); } /** * Get parents IDs of product IDs to be re-indexed * * @deprecated 100.2.3 as it not used in the class anymore and duplicates another API method * @see \Magento\CatalogSearch\Model\ResourceModel\Fulltext::getRelationsByChild() * * @param int[] $entityIds * @return int[] * @throws \Exception */ protected function getProductIdsFromParents(array $entityIds) { $connection = $this->connection; $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $select = $connection ->select() ->from(['relation' => $this->getTable('catalog_product_relation')], []) ->distinct(true) ->where('child_id IN (?)', $entityIds, \Zend_Db::INT_TYPE) ->join( ['cpe' => $this->getTable('catalog_product_entity')], 'relation.parent_id = cpe.' . $linkField, ['cpe.entity_id'] ); return $connection->fetchCol($select); } /** * Regenerate search index for specific store * * To be suitable for indexation product must meet set of requirements: * - to be visible on frontend * - to be enabled * - in case product is composite at least one sub product must be enabled * * @param int $storeId Store View Id * @param int[] $productIds Product Entity Id * @return \Generator */ public function rebuildStoreIndex($storeId, $productIds = null) { if ($productIds !== null) { $productIds = array_unique($productIds); } // prepare searchable attributes $staticFields = []; foreach ($this->getSearchableAttributes('static') as $attribute) { $staticFields[] = $attribute->getAttributeCode(); } $dynamicFields = [ 'int' => array_keys($this->dataProvider->getSearchableAttributes('int')), 'varchar' => array_keys($this->dataProvider->getSearchableAttributes('varchar')), 'text' => array_keys($this->dataProvider->getSearchableAttributes('text')), 'decimal' => array_keys($this->dataProvider->getSearchableAttributes('decimal')), 'datetime' => array_keys($this->dataProvider->getSearchableAttributes('datetime')), ]; $lastProductId = 0; $this->batchSize = $this->deploymentConfig->get( self::DEPLOYMENT_CONFIG_INDEXER_BATCHES . Fulltext::INDEXER_ID . '/mysql_get' ) ?? $this->batchSize; $products = $this->dataProvider ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $this->batchSize); while (count($products) > 0) { $productsIds = array_column($products, 'entity_id'); $relatedProducts = $this->getRelatedProducts($products); $productsIds = array_merge($productsIds, array_values($relatedProducts)); $productsAttributes = $this->dataProvider->getProductAttributes($storeId, $productsIds, $dynamicFields); foreach ($products as $productData) { $lastProductId = $productData['entity_id']; $productIndex = [$productData['entity_id'] => $productsAttributes[$productData['entity_id']]]; if (isset($relatedProducts[$productData['entity_id']])) { $childProductsIndex = $this->getChildProductsIndex( $productData['entity_id'], $relatedProducts, $productsAttributes ); if (empty($childProductsIndex)) { continue; } $productIndex = $productIndex + $childProductsIndex; } $index = $this->dataProvider->prepareProductIndex($productIndex, $productData, $storeId); yield $productData['entity_id'] => $index; } $products = $this->dataProvider ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $this->batchSize); } } /** * Get related (child) products ids * * Load related (child) products ids for composite product type * * @param array $products * @return array */ private function getRelatedProducts($products) { $relatedProducts = []; foreach ($products as $productData) { $relatedProducts[$productData['entity_id']] = $this->dataProvider->getProductChildIds( $productData['entity_id'], $productData['type_id'] ); } return array_filter($relatedProducts); } /** * Performs check that product is enabled on Store Front * * Check that product is enabled on Store Front using status attribute * and statuses allowed to be visible on Store Front. * * @param int $productId * @param array $productsAttributes * @return bool */ private function isProductEnabled($productId, array $productsAttributes) { $status = $this->dataProvider->getSearchableAttribute('status'); $allowedStatuses = $this->catalogProductStatus->getVisibleStatusIds(); return isset($productsAttributes[$productId][$status->getId()]) && in_array($productsAttributes[$productId][$status->getId()], $allowedStatuses); } /** * Get data for index using related(child) products data * * Build data for index using child products(if any). * Use only enabled child products {@see isProductEnabled}. * * @param int $parentId * @param array $relatedProducts * @param array $productsAttributes * @return array */ private function getChildProductsIndex($parentId, array $relatedProducts, array $productsAttributes) { $productIndex = []; foreach ($relatedProducts[$parentId] as $productChildId) { if ($this->isProductEnabled($productChildId, $productsAttributes)) { $productIndex[$productChildId] = $productsAttributes[$productChildId]; } } return $productIndex; } /** * Clean search index data for store * * @deprecated 100.1.6 As part of self::reindexAll() * @param int $storeId * @return void */ protected function cleanIndex($storeId) { $dimension = $this->dimensionFactory->create(['name' => self::SCOPE_FIELD_NAME, 'value' => $storeId]); $this->indexHandler->cleanIndex([$dimension]); } /** * Retrieve EAV Config Singleton * * @return \Magento\Eav\Model\Config * @deprecated 100.1.6 Use $self::$eavConfig directly */ protected function getEavConfig() { return $this->eavConfig; } /** * Retrieve searchable attributes * * @param string $backendType * @deprecated 100.2.0 see DataProvider::getSearchableAttributes() * @return \Magento\Eav\Model\Entity\Attribute[] */ protected function getSearchableAttributes($backendType = null) { return $this->dataProvider->getSearchableAttributes($backendType); } /** * Retrieve searchable attribute by Id or code * * @param int|string $attribute * @deprecated 100.2.0 see DataProvider::getSearchableAttributes() * @return \Magento\Eav\Model\Entity\Attribute */ protected function getSearchableAttribute($attribute) { return $this->dataProvider->getSearchableAttribute($attribute); } /** * Returns expression for field unification * * @deprecated 100.1.6 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::unifyField() * @param string $field * @param string $backendType * @return \Zend_Db_Expr */ protected function unifyField($field, $backendType = 'varchar') { if ($backendType == 'datetime') { $expr = $this->connection->getDateFormatSql($field, '%Y-%m-%d %H:%i:%s'); } else { $expr = $field; } return $expr; } /** * Retrieve Product Type Instance * * @deprecated 100.1.6 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::getProductTypeInstance() * @param string $typeId * @return \Magento\Catalog\Model\Product\Type\AbstractType */ protected function getProductTypeInstance($typeId) { if (!isset($this->productTypes[$typeId])) { $productEmulator = $this->getProductEmulator($typeId); $this->productTypes[$typeId] = $this->catalogProductType->factory($productEmulator); } return $this->productTypes[$typeId]; } /** * Retrieve Product Emulator (Magento Object) * * @deprecated 100.1.6 Moved to \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider * @see \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider::getProductEmulator() * @param string $typeId * @return \Magento\Framework\DataObject */ protected function getProductEmulator($typeId) { if (!isset($this->productEmulators[$typeId])) { $productEmulator = new \Magento\Framework\DataObject(); $productEmulator->setTypeId($typeId); $this->productEmulators[$typeId] = $productEmulator; } return $this->productEmulators[$typeId]; } }