diff --git a/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php b/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php index d67a50875b81..359c4df380b8 100644 --- a/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php +++ b/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php @@ -124,7 +124,7 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte $this->addEntityIdSort($searchCriteria); $this->addVisibilityFilter($searchCriteria, $isSearch, !empty($args['filter'])); - $searchCriteria->setCurrentPage($args['currentPage']); + $searchCriteria->setCurrentPage($args['currentPage'] - 1); $searchCriteria->setPageSize($args['pageSize']); return $searchCriteria; @@ -168,7 +168,7 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void } $sortOrderArray[] = $this->sortOrderBuilder - ->setField('_id') + ->setField('entity_id') ->setDirection($sortDir) ->create(); $searchCriteria->setSortOrders($sortOrderArray); diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php index f1d30ab942aa..5c170f428bc9 100644 --- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php +++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php @@ -8,18 +8,15 @@ namespace Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider; use Magento\Catalog\Api\Data\ProductSearchResultsInterfaceFactory; -use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product\CollectionProcessorInterface; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product\CollectionPostProcessorInterface; -use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ProductSearch\ProductCollectionSearchCriteriaBuilder; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierFactory; -use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface; +use Magento\Framework\Api\Search\SearchCriteriaInterfaceFactory as SearchCriteriaFactory; use Magento\Framework\Api\Search\SearchResultInterface; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SearchResultsInterface; -use Magento\Framework\App\ObjectManager; use Magento\GraphQl\Model\Query\ContextInterface; /** @@ -53,14 +50,9 @@ class ProductSearch private $searchResultApplierFactory; /** - * @var ProductCollectionSearchCriteriaBuilder + * @var SearchCriteriaFactory */ - private $searchCriteriaBuilder; - - /** - * @var Visibility - */ - private $catalogProductVisibility; + private $searchCriteriaFactory; /** * @param CollectionFactory $collectionFactory @@ -68,8 +60,7 @@ class ProductSearch * @param CollectionProcessorInterface $collectionPreProcessor * @param CollectionPostProcessorInterface $collectionPostProcessor * @param SearchResultApplierFactory $searchResultsApplierFactory - * @param ProductCollectionSearchCriteriaBuilder $searchCriteriaBuilder - * @param Visibility $catalogProductVisibility + * @param SearchCriteriaFactory $searchCriteriaFactory */ public function __construct( CollectionFactory $collectionFactory, @@ -77,16 +68,14 @@ public function __construct( CollectionProcessorInterface $collectionPreProcessor, CollectionPostProcessorInterface $collectionPostProcessor, SearchResultApplierFactory $searchResultsApplierFactory, - ProductCollectionSearchCriteriaBuilder $searchCriteriaBuilder, - Visibility $catalogProductVisibility + SearchCriteriaFactory $searchCriteriaFactory ) { $this->collectionFactory = $collectionFactory; $this->searchResultsFactory = $searchResultsFactory; $this->collectionPreProcessor = $collectionPreProcessor; $this->collectionPostProcessor = $collectionPostProcessor; $this->searchResultApplierFactory = $searchResultsApplierFactory; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->catalogProductVisibility = $catalogProductVisibility; + $this->searchCriteriaFactory = $searchCriteriaFactory; } /** @@ -107,75 +96,27 @@ public function getList( /** @var Collection $collection */ $collection = $this->collectionFactory->create(); - //Create a copy of search criteria without filters to preserve the results from search - $searchCriteriaForCollection = $this->searchCriteriaBuilder->build($searchCriteria); //Apply CatalogSearch results from search and join table - $this->getSearchResultsApplier( - $searchResult, - $collection, - $this->getSortOrderArray($searchCriteriaForCollection) - )->apply(); - - $collection->setFlag('search_resut_applied', true); - - $collection->setVisibility($this->catalogProductVisibility->getVisibleInSiteIds()); - $this->collectionPreProcessor->process($collection, $searchCriteriaForCollection, $attributes, $context); - $collection->load(); - $this->collectionPostProcessor->process($collection, $attributes, $context); - - $searchResults = $this->searchResultsFactory->create(); - $searchResults->setSearchCriteria($searchCriteriaForCollection); - $searchResults->setItems($collection->getItems()); - $searchResults->setTotalCount($collection->getSize()); - return $searchResults; - } - - /** - * Create searchResultApplier - * - * @param SearchResultInterface $searchResult - * @param Collection $collection - * @param array $orders - * @return SearchResultApplierInterface - */ - private function getSearchResultsApplier( - SearchResultInterface $searchResult, - Collection $collection, - array $orders - ): SearchResultApplierInterface { - return $this->searchResultApplierFactory->create( + $searchResultsApplier = $this->searchResultApplierFactory->create( [ 'collection' => $collection, 'searchResult' => $searchResult, - 'orders' => $orders ] ); - } + $searchResultsApplier->apply(); - /** - * Format sort orders into associative array - * - * E.g. ['field1' => 'DESC', 'field2' => 'ASC", ...] - * - * @param SearchCriteriaInterface $searchCriteria - * @return array - */ - private function getSortOrderArray(SearchCriteriaInterface $searchCriteria) - { - $ordersArray = []; - $sortOrders = $searchCriteria->getSortOrders(); - if (is_array($sortOrders)) { - foreach ($sortOrders as $sortOrder) { - // I am replacing _id with entity_id because in ElasticSearch _id is required for sorting by ID. - // Where as entity_id is required when using ID as the sort in $collection->load();. - // @see \Magento\CatalogGraphQl\Model\Resolver\Products\Query\Search::getResult - if ($sortOrder->getField() === '_id') { - $sortOrder->setField('entity_id'); - } - $ordersArray[$sortOrder->getField()] = $sortOrder->getDirection(); - } - } + //Empty search criteria for backward compatibility. + //Search criteria must be already applied to the search result. + $emptySearchCriteria = $this->searchCriteriaFactory->create(); + $this->collectionPreProcessor->process($collection, $emptySearchCriteria, $attributes, $context); + $collection->load(); + $this->collectionPostProcessor->process($collection, $attributes, $context); - return $ordersArray; + $searchResults = $this->searchResultsFactory->create(); + $searchResults->setSearchCriteria($searchCriteria); + $searchResults->setItems($collection->getItems()); + $searchResults->setTotalCount($searchResult->getTotalCount()); + + return $searchResults; } } diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php index 03e8358b1ee7..e69de29bb2d1 100644 --- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php +++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php @@ -1,77 +0,0 @@ -searchCriteriaFactory = $searchCriteriaFactory; - $this->filterBuilder = $filterBuilder; - $this->filterGroupBuilder = $filterGroupBuilder; - } - - /** - * Build searchCriteria from search for product collection - * - * @param SearchCriteriaInterface $searchCriteria - * @return SearchCriteriaInterface - */ - public function build(SearchCriteriaInterface $searchCriteria): SearchCriteriaInterface - { - //Create a copy of search criteria without filters to preserve the results from search - $searchCriteriaForCollection = $this->searchCriteriaFactory->create() - ->setSortOrders($searchCriteria->getSortOrders()) - ->setPageSize($searchCriteria->getPageSize()) - ->setCurrentPage($searchCriteria->getCurrentPage()); - - //Add category id to enable sorting by position - foreach ($searchCriteria->getFilterGroups() as $filterGroup) { - foreach ($filterGroup->getFilters() as $filter) { - if ($filter->getField() == CategoryProductLink::KEY_CATEGORY_ID) { - $categoryFilter = $this->filterBuilder - ->setField(CategoryProductLink::KEY_CATEGORY_ID) - ->setValue($filter->getValue()) - ->setConditionType($filter->getConditionType()) - ->create(); - - $this->filterGroupBuilder->addFilter($categoryFilter); - $categoryGroup = $this->filterGroupBuilder->create(); - $searchCriteriaForCollection->setFilterGroups([$categoryGroup]); - } - } - } - return $searchCriteriaForCollection; - } -} diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php index c4d189cd7cb0..fcc134649352 100644 --- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php +++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php @@ -13,13 +13,11 @@ use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResult; use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResultFactory; use Magento\Framework\Api\Search\SearchCriteriaInterface; -use Magento\Framework\App\ObjectManager; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\ArgumentsProcessorInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\GraphQl\Model\Query\ContextInterface; use Magento\Search\Api\SearchInterface; -use Magento\Search\Model\Search\PageSizeProvider; /** * Full text search for catalog using given search criteria. @@ -38,11 +36,6 @@ class Search implements ProductQueryInterface */ private $searchResultFactory; - /** - * @var PageSizeProvider - */ - private $pageSizeProvider; - /** * @var FieldSelection */ @@ -76,36 +69,31 @@ class Search implements ProductQueryInterface /** * @param SearchInterface $search * @param SearchResultFactory $searchResultFactory - * @param PageSizeProvider $pageSize * @param FieldSelection $fieldSelection * @param ProductSearch $productsProvider * @param SearchCriteriaBuilder $searchCriteriaBuilder - * @param ArgumentsProcessorInterface|null $argsSelection - * @param Suggestions|null $suggestions - * @param QueryPopularity|null $queryPopularity + * @param ArgumentsProcessorInterface $argsSelection + * @param Suggestions $suggestions + * @param QueryPopularity $queryPopularity */ public function __construct( SearchInterface $search, SearchResultFactory $searchResultFactory, - PageSizeProvider $pageSize, FieldSelection $fieldSelection, ProductSearch $productsProvider, SearchCriteriaBuilder $searchCriteriaBuilder, - ArgumentsProcessorInterface $argsSelection = null, - Suggestions $suggestions = null, - QueryPopularity $queryPopularity = null + ArgumentsProcessorInterface $argsSelection, + Suggestions $suggestions, + QueryPopularity $queryPopularity ) { $this->search = $search; $this->searchResultFactory = $searchResultFactory; - $this->pageSizeProvider = $pageSize; $this->fieldSelection = $fieldSelection; $this->productsProvider = $productsProvider; $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->argsSelection = $argsSelection ?: ObjectManager::getInstance() - ->get(ArgumentsProcessorInterface::class); - $this->suggestions = $suggestions ?: ObjectManager::getInstance() - ->get(Suggestions::class); - $this->queryPopularity = $queryPopularity ?: ObjectManager::getInstance()->get(QueryPopularity::class); + $this->argsSelection = $argsSelection; + $this->suggestions = $suggestions; + $this->queryPopularity = $queryPopularity; } /** @@ -123,18 +111,7 @@ public function getResult( ContextInterface $context ): SearchResult { $searchCriteria = $this->buildSearchCriteria($args, $info); - - $realPageSize = $searchCriteria->getPageSize(); - $realCurrentPage = $searchCriteria->getCurrentPage(); - //Because of limitations of sort and pagination on search API we will query all IDS - $pageSize = $this->pageSizeProvider->getMaxPageSize(); - $searchCriteria->setPageSize($pageSize); - $searchCriteria->setCurrentPage(0); $itemsResults = $this->search->search($searchCriteria); - - //Address limitations of sort and pagination on search API apply original pagination from GQL query - $searchCriteria->setPageSize($realPageSize); - $searchCriteria->setCurrentPage($realCurrentPage); $searchResults = $this->productsProvider->getList( $searchCriteria, $itemsResults, @@ -142,7 +119,9 @@ public function getResult( $context ); - $totalPages = $realPageSize ? ((int)ceil($searchResults->getTotalCount() / $realPageSize)) : 0; + $totalPages = $searchCriteria->getPageSize() + ? ((int)ceil($searchResults->getTotalCount() / $searchCriteria->getPageSize())) + : 0; // add query statistics data if (!empty($args['search'])) { @@ -167,8 +146,8 @@ public function getResult( 'totalCount' => $totalCount, 'productsSearchResult' => $productArray, 'searchAggregation' => $itemsResults->getAggregations(), - 'pageSize' => $realPageSize, - 'currentPage' => $realCurrentPage, + 'pageSize' => $searchCriteria->getPageSize(), + 'currentPage' => $searchCriteria->getCurrentPage() + 1, //search criteria pagination starts with 0 'totalPages' => $totalPages, 'suggestions' => $suggestions, ] diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php index d15c072b9fe4..e8825b95a9c7 100644 --- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php +++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php @@ -105,14 +105,11 @@ public function apply(Filter $filter, AbstractDb $collection) } elseif ($conditionType === self::CONDITION_TYPE_IN) { $this->joinMinimalPosition->execute($collection, $ids); } - /** Prevent filtering duplication as the filter should be already applied to the search result */ - if (!$collection->getFlag('search_resut_applied')) { - $collection->addCategoriesFilter( - [ - $conditionType => array_map('intval', $this->getCategoryIds($ids)) - ] - ); - } + $collection->addCategoriesFilter( + [ + $conditionType => array_map('intval', $this->getCategoryIds($ids)) + ] + ); } return true; diff --git a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php index 9b66606d37a9..22ed526d8161 100644 --- a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php +++ b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php @@ -567,7 +567,7 @@ protected function _beforeLoad() * for the same requests and products with the same relevance * NOTE: this does not replace existing orders but ADDs one more */ - $this->setOrder('entity_id'); + $this->setOrder('entity_id', Select::SQL_ASC); return parent::_beforeLoad(); } diff --git a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php index 36e0a85fa430..49676b7c3b20 100644 --- a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php +++ b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php @@ -27,24 +27,16 @@ class SearchResultApplier implements SearchResultApplierInterface */ private $searchResult; - /** - * @var array - */ - private $orders; - /** * @param Collection $collection * @param SearchResultInterface $searchResult - * @param array $orders */ public function __construct( Collection $collection, - SearchResultInterface $searchResult, - array $orders + SearchResultInterface $searchResult ) { $this->collection = $collection; $this->searchResult = $searchResult; - $this->orders = $orders; } /** @@ -56,18 +48,16 @@ public function apply() $this->collection->getSelect()->where('NULL'); return; } + $ids = []; foreach ($this->searchResult->getItems() as $item) { $ids[] = (int)$item->getId(); } $orderList = implode(',', $ids); - $this->collection->getSelect()->where('e.entity_id IN (?)', $ids); - - if (isset($this->orders['relevance'])) { - $this->collection->getSelect() - ->reset(\Magento\Framework\DB\Select::ORDER) - ->order(new \Magento\Framework\DB\Sql\Expression("FIELD(e.entity_id, $orderList)")); - } + $this->collection->getSelect() + ->where('e.entity_id IN (?)', $ids) + ->reset(\Magento\Framework\DB\Select::ORDER) + ->order(new \Magento\Framework\DB\Sql\Expression("FIELD(e.entity_id, $orderList)")); } } diff --git a/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php b/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php index a9fb67f209aa..043f6ca3fd79 100644 --- a/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php +++ b/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php @@ -311,7 +311,7 @@ function (string $valueId) { && in_array($attribute->getAttributeCode(), $this->sortableAttributesValuesToImplode) && count($attributeValues) > 1 ) { - $attributeValues = [$productId => implode(' ', $attributeValues)]; + $attributeValues = [$productId => implode("\n", $attributeValues)]; } if (in_array($attribute->getAttributeCode(), $this->sortableCaseSensitiveAttributes)) { diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php index 7d41d54fb22a..9721c6652208 100644 --- a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php +++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php @@ -7,9 +7,7 @@ namespace Magento\Elasticsearch\SearchAdapter\Query\Builder; use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeProvider; -use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldName\ResolverInterface - as FieldNameResolver; -use Magento\Elasticsearch\Model\Adapter\FieldMapperInterface; +use Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\ExpressionBuilderInterface as SortExpressionBuilder; use Magento\Framework\Search\RequestInterface; /** @@ -17,56 +15,26 @@ */ class Sort { - /** - * List of fields that need to skipp by default. - */ - private const DEFAULT_SKIPPED_FIELDS = [ - 'entity_id', - ]; - - /** - * Default mapping for special fields. - */ - private const DEFAULT_MAP = [ - 'relevance' => '_score', - ]; - /** * @var AttributeProvider */ private $attributeAdapterProvider; /** - * @var FieldNameResolver - */ - private $fieldNameResolver; - - /** - * @var array + * @var SortExpressionBuilder */ - private $skippedFields; - - /** - * @var array - */ - private $map; + private $sortExpressionBuilder; /** * @param AttributeProvider $attributeAdapterProvider - * @param FieldNameResolver $fieldNameResolver - * @param array $skippedFields - * @param array $map + * @param SortExpressionBuilder $sortExpressionBuilder */ public function __construct( AttributeProvider $attributeAdapterProvider, - FieldNameResolver $fieldNameResolver, - array $skippedFields = [], - array $map = [] + SortExpressionBuilder $sortExpressionBuilder ) { $this->attributeAdapterProvider = $attributeAdapterProvider; - $this->fieldNameResolver = $fieldNameResolver; - $this->skippedFields = array_merge(self::DEFAULT_SKIPPED_FIELDS, $skippedFields); - $this->map = array_merge(self::DEFAULT_MAP, $map); + $this->sortExpressionBuilder = $sortExpressionBuilder; } /** @@ -74,9 +42,6 @@ public function __construct( * * @param RequestInterface $request * @return array - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getSort(RequestInterface $request) { @@ -88,38 +53,11 @@ public function getSort(RequestInterface $request) if (!method_exists($request, 'getSort')) { return $sorts; } + foreach ($request->getSort() as $item) { - if (in_array($item['field'], $this->skippedFields)) { - continue; - } $attribute = $this->attributeAdapterProvider->getByAttributeCode((string)$item['field']); - $fieldName = $this->fieldNameResolver->getFieldName($attribute); - if (isset($this->map[$fieldName])) { - $fieldName = $this->map[$fieldName]; - } - if ($attribute->isSortable() && - !$attribute->isComplexType() && - !($attribute->isFloatType() || $attribute->isIntegerType()) - ) { - $suffix = $this->fieldNameResolver->getFieldName( - $attribute, - ['type' => FieldMapperInterface::TYPE_SORT] - ); - $fieldName .= '.' . $suffix; - } - if ($attribute->isComplexType() && $attribute->isSortable()) { - $fieldName .= '_value'; - $suffix = $this->fieldNameResolver->getFieldName( - $attribute, - ['type' => FieldMapperInterface::TYPE_SORT] - ); - $fieldName .= '.' . $suffix; - } - $sorts[] = [ - $fieldName => [ - 'order' => strtolower($item['direction'] ?? '') - ] - ]; + $direction = strtolower($item['direction'] ?? ''); + $sorts[] = $this->sortExpressionBuilder->build($attribute, $direction, $request); } return $sorts; diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php new file mode 100644 index 000000000000..f7d19a02d23a --- /dev/null +++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php @@ -0,0 +1,60 @@ +fieldNameResolver = $fieldNameResolver; + } + + /** + * @inheritdoc + */ + public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array + { + $fieldName = $this->fieldNameResolver->getFieldName($attribute); + if ($attribute->isSortable() && + !$attribute->isComplexType() && + !($attribute->isFloatType() || $attribute->isIntegerType()) + ) { + $suffix = $this->fieldNameResolver->getFieldName( + $attribute, + ['type' => FieldMapperInterface::TYPE_SORT] + ); + $fieldName .= '.' . $suffix; + } + if ($attribute->isComplexType() && $attribute->isSortable()) { + $fieldName .= '_value'; + $suffix = $this->fieldNameResolver->getFieldName( + $attribute, + ['type' => FieldMapperInterface::TYPE_SORT] + ); + $fieldName .= '.' . $suffix; + } + + return [ + $fieldName => ['order' => $direction], + ]; + } +} diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php new file mode 100644 index 000000000000..f0a3b0854770 --- /dev/null +++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php @@ -0,0 +1,31 @@ + [ + 'type' => 'number', + 'script' => [ + 'lang' => 'painless', + 'source' => 'Long.parseLong(doc[\'_id\'].value)', + ], + 'order' => $direction, + ], + ]; + } +} diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php new file mode 100644 index 000000000000..f9f1c8a965cd --- /dev/null +++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php @@ -0,0 +1,46 @@ +defaultExpressionBuilder = $defaultExpressionBuilder; + $this->customExpressionBuilders = $customExpressionBuilders; + } + + /** + * @inheritdoc + */ + public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array + { + return isset($this->customExpressionBuilders[$attribute->getAttributeCode()]) + ? $this->customExpressionBuilders[$attribute->getAttributeCode()]->build($attribute, $direction, $request) + : $this->defaultExpressionBuilder->build($attribute, $direction, $request); + } +} diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php new file mode 100644 index 000000000000..50314b5dcd76 --- /dev/null +++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php @@ -0,0 +1,24 @@ +fieldNameResolver = $fieldNameResolver; + } + + /** + * @inheritdoc + */ + public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array + { + $sortParams = ['order' => $direction]; + + $categoryIds = $this->getCategoryIdsFromQuery($request->getQuery()); + if (count($categoryIds) > 1) { + $fieldNames = []; + foreach ($categoryIds as $categoryId) { + $fieldNames[] = $this->fieldNameResolver->getFieldName($attribute, ['categoryId' => $categoryId]); + } + $fieldName = '_script'; + $sortParams += [ + 'type' => 'number', + 'script' => [ + 'lang' => 'painless', + 'source' => <<