Skip to content

Commit 520740d

Browse files
author
Eric Bohanon
committed
MAGETWO-82674: GraphQL Full Text Search
1 parent ddbb960 commit 520740d

File tree

7 files changed

+167
-172
lines changed

7 files changed

+167
-172
lines changed

app/code/Magento/GraphQlCatalog/Model/Resolver/Products/DataProvider/Product.php

Lines changed: 34 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
namespace Magento\GraphQlCatalog\Model\Resolver\Products\DataProvider;
88

99
use Magento\Catalog\Api\ProductRepositoryInterface;
10+
use Magento\Catalog\Model\Product\Option;
11+
use Magento\Catalog\Model\Product\TierPrice;
1012
use Magento\Framework\Api\SearchCriteriaInterface;
1113
use Magento\Framework\Data\SearchResultInterface;
1214
use Magento\Framework\Exception\NoSuchEntityException;
@@ -23,11 +25,6 @@
2325
*/
2426
class Product
2527
{
26-
/**
27-
* @var ProductRepositoryInterface
28-
*/
29-
private $productRepository;
30-
3128
/**
3229
* @var ServiceOutputProcessor
3330
*/
@@ -64,83 +61,30 @@ class Product
6461
private $searchResultsFactory;
6562

6663
/**
67-
* @var EntityAttributeList
68-
*/
69-
private $entityAttributeList;
70-
71-
/**
72-
* @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection
73-
*/
74-
private $configurable;
75-
76-
/**
77-
* @param ProductRepositoryInterface $productRepository
7864
* @param ServiceOutputProcessor $serviceOutputProcessor
7965
* @param MediaGalleryEntries $mediaGalleryResolver
8066
* @param SerializerInterface $jsonSerializer
8167
* @param CollectionFactory $collectionFactory
8268
* @param JoinProcessorInterface $joinProcessor
8369
* @param CollectionProcessorInterface $collectionProcessor
8470
* @param ProductSearchResultsInterfaceFactory $searchResultsFactory
85-
* @param EntityAttributeList $entityAttributeList
86-
* @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection $collection
8771
*/
8872
public function __construct(
89-
ProductRepositoryInterface $productRepository,
9073
ServiceOutputProcessor $serviceOutputProcessor,
9174
MediaGalleryEntries $mediaGalleryResolver,
9275
SerializerInterface $jsonSerializer,
9376
CollectionFactory $collectionFactory,
9477
JoinProcessorInterface $joinProcessor,
9578
CollectionProcessorInterface $collectionProcessor,
96-
ProductSearchResultsInterfaceFactory $searchResultsFactory,
97-
EntityAttributeList $entityAttributeList,
98-
\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection $collection
79+
ProductSearchResultsInterfaceFactory $searchResultsFactory
9980
) {
100-
$this->productRepository = $productRepository;
10181
$this->serviceOutputProcessor = $serviceOutputProcessor;
10282
$this->mediaGalleryResolver = $mediaGalleryResolver;
10383
$this->jsonSerializer = $jsonSerializer;
10484
$this->collectionFactory = $collectionFactory;
10585
$this->joinProcessor = $joinProcessor;
10686
$this->collectionProcessor = $collectionProcessor;
10787
$this->searchResultsFactory = $searchResultsFactory;
108-
$this->entityAttributeList = $entityAttributeList;
109-
$this->configurable = $collection;
110-
}
111-
112-
/**
113-
* Get product data by Sku
114-
*
115-
* @param string $sku
116-
* @return array|null
117-
*/
118-
public function getProduct(string $sku)
119-
{
120-
try {
121-
$productObject = $this->productRepository->get($sku);
122-
} catch (NoSuchEntityException $e) {
123-
// No error should be thrown, null result should be returned
124-
return null;
125-
}
126-
return $this->processProduct($productObject);
127-
}
128-
129-
/**
130-
* Get product data by Id
131-
*
132-
* @param int $productId
133-
* @return array|null
134-
*/
135-
public function getProductById(int $productId)
136-
{
137-
try {
138-
$productObject = $this->productRepository->getById($productId);
139-
} catch (NoSuchEntityException $e) {
140-
// No error should be thrown, null result should be returned
141-
return null;
142-
}
143-
return $this->processProduct($productObject);
14488
}
14589

14690
/**
@@ -151,44 +95,42 @@ public function getProductById(int $productId)
15195
*/
15296
public function processProduct(\Magento\Catalog\Api\Data\ProductInterface $productObject)
15397
{
154-
// $productObject = $this->productRepository->get($productObject->getSku());
155-
$product = $this->serviceOutputProcessor->process(
156-
$productObject,
157-
ProductRepositoryInterface::class,
158-
'get'
159-
);
160-
if (isset($product['extension_attributes'])) {
161-
$product = array_merge($product, $product['extension_attributes']);
162-
}
163-
$customAttributes = [];
164-
if (isset($product['custom_attributes'])) {
165-
foreach ($product['custom_attributes'] as $attribute) {
166-
$isArray = false;
167-
if (is_array($attribute['value'])) {
168-
$isArray = true;
169-
foreach ($attribute['value'] as $attributeValue) {
170-
if (is_array($attributeValue)) {
171-
$customAttributes[$attribute['attribute_code']] = $this->jsonSerializer->serialize(
172-
$attribute['value']
173-
);
174-
continue;
175-
}
176-
$customAttributes[$attribute['attribute_code']] = implode(',', $attribute['value']);
177-
continue;
178-
}
98+
/** @var \Magento\Catalog\Model\Product $productObject */
99+
$productArray = $productObject->getData();
100+
$productArray['id'] = $productArray['entity_id'];
101+
unset($productArray['entity_id']);
102+
$productArray['media_gallery_entries'] = $productObject->getMediaGalleryEntries();
103+
if (isset($productArray['media_gallery_entries'])) {
104+
foreach ($productArray['media_gallery_entries'] as $key => $entry) {
105+
if ($entry->getExtensionAttributes() && $entry->getExtensionAttributes()->getVideoContent()) {
106+
$productArray['media_gallery_entries'][$key]['video_content']
107+
= $entry->getExtensionAttributes()->getVideoContent()->getData();
179108
}
180-
if ($isArray) {
181-
continue;
109+
}
110+
}
111+
if (isset($productArray['options'])) {
112+
/** @var Option $option */
113+
foreach ($productArray['options'] as $key => $option) {
114+
$productArray['options'][$key] = $option->getData();
115+
$productArray['options'][$key]['product_sku'] = $option->getProductSku();
116+
$values = $option->getValues() ?: [];
117+
/** @var Option\Value $value */
118+
foreach ($values as $value) {
119+
$productArray['options'][$key]['values'][] = $value->getData();
182120
}
183-
$customAttributes[$attribute['attribute_code']] = $attribute['value'];
184121
}
185122
}
186-
$product = array_merge($product, $customAttributes);
187-
$product = array_merge($product, $product['product_links']);
188-
$product['media_gallery_entries']
189-
= $this->mediaGalleryResolver->getMediaGalleryEntries($productObject->getSku());
123+
$tierPrices = $productObject->getTierPrices();
124+
if ($tierPrices) {
125+
/** @var TierPrice $tierPrice */
126+
foreach ($tierPrices as $tierPrice) {
127+
$productArray['tier_prices'][] = $tierPrice->getData();
128+
}
129+
} else {
130+
$productArray['tier_prices'] = null;
131+
}
190132

191-
return $product;
133+
return $productArray;
192134
}
193135

194136
/**

app/code/Magento/GraphQlCatalog/Model/Resolver/Products/Query/Filter.php

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
use Magento\Catalog\Api\Data\ProductInterface;
1010
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
12+
use Magento\Framework\Api\SearchCriteriaBuilder;
1113
use Magento\Framework\Api\SearchCriteriaInterface;
1214
use Magento\GraphQlCatalog\Model\Resolver\Products\DataProvider\Product;
1315
use Magento\GraphQlCatalog\Model\Resolver\Products\SearchResult;
@@ -33,19 +35,34 @@ class Filter
3335
*/
3436
private $productDataProvider;
3537

38+
/**
39+
* @var SearchCriteriaBuilder
40+
*/
41+
private $searchCriteriaBuilder;
42+
43+
/**
44+
* @var \Magento\Catalog\Model\ResourceModel\Product
45+
*/
46+
private $productResource;
47+
3648
/**
3749
* @param ProductRepositoryInterface $productRepository
3850
* @param SearchResultFactory $searchResultFactory
3951
* @param Product $productDataProvider
52+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
4053
*/
4154
public function __construct(
4255
ProductRepositoryInterface $productRepository,
4356
SearchResultFactory $searchResultFactory,
44-
Product $productDataProvider
57+
Product $productDataProvider,
58+
SearchCriteriaBuilder $searchCriteriaBuilder,
59+
\Magento\Catalog\Model\ResourceModel\Product $productResource
4560
) {
4661
$this->productRepository = $productRepository;
4762
$this->searchResultFactory = $searchResultFactory;
4863
$this->productDataProvider = $productDataProvider;
64+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
65+
$this->productResource = $productResource;
4966
}
5067

5168
/**
@@ -56,12 +73,77 @@ public function __construct(
5673
*/
5774
public function getResult(SearchCriteriaInterface $searchCriteria)
5875
{
76+
$realPageSize = $searchCriteria->getPageSize();
77+
$realCurrentPage = $searchCriteria->getCurrentPage();
78+
// Current page must be set to 0 and page size to max for search to grab all ID's as temporary workaround for
79+
// inaccurate search
80+
$searchCriteria->setPageSize(PHP_INT_MAX);
81+
$searchCriteria->setCurrentPage(1);
5982
$products = $this->productDataProvider->getList($searchCriteria);
6083
$productArray = [];
84+
$configurableProducts = [];
85+
$childrenIds = [];
86+
$searchCriteria->setPageSize($realPageSize);
87+
$searchCriteria->setCurrentPage($realCurrentPage);
88+
$paginatedProducts = $this->paginateList($products->getItems(), $searchCriteria);
6189
/** @var ProductInterface $product */
62-
foreach ($products->getItems() as $product) {
63-
$productArray[] = $this->productDataProvider->processProduct($product);
90+
foreach ($paginatedProducts as $product) {
91+
$productData = $this->productDataProvider->processProduct($product);
92+
if ($product->getTypeId() === Configurable::TYPE_CODE) {
93+
$extensionAttributes = $product->getExtensionAttributes();
94+
$productData['configurable_product_options'] = $extensionAttributes->getConfigurableProductOptions();
95+
$productData['configurable_product_links'] = $extensionAttributes->getConfigurableProductLinks();
96+
$childrenIds = array_merge($childrenIds, $productData['configurable_product_links']);
97+
$formattedLinks = [];
98+
foreach ($productData['configurable_product_links'] as $configurable_product_link) {
99+
$formattedLinks[$configurable_product_link] = null;
100+
}
101+
$productData['configurable_product_links'] = $formattedLinks;
102+
$configurableProducts[] = $productData;
103+
} else {
104+
$productArray[] = $productData;
105+
}
106+
}
107+
108+
if (!empty($configurableProducts)) {
109+
$this->searchCriteriaBuilder->addFilter('entity_id', $childrenIds, 'in');
110+
$childProducts = $this->productDataProvider->getList($this->searchCriteriaBuilder->create());
111+
/** @var \Magento\Catalog\Model\Product $childProduct */
112+
foreach ($childProducts->getItems() as $childProduct) {
113+
$childData = $this->productDataProvider->processProduct($childProduct);
114+
$childId = (int)$childProduct->getId();
115+
foreach ($configurableProducts as $key => $configurableProduct) {
116+
if (array_key_exists($childId, $configurableProduct['configurable_product_links'])) {
117+
$configurableProducts[$key]['configurable_product_links'][$childId] = $childData;
118+
$categoryLinks = $this->productResource->getCategoryIds($childProduct);
119+
foreach ($categoryLinks as $key => $link) {
120+
$configurableProducts[$key]['configurable_product_links'][$childId]['category_links'][] =
121+
['position' => $key, 'category_id' => $link];
122+
}
123+
}
124+
}
125+
}
64126
}
127+
128+
$productArray = array_merge($productArray, $configurableProducts);
129+
65130
return $this->searchResultFactory->create($products->getTotalCount(), $productArray);
66131
}
132+
133+
/**
134+
* Paginates array of Ids pulled back in search based off search criteria and total count.
135+
*
136+
* This function and its usages should be removed after MAGETWO-85611 is resolved.
137+
*
138+
* @param array $ids
139+
* @param SearchCriteriaInterface $searchCriteria
140+
* @return int[]
141+
*/
142+
private function paginateList(array $ids, SearchCriteriaInterface $searchCriteria)
143+
{
144+
$length = $searchCriteria->getPageSize();
145+
// Search starts pages from 0
146+
$offset = $length * ($searchCriteria->getCurrentPage() - 1);
147+
return array_slice($ids, $offset, $length);
148+
}
67149
}

app/code/Magento/GraphQlCatalog/Model/Resolver/Products/Query/Search.php

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public function __construct(
6363
*/
6464
public function getResult(SearchCriteriaInterface $searchCriteria)
6565
{
66+
$realPageSize = $searchCriteria->getPageSize();
67+
$realCurrentPage = $searchCriteria->getCurrentPage();
6668
// Current page must be set to 0 and page size to max for search to grab all ID's as temporary workaround
6769
// for MAGETWO-85611
6870
$searchCriteria->setPageSize(PHP_INT_MAX);
@@ -75,45 +77,30 @@ public function getResult(SearchCriteriaInterface $searchCriteria)
7577
$ids[$item->getId()] = null;
7678
$searchIds[] = $item->getId();
7779
}
80+
$searchCriteria->setPageSize($realPageSize);
81+
$searchCriteria->setCurrentPage($realCurrentPage);
7882

7983
$filter = $this->filterHelper->generate('entity_id', 'in', $searchIds);
8084
$searchCriteria = $this->filterHelper->remove($searchCriteria, 'search_term');
8185
$searchCriteria = $this->filterHelper->add($searchCriteria, $filter);
8286
$searchResult = $this->filterQuery->getResult($searchCriteria);
8387

84-
$paginatedIds = $this->paginateIdList($searchIds, $searchCriteria);
8588
$products = [];
8689
if (!isset($searchCriteria->getSortOrders()[0])) {
8790
foreach ($searchResult->getProductsSearchResult() as $product) {
88-
if (in_array($product['id'], $paginatedIds)) {
91+
if (in_array($product['id'], $searchIds)) {
8992
$ids[$product['id']] = $product;
9093
}
9194
}
9295
$products = array_filter($ids);
9396
} else {
9497
foreach ($searchResult->getProductsSearchResult() as $product) {
95-
if (in_array($product['id'], $paginatedIds)) {
98+
if (in_array($product['id'], $searchIds)) {
9699
$products[] = $product;
97100
}
98101
}
99102
}
100103

101104
return $this->searchResultFactory->create($searchResult->getTotalCount(), $products);
102105
}
103-
104-
/**
105-
* Paginates array of Ids pulled back in search based off search criteria and total count.
106-
*
107-
* This function and its usages should be removed after MAGETWO-85611 is resolved.
108-
*
109-
* @param int[] $ids
110-
* @param SearchCriteriaInterface $searchCriteria
111-
* @return int[]
112-
*/
113-
private function paginateIdList(array $ids, SearchCriteriaInterface $searchCriteria)
114-
{
115-
$length = $searchCriteria->getPageSize();
116-
$offset = $length * $searchCriteria->getCurrentPage();
117-
return array_slice($ids, $offset, $length);
118-
}
119106
}

app/code/Magento/GraphQlCatalog/Model/Type/Handler/Product.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,33 @@ private function getFields(string $typeName)
120120
$content = $mediaGalleryEntries['content'];
121121
$result['media_gallery_entries'][0]['video_content'] = $videoContent;
122122
$result['media_gallery_entries'][0]['content'] = $content;
123+
$result['category_ids'] = ['int'];
124+
$result['media_gallery'] =
125+
[
126+
'images' => [
127+
0 => [
128+
'value_id' => 'string',
129+
'file' => 'string',
130+
'media_type' => 'string',
131+
'entity_id' => 'string',
132+
'label' => 'string',
133+
'position' => 'string',
134+
'disabled' => 'string',
135+
'label_default' => 'string',
136+
'position_default' => 'string',
137+
'disabled_default' => 'string',
138+
'video_provider' => 'string',
139+
'video_url' => 'string',
140+
'video_description' => 'string',
141+
'video_metadata' => 'string',
142+
'video_provider_default' => 'string',
143+
'video_url_default' => 'string',
144+
'video_title_default' => 'string',
145+
'video_description_default' => 'string',
146+
'video_metadata_default' => 'string'
147+
]
148+
]
149+
];
123150

124151
$resolvedTypes = $this->typeGenerator->generate($typeName, $result);
125152
$fields = $resolvedTypes->config['fields'];

0 commit comments

Comments
 (0)