Skip to content

Commit 677412f

Browse files
authored
Merge pull request #1751 from algolia/fix/MAGE-1201-recommend-model-validation-3.15
MAGE-1201 Recommend model validation fix → 3.15
2 parents bffa9cf + 269a880 commit 677412f

File tree

3 files changed

+124
-12
lines changed

3 files changed

+124
-12
lines changed

Model/RecommendManagement.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function getTrendingItemsRecommendation(): array
7575
*/
7676
public function getLookingSimilarRecommendation(string $productId): array
7777
{
78-
return $this->getRecommendations($productId, 'bought-together');
78+
return $this->getRecommendations($productId, 'looking-similar');
7979
}
8080

8181
/**

Observer/RecommendSettings.php

Lines changed: 117 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99
use Magento\Catalog\Model\Product\Visibility;
1010
use Magento\Framework\Api\SearchCriteriaBuilder;
1111
use Magento\Framework\App\Config\Storage\WriterInterface;
12+
use Magento\Framework\App\State;
1213
use Magento\Framework\Event\Observer;
1314
use Magento\Framework\Event\ObserverInterface;
1415
use Magento\Framework\Exception\LocalizedException;
16+
use Magento\Framework\Message\ManagerInterface as MessageManagerInterface;
17+
use Psr\Log\LoggerInterface;
1518

1619
class RecommendSettings implements ObserverInterface
1720
{
1821
const QUANTITY_AND_STOCK_STATUS = 'quantity_and_stock_status';
1922
const STATUS = 'status';
2023
const VISIBILITY = 'visibility';
2124

25+
const ENFORCE_VALIDATION = 0;
26+
2227
/**
2328
* @var string
2429
*/
@@ -36,7 +41,10 @@ public function __construct(
3641
protected readonly WriterInterface $configWriter,
3742
protected readonly ProductRepositoryInterface $productRepository,
3843
protected readonly RecommendManagementInterface $recommendManagement,
39-
protected readonly SearchCriteriaBuilder $searchCriteriaBuilder
44+
protected readonly SearchCriteriaBuilder $searchCriteriaBuilder,
45+
protected readonly State $appState,
46+
protected readonly MessageManagerInterface $messageManager,
47+
protected readonly LoggerInterface $logger
4048
){}
4149

4250
/**
@@ -143,24 +151,122 @@ protected function validateRecommendation(string $changedPath, string $recommend
143151
{
144152
try {
145153
$recommendations = $this->recommendManagement->$recommendationMethod($this->getProductId());
146-
if (empty($recommendations['renderingContent'])) {
147-
throw new LocalizedException(__(
148-
"It appears that there is no trained model available for Algolia application ID %1.",
149-
$this->configHelper->getApplicationID()
150-
));
151-
}
154+
155+
$this->validateRecommendApiResponse($recommendations, $modelName);
152156
} catch (\Exception $e) {
153-
$this->configWriter->save($changedPath, 0);
154-
throw new LocalizedException(__(
155-
"Unable to save %1 Recommend configuration due to the following error: %2",
157+
$this->handleRecommendApiException($e, $modelName, $changedPath);
158+
}
159+
}
160+
161+
/**
162+
* If API does not return a hits response the model may not be configured correctly.
163+
* Do not hard fail but alert the end user.
164+
*
165+
* @throws LocalizedException
166+
*/
167+
protected function validateRecommendApiResponse(array $recommendResponse, string $modelName): void
168+
{
169+
if (!array_key_exists('hits', $recommendResponse)) {
170+
$msg = __(
171+
"It appears that there is no trained %1 model available for Algolia application ID %2. "
172+
. "Please verify your configuration in the Algolia Dashboard before continuing.",
173+
$modelName,
174+
$this->configHelper->getApplicationID()
175+
);
176+
177+
if ($this->shouldDisplayWarning()) {
178+
$this->messageManager->addWarningMessage($msg);
179+
}
180+
else {
181+
$this->logger->warning($msg);
182+
}
183+
}
184+
}
185+
186+
/**
187+
* Handles exceptions on the test request against the Recommend API
188+
*
189+
* The goal is to warn the user of potential issues so they do not enable a model on the front end that has not been
190+
* properly configured in Algolia
191+
*
192+
* TODO: Implement store scoped validation
193+
*
194+
* @throws LocalizedException
195+
*/
196+
protected function handleRecommendApiException(\Exception $e, string $modelName, string $changedPath): void
197+
{
198+
$msg = $this->getUserFriendlyRecommendApiErrorMessage($e);
199+
200+
if (self::ENFORCE_VALIDATION) {
201+
$this->rollBack($changedPath, __(
202+
"Unable to save %1 Recommend configuration due to the following error: %2",
156203
$modelName,
157-
$e->getMessage()
204+
$msg
158205
)
159206
);
160207
}
208+
209+
$msg = __(
210+
"Error encountered while enabling %1 recommendations: %2",
211+
$modelName,
212+
$msg
213+
);
214+
215+
if ($this->shouldDisplayWarning()) {
216+
$this->messageManager->addWarningMessage(
217+
$msg
218+
. ' Please verify your configuration in the Algolia Dashboard before continuing.');
219+
}
220+
else {
221+
$this->logger->warning($msg);
222+
}
223+
}
224+
225+
/*
226+
* For hard fail only
227+
*/
228+
protected function rollBack(string $changedPath, \Magento\Framework\Phrase $message): void
229+
{
230+
$this->configWriter->save($changedPath, 0);
231+
throw new LocalizedException($message);
232+
}
233+
234+
/**
235+
* Warnings should only be displayed within the admin panel
236+
* @throws LocalizedException
237+
*/
238+
protected function shouldDisplayWarning(): bool
239+
{
240+
return $this->appState->getAreaCode() === \Magento\Framework\App\Area::AREA_ADMINHTML
241+
&& php_sapi_name() !== 'cli';
242+
}
243+
244+
/**
245+
* If there is no model on the index then a 404 error should be returned
246+
* (which will cause the exception on the API call) because there is no model for that index
247+
* However errors which say "Index does not exist" are cryptic
248+
* This function serves to make this clearer to the user while also filtering out the possible
249+
* "ObjectID does not exist" error which can occur if the model does not contain the test product
250+
*/
251+
protected function getUserFriendlyRecommendApiErrorMessage(\Exception $e): string
252+
{
253+
$msg = $e->getMessage();
254+
if ($e->getCode() === 404) {
255+
if (!!preg_match('/index.*does not exist/i', $msg)) {
256+
$msg = (string) __("A trained model could not be found.");
257+
}
258+
if (!!preg_match('/objectid does not exist/i', $msg)) {
259+
$msg = (string) __("Could not find test product in trained model.");
260+
}
261+
}
262+
return $msg;
161263
}
162264

163265
/**
266+
* Retrieve a test product for requests against the Recommend API
267+
*
268+
* TODO: Implement store scoping and independently address 404 where objectID is not found
269+
*
164270
* @return string - Product ID string for use in API calls
165271
* @throws LocalizedException
166272
*/

etc/di.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,10 @@
206206
<argument name="logger" xsi:type="object">Algolia\AlgoliaSearch\Logger\AlgoliaLogger</argument>
207207
</arguments>
208208
</type>
209+
210+
<type name="\Algolia\AlgoliaSearch\Observer\RecommendSettings">
211+
<arguments>
212+
<argument name="logger" xsi:type="object">Algolia\AlgoliaSearch\Logger\AlgoliaLogger</argument>
213+
</arguments>
214+
</type>
209215
</config>

0 commit comments

Comments
 (0)