![]() 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-elasticsearch/Model/DataProvider/Base/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Elasticsearch\Model\DataProvider\Base; use Elasticsearch\Common\Exceptions\BadRequest400Exception; use Exception; use Magento\AdvancedSearch\Model\SuggestedQueriesInterface; use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface; use Magento\Elasticsearch\Model\Config; use Magento\Elasticsearch\SearchAdapter\ConnectionManager; use Magento\Elasticsearch\SearchAdapter\SearchIndexNameResolver; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ObjectManager; use Magento\Search\Model\QueryInterface; use Magento\Search\Model\QueryResultFactory; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface as StoreManager; use Psr\Log\LoggerInterface; /** * Default implementation to provide suggestions mechanism for Elasticsearch * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Suggestions implements SuggestedQueriesInterface { /** * @var Config */ private $config; /** * @var QueryResultFactory */ private $queryResultFactory; /** * @var ConnectionManager */ private $connectionManager; /** * @var ScopeConfigInterface */ private $scopeConfig; /** * @var SearchIndexNameResolver */ private $searchIndexNameResolver; /** * @var StoreManager */ private $storeManager; /** * @var FieldProviderInterface */ private $fieldProvider; /** * @var LoggerInterface */ private $logger; /** * @var GetSuggestionFrequencyInterface */ private $getSuggestionFrequency; /** * @var array */ private $responseErrorExceptionList = [ 'elasticsearchBadRequest404' => BadRequest400Exception::class ]; /** * Suggestions constructor. * * @param ScopeConfigInterface $scopeConfig * @param Config $config * @param QueryResultFactory $queryResultFactory * @param ConnectionManager $connectionManager * @param SearchIndexNameResolver $searchIndexNameResolver * @param StoreManager $storeManager * @param FieldProviderInterface $fieldProvider * @param LoggerInterface|null $logger * @param GetSuggestionFrequencyInterface|null $getSuggestionFrequency * @param array $responseErrorExceptionList * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( ScopeConfigInterface $scopeConfig, Config $config, QueryResultFactory $queryResultFactory, ConnectionManager $connectionManager, SearchIndexNameResolver $searchIndexNameResolver, StoreManager $storeManager, FieldProviderInterface $fieldProvider, LoggerInterface $logger = null, ?GetSuggestionFrequencyInterface $getSuggestionFrequency = null, array $responseErrorExceptionList = [] ) { $this->queryResultFactory = $queryResultFactory; $this->connectionManager = $connectionManager; $this->scopeConfig = $scopeConfig; $this->config = $config; $this->searchIndexNameResolver = $searchIndexNameResolver; $this->storeManager = $storeManager; $this->fieldProvider = $fieldProvider; $this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class); $this->getSuggestionFrequency = $getSuggestionFrequency ?: ObjectManager::getInstance()->get(GetSuggestionFrequencyInterface::class); $this->responseErrorExceptionList = array_merge($this->responseErrorExceptionList, $responseErrorExceptionList); } /** * @inheritdoc */ public function getItems(QueryInterface $query) { $result = []; if ($this->isSuggestionsAllowed()) { $isResultsCountEnabled = $this->isResultsCountEnabled(); try { $suggestions = $this->getSuggestions($query); } catch (Exception $e) { if ($this->validateException($e)) { $this->logger->critical($e); $suggestions = []; } else { throw $e; } } foreach ($suggestions as $suggestion) { $count = null; if ($isResultsCountEnabled) { try { $count = $this->getSuggestionFrequency->execute($suggestion['text']); } catch (Exception $e) { $this->logger->critical($e); } } $result[] = $this->queryResultFactory->create( [ 'queryText' => $suggestion['text'], 'resultsCount' => $count, ] ); } } return $result; } /** * @inheritdoc */ public function isResultsCountEnabled() { return $this->scopeConfig->isSetFlag( SuggestedQueriesInterface::SEARCH_SUGGESTION_COUNT_RESULTS_ENABLED, ScopeInterface::SCOPE_STORE ); } /** * Check if the given class name is in the exception list * * @param Exception $exception * @return bool */ private function validateException(Exception $exception): bool { return in_array(get_class($exception), $this->responseErrorExceptionList, true); } /** * Get Suggestions * * @param QueryInterface $query * @return array * @throws \Magento\Framework\Exception\NoSuchEntityException */ private function getSuggestions(QueryInterface $query) { $suggestions = []; $searchSuggestionsCount = $this->getSearchSuggestionsCount(); $searchQuery = $this->initQuery($query); $searchQuery = $this->addSuggestFields($searchQuery, $searchSuggestionsCount); $result = $this->fetchQuery($searchQuery); if (is_array($result)) { foreach ($result['suggest'] ?? [] as $suggest) { foreach ($suggest as $token) { foreach ($token['options'] ?? [] as $key => $suggestion) { $suggestions[$suggestion['score'] . '_' . $key] = $suggestion; } } } krsort($suggestions); $texts = array_unique(array_column($suggestions, 'text')); $suggestions = array_slice( array_intersect_key(array_values($suggestions), $texts), 0, $searchSuggestionsCount ); } return $suggestions; } /** * Init Search Query * * @param QueryInterface $query * @return array * @throws \Magento\Framework\Exception\NoSuchEntityException */ private function initQuery(QueryInterface $query): array { $searchQuery = [ 'index' => $this->searchIndexNameResolver->getIndexName( $this->storeManager->getStore()->getId(), Config::ELASTICSEARCH_TYPE_DEFAULT ), 'type' => Config::ELASTICSEARCH_TYPE_DEFAULT, 'body' => [ 'suggest' => [ 'text' => $query->getQueryText() ] ], ]; return $searchQuery; } /** * Build Suggest on searchable fields. * * @param array $searchQuery * @param int $searchSuggestionsCount * * @return array */ private function addSuggestFields($searchQuery, $searchSuggestionsCount) { $fields = $this->getSuggestFields(); foreach ($fields as $field) { $searchQuery['body']['suggest']['phrase_' . $field] = [ 'phrase' => [ 'field' => $field, 'analyzer' => 'standard', 'size' => $searchSuggestionsCount, 'max_errors' => 0.9, 'direct_generator' => [ [ 'field' => $field, 'min_word_length' => 3, ] ], ], ]; } return $searchQuery; } /** * Get fields to build suggest query on. * * @return array */ private function getSuggestFields() { $fields = array_filter($this->fieldProvider->getFields(), function ($field) { return (($field['type'] ?? null) === 'text') && (($field['index'] ?? null) !== false); }); return array_keys($fields); } /** * Fetch Query * * @param array $query * @return array */ private function fetchQuery(array $query) { return $this->connectionManager->getConnection()->query($query); } /** * Get search suggestions Max Count from config * * @return int */ private function getSearchSuggestionsCount() { return (int) $this->scopeConfig->getValue( SuggestedQueriesInterface::SEARCH_SUGGESTION_COUNT, ScopeInterface::SCOPE_STORE ); } /** * Is Search Suggestions Allowed * * @return bool */ private function isSuggestionsAllowed() { $isSuggestionsEnabled = $this->scopeConfig->isSetFlag( SuggestedQueriesInterface::SEARCH_SUGGESTION_ENABLED, ScopeInterface::SCOPE_STORE ); $isEnabled = $this->config->isElasticsearchEnabled(); return $isEnabled && $isSuggestionsEnabled; } }