Skip to content

Commit 241e38e

Browse files
committed
MAGE-940: code updated as per code review suggestions.
1 parent b5cb322 commit 241e38e

File tree

3 files changed

+210
-42
lines changed

3 files changed

+210
-42
lines changed

Model/RecommendManagement.php

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,24 @@
55

66
use Algolia\AlgoliaSearch\Api\RecommendClient;
77
use Algolia\AlgoliaSearch\Api\RecommendManagementInterface;
8-
use Algolia\AlgoliaSearch\Exceptions\AlgoliaException;
9-
use Algolia\AlgoliaSearch\Helper\AlgoliaHelper;
108
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
9+
use Algolia\AlgoliaSearch\Service\IndexNameFetcher;
1110
use Magento\Framework\Exception\NoSuchEntityException;
12-
use Magento\Store\Model\StoreManagerInterface;
1311

1412
class RecommendManagement implements RecommendManagementInterface
1513
{
1614
/**
1715
* @var null|RecommendClient
1816
*/
19-
private $client = null;
17+
private ?RecommendClient $client = null;
2018

2119
/**
22-
* @param AlgoliaHelper $algoliaHelper
2320
* @param ConfigHelper $configHelper
24-
* @param StoreManagerInterface $storeManager
21+
* @param IndexNameFetcher $indexNameFetcher
2522
*/
2623
public function __construct(
27-
private readonly AlgoliaHelper $algoliaHelper,
2824
private readonly ConfigHelper $configHelper,
29-
private readonly StoreManagerInterface $storeManager
25+
private readonly IndexNameFetcher $indexNameFetcher
3026
){}
3127

3228
/**
@@ -43,80 +39,55 @@ private function getClient(): RecommendClient
4339
return $this->client;
4440
}
4541

46-
/**
47-
* @param string $name
48-
* @return string
49-
* @throws AlgoliaException
50-
* @throws NoSuchEntityException
51-
*/
52-
private function getFullIndexName(string $name): string
53-
{
54-
$prefix = $this->configHelper->getIndexPrefix();
55-
$storeCode = $this->storeManager->getStore()->getCode();
56-
57-
foreach ($this->algoliaHelper->listIndexes()['items'] as $index) {
58-
if ($index['name'] == $prefix . $storeCode . '_' . $name) {
59-
return $index['name'];
60-
}
61-
}
62-
63-
return '';
64-
}
65-
6642
/**
6743
* @param string $productId
6844
* @return array
69-
* @throws AlgoliaException
7045
* @throws NoSuchEntityException
7146
*/
7247
public function getBoughtTogetherRecommendation(string $productId): array
7348
{
74-
return $this->getRecommendations($productId, 'bought-together', 50);
49+
return $this->getRecommendations($productId, 'bought-together');
7550
}
7651

7752
/**
7853
* @param string $productId
7954
* @return array
80-
* @throws AlgoliaException
8155
* @throws NoSuchEntityException
8256
*/
83-
public function getRelatedProductsRecommendation($productId): array
57+
public function getRelatedProductsRecommendation(string $productId): array
8458
{
85-
return $this->getRecommendations($productId, 'related-products', 50);
59+
return $this->getRecommendations($productId, 'related-products');
8660
}
8761

8862
/**
8963
* @return array
90-
* @throws AlgoliaException
9164
* @throws NoSuchEntityException
9265
*/
9366
public function getTrendingItemsRecommendation(): array
9467
{
95-
return $this->getRecommendations('', 'trending-items', 50);
68+
return $this->getRecommendations('', 'trending-items');
9669
}
9770

9871
/**
9972
* @param string $productId
10073
* @return array
101-
* @throws AlgoliaException
10274
* @throws NoSuchEntityException
10375
*/
104-
public function getLookingSimilarRecommendation($productId): array
76+
public function getLookingSimilarRecommendation(string $productId): array
10577
{
106-
return $this->getRecommendations($productId, 'bought-together', 50);
78+
return $this->getRecommendations($productId, 'bought-together');
10779
}
10880

10981
/**
11082
* @param string $productId
11183
* @param string $model
11284
* @param float|int $threshold
11385
* @return array
114-
* @throws AlgoliaException
11586
* @throws NoSuchEntityException
11687
*/
117-
private function getRecommendations(string $productId, string $model, float|int $threshold = 42): array
88+
private function getRecommendations(string $productId, string $model, float|int $threshold = 50): array
11889
{
119-
$request['indexName'] = $this->getFullIndexName('products');
90+
$request['indexName'] = $this->indexNameFetcher->getIndexName('_products');
12091
$request['model'] = $model;
12192
$request['threshold'] = $threshold;
12293
if (!empty($productId)) {

Observer/RecommendSettings.php

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Algolia\AlgoliaSearch\Observer;
5+
6+
use Algolia\AlgoliaSearch\Api\RecommendManagementInterface;
7+
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Framework\Api\SearchCriteriaBuilder;
10+
use Magento\Framework\App\Config\Storage\WriterInterface;
11+
use Magento\Framework\Event\ObserverInterface;
12+
use Magento\Framework\Event\Observer;
13+
use Magento\Framework\Exception\LocalizedException;
14+
15+
class RecommendSettings implements ObserverInterface
16+
{
17+
/**
18+
* @var string
19+
*/
20+
private $productId = '';
21+
22+
/**
23+
* @param ConfigHelper $configHelper
24+
* @param WriterInterface $configWriter
25+
* @param ProductRepositoryInterface $productRepository
26+
* @param RecommendManagementInterface $recommendManagement
27+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
28+
*/
29+
public function __construct(
30+
private readonly ConfigHelper $configHelper,
31+
private readonly WriterInterface $configWriter,
32+
private readonly ProductRepositoryInterface $productRepository,
33+
private readonly RecommendManagementInterface $recommendManagement,
34+
private readonly SearchCriteriaBuilder $searchCriteriaBuilder
35+
){}
36+
37+
/**
38+
* @param Observer $observer
39+
* @throws LocalizedException
40+
*/
41+
public function execute(Observer $observer)
42+
{
43+
foreach ($observer->getData('changed_paths') as $changedPath) {
44+
// Validate before enable FBT on PDP or on cart page
45+
if ((
46+
$changedPath == ConfigHelper::IS_RECOMMEND_FREQUENTLY_BOUGHT_TOGETHER_ENABLED
47+
&& $this->configHelper->isRecommendFrequentlyBroughtTogetherEnabled()
48+
) || (
49+
$changedPath == ConfigHelper::IS_RECOMMEND_FREQUENTLY_BOUGHT_TOGETHER_ENABLED_ON_CART_PAGE
50+
&& $this->configHelper->isRecommendFrequentlyBroughtTogetherEnabledOnCartPage()
51+
)) {
52+
$this->validateFrequentlyBroughtTogether($changedPath);
53+
}
54+
55+
// Validate before enable related products on PDP or on cart page
56+
if ((
57+
$changedPath == ConfigHelper::IS_RECOMMEND_RELATED_PRODUCTS_ENABLED
58+
&& $this->configHelper->isRecommendRelatedProductsEnabled()
59+
) || (
60+
$changedPath == ConfigHelper::IS_RECOMMEND_RELATED_PRODUCTS_ENABLED_ON_CART_PAGE
61+
&& $this->configHelper->isRecommendRelatedProductsEnabledOnCartPage()
62+
)) {
63+
$this->validateRelatedProducts($changedPath);
64+
}
65+
66+
// Validate before enable trending items on PDP or on cart page
67+
if ((
68+
$changedPath == ConfigHelper::IS_TREND_ITEMS_ENABLED_IN_PDP
69+
&& $this->configHelper->isTrendItemsEnabledInPDP()
70+
) || (
71+
$changedPath == ConfigHelper::IS_TREND_ITEMS_ENABLED_IN_SHOPPING_CART
72+
&& $this->configHelper->isTrendItemsEnabledInShoppingCart()
73+
)) {
74+
$this->validateTrendingItems($changedPath);
75+
}
76+
77+
// Validate before enable looking similar on PDP or on cart page
78+
if ((
79+
$changedPath == ConfigHelper::IS_LOOKING_SIMILAR_ENABLED_IN_PDP
80+
&& $this->configHelper->isLookingSimilarEnabledInPDP()
81+
) || (
82+
$changedPath == ConfigHelper::IS_LOOKING_SIMILAR_ENABLED_IN_SHOPPING_CART
83+
&& $this->configHelper->isLookingSimilarEnabledInShoppingCart()
84+
)) {
85+
$this->validateLookingSimilar($changedPath);
86+
}
87+
}
88+
}
89+
90+
/**
91+
* @param string $changedPath
92+
* @return void
93+
* @throws LocalizedException
94+
*/
95+
protected function validateFrequentlyBroughtTogether(string $changedPath): void
96+
{
97+
try {
98+
$recommendations = $this->recommendManagement->getBoughtTogetherRecommendation($this->getProductId());
99+
if (empty($recommendations['renderingContent'])) {
100+
throw new LocalizedException(__(
101+
"It appears that there is no trained model available for the AppID: %1.",
102+
$this->configHelper->getApplicationID()
103+
));
104+
}
105+
} catch (\Exception $e) {
106+
$this->configWriter->save($changedPath, 0);
107+
throw new LocalizedException(__("Unable to save FBT Recommend configuration due to the following error: " . $e->getMessage()));
108+
}
109+
}
110+
111+
/**
112+
* @param string $changedPath
113+
* @return void
114+
* @throws LocalizedException
115+
*/
116+
protected function validateRelatedProducts(string $changedPath): void
117+
{
118+
try {
119+
$recommendations = $this->recommendManagement->getRelatedProductsRecommendation($this->getProductId());
120+
if (empty($recommendations['renderingContent'])) {
121+
throw new LocalizedException(__(
122+
"It appears that there is no trained model available for the AppID: %1.",
123+
$this->configHelper->getApplicationID()
124+
));
125+
}
126+
} catch (\Exception $e) {
127+
$this->configWriter->save($changedPath, 0);
128+
throw new LocalizedException(__("Unable to save Related Products Recommend configuration due to the following error: ". $e->getMessage()));
129+
}
130+
}
131+
132+
/**
133+
* @param string $changedPath
134+
* @return void
135+
* @throws LocalizedException
136+
*/
137+
protected function validateTrendingItems(string $changedPath): void
138+
{
139+
try {
140+
$recommendations = $this->recommendManagement->getTrendingItemsRecommendation();
141+
// When no recommendations suggested, most likely trained model is missing
142+
if (empty($recommendations['renderingContent'])) {
143+
throw new LocalizedException(__(
144+
"It appears that there is no trained model available for the AppID: %1.",
145+
$this->configHelper->getApplicationID()
146+
));
147+
}
148+
} catch (\Exception $e) {
149+
$this->configWriter->save($changedPath, 0);
150+
throw new LocalizedException(__("Unable to save Trending Items Recommend configuration due to the following error: ". $e->getMessage()));
151+
}
152+
}
153+
154+
/**
155+
* @param string $changedPath
156+
* @return void
157+
* @throws LocalizedException
158+
*/
159+
protected function validateLookingSimilar(string $changedPath): void
160+
{
161+
try {
162+
$recommendations = $this->recommendManagement->getLookingSimilarRecommendation($this->getProductId());
163+
if (empty($recommendations['renderingContent'])) {
164+
throw new LocalizedException(__(
165+
"It appears that there is no trained model available for the AppID: %1.",
166+
$this->configHelper->getApplicationID()
167+
));
168+
}
169+
} catch (\Exception $e) {
170+
$this->configWriter->save($changedPath, 0);
171+
throw new LocalizedException(__("Unable to save Looking Similar Recommend configuration due to the following error: ". $e->getMessage()));
172+
}
173+
}
174+
175+
/**
176+
* @return string
177+
*/
178+
private function getProductId(): string
179+
{
180+
if ($this->productId === '') {
181+
$searchCriteria = $this->searchCriteriaBuilder
182+
->addFilter('status', 1)
183+
->addFilter('quantity_and_stock_status', 1)
184+
->addFilter('visibility', [2, 3, 4], 'in')
185+
->setPageSize(10)
186+
->create();
187+
$result = $this->productRepository->getList($searchCriteria);
188+
if ($result->getTotalCount()) {
189+
$products = array_reverse($result->getItems());
190+
$firstProduct = array_pop($products);
191+
$this->productId = (string)$firstProduct->getId();
192+
}
193+
}
194+
195+
return $this->productId;
196+
}
197+
}

etc/adminhtml/events.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<observer name="algoliasearch_extra_settings_saved" instance="Algolia\AlgoliaSearch\Model\Observer\SaveSettings" />
3232
</event>
3333
<event name="admin_system_config_changed_section_algoliasearch_recommend">
34-
<observer name="algoliasearch_recommend_settings_saved" instance="Algolia\AlgoliaSearch\Model\Observer\RecommendSettings" />
34+
<observer name="algoliasearch_recommend_settings_saved" instance="Algolia\AlgoliaSearch\Observer\RecommendSettings" />
3535
</event>
3636
<event name="controller_action_predispatch_indexer_indexer_list">
3737
<observer name="show_warning_mismatch_indexer_type_indexer_list" instance="Algolia\AlgoliaSearch\Model\Observer\IndexerMismatchWarning" />

0 commit comments

Comments
 (0)