You are currently using multiple Algolia application IDs with your Magento installation.
+When verifying data in Algolia, please make sure you are referencing the correct application.
'; + + $this->notices[] = [ + 'selector' => '.entry-edit', + 'method' => 'before', + 'message' => $this->formatNotice($noticeTitle, $noticeContent), + ]; + } } diff --git a/Helper/Data.php b/Helper/Data.php index 64f23d571..7436729e8 100755 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -25,6 +25,7 @@ use Magento\Framework\Indexer\IndexerRegistry; use Magento\Search\Model\Query; use Magento\Search\Model\ResourceModel\Query\Collection as QueryCollection; +use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Model\App\Emulation; use Magento\Store\Model\StoreManagerInterface; @@ -165,6 +166,8 @@ public function rebuildStoreAdditionalSectionsIndex(int $storeId): void return; } + $this->algoliaHelper->setStoreId($storeId); + $additionalSections = $this->configHelper->getAutocompleteSections(); $protectedSections = ['products', 'categories', 'pages', 'suggestions']; @@ -188,6 +191,8 @@ public function rebuildStoreAdditionalSectionsIndex(int $storeId): void $this->algoliaHelper->moveIndex($tempIndexName, $indexName); $this->algoliaHelper->setSettings($indexName, $this->additionalSectionHelper->getIndexSettings($storeId)); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } } @@ -209,6 +214,8 @@ public function rebuildStorePageIndex($storeId, array $pageIds = null): void return; } + $this->algoliaHelper->setStoreId($storeId); + $indexName = $this->pageHelper->getIndexName($storeId); $this->startEmulation($storeId); @@ -252,6 +259,7 @@ public function rebuildStorePageIndex($storeId, array $pageIds = null): void $this->algoliaHelper->moveIndex($tempIndexName, $indexName); } $this->algoliaHelper->setSettings($indexName, $this->pageHelper->getIndexSettings($storeId)); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -351,11 +359,12 @@ public function moveStoreSuggestionIndex(int $storeId): void if ($this->isIndexingEnabled($storeId) === false) { return; } - + $this->algoliaHelper->setStoreId($storeId); $tmpIndexName = $this->suggestionHelper->getTempIndexName($storeId); $indexName = $this->suggestionHelper->getIndexName($storeId); $this->algoliaHelper->copyQueryRules($indexName, $tmpIndexName); $this->algoliaHelper->moveIndex($tmpIndexName, $indexName); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -462,6 +471,7 @@ public function rebuildStoreSuggestionIndexPage(int $storeId, QueryCollection $c return; } + $this->algoliaHelper->setStoreId($storeId); $collection = clone $collectionDefault; $collection->setCurPage($page)->setPageSize($pageSize); $collection->load(); @@ -483,6 +493,7 @@ public function rebuildStoreSuggestionIndexPage(int $storeId, QueryCollection $c unset($indexData); $collection->walk('clearInstance'); $collection->clear(); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); unset($collection); } @@ -495,6 +506,7 @@ public function rebuildStoreCategoryIndexPage($storeId, $collection, $page, $pag if ($this->isIndexingEnabled($storeId) === false) { return; } + $this->algoliaHelper->setStoreId($storeId); $collection->setCurPage($page)->setPageSize($pageSize); $collection->load(); $indexName = $this->categoryHelper->getIndexName($storeId); @@ -519,6 +531,7 @@ public function rebuildStoreCategoryIndexPage($storeId, $collection, $page, $pag $collection->walk('clearInstance'); $collection->clear(); unset($collection); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -682,6 +695,8 @@ public function rebuildStoreProductIndexPage( return; } + $this->algoliaHelper->setStoreId($storeId); + $wrapperLogMessage = 'rebuildStoreProductIndexPage: ' . $this->logger->getStoreName($storeId) . ', page ' . $page . ', pageSize ' . $pageSize; @@ -743,6 +758,9 @@ public function rebuildStoreProductIndexPage( if ($emulationInfo === null) { $this->stopEmulation(); } + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + $this->logger->stop($wrapperLogMessage); } @@ -856,6 +874,7 @@ protected function getSalesData($storeId, Collection $collection) public function deleteInactiveProducts($storeId): void { $indexName = $this->productHelper->getIndexName($storeId); + $this->algoliaHelper->setStoreId($storeId); $client = $this->algoliaHelper->getClient(); $objectIds = []; $counter = 0; @@ -876,6 +895,7 @@ public function deleteInactiveProducts($storeId): void if (!empty($objectIds)) { $this->deleteInactiveIds($storeId, $objectIds, $indexName); } + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -906,20 +926,39 @@ public function getBaseIndexName(int $storeId = null): string */ public function getIndexDataByStoreIds(): array { + $indexNames = []; - $indexNames[0] = [ - 'indexName' => $this->getBaseIndexName(), - 'priceKey' => '.' . $this->configHelper->getCurrencyCode() . '.default', - ]; + $indexNames[AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE] = $this->buildIndexData(); foreach ($this->storeManager->getStores() as $store) { - $indexNames[$store->getId()] = [ - 'indexName' => $this->getBaseIndexName($store->getId()), - 'priceKey' => '.' . $store->getCurrentCurrencyCode($store->getId()) . '.default', - ]; + $indexNames[$store->getId()] = $this->buildIndexData($store); } return $indexNames; } + /** + * @param StoreInterface|null $store + * @return array + * @throws NoSuchEntityException + */ + protected function buildIndexData(StoreInterface $store = null): array + { + $storeId = !is_null($store) ? $store->getStoreId() : null; + $currencyCode = !is_null($store) ? + $store->getCurrentCurrencyCode($storeId) : + $this->configHelper->getCurrencyCode(); + + return [ + 'appId' => $this->configHelper->getApplicationID($storeId), + 'apiKey' => $this->configHelper->getAPIKey($storeId), + 'indexName' => $this->getBaseIndexName($storeId), + 'priceKey' => '.' . $currencyCode . '.default', + 'facets' => $this->configHelper->getFacets($storeId), + 'currencyCode' => $this->configHelper->getCurrencyCode($storeId), + 'maxValuesPerFacet' => (int) $this->configHelper->getMaxValuesPerFacet($storeId), + 'categorySeparator' => $this->configHelper->getCategorySeparator($storeId), + ]; + } + /** * @param $storeId * @param $objectIds diff --git a/Helper/Entity/ProductHelper.php b/Helper/Entity/ProductHelper.php index 250d3cb63..45c54f5b3 100755 --- a/Helper/Entity/ProductHelper.php +++ b/Helper/Entity/ProductHelper.php @@ -350,6 +350,7 @@ public function getIndexSettings(?int $storeId = null): array */ public function setSettings(string $indexName, string $indexNameTmp, int $storeId, bool $saveToTmpIndicesToo = false): void { + $this->algoliaHelper->setStoreId($storeId); $indexSettings = $this->getIndexSettings($storeId); $this->algoliaHelper->setSettings($indexName, $indexSettings, false, true); @@ -378,6 +379,7 @@ public function setSettings(string $indexName, string $indexNameTmp, int $storeI '); } catch (AlgoliaException $e) { $this->logger->error('Error encountered while copying synonyms: ' . $e->getMessage()); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } try { @@ -390,8 +392,10 @@ public function setSettings(string $indexName, string $indexNameTmp, int $storeI if ($e->getCode() !== 404) { throw $e; } + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } } + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -1206,12 +1210,12 @@ protected function getAttributesForFaceting($storeId) } /** - * @param $indexName - * @param $storeId + * @param string $indexName + * @param int|null $storeId * @return void * @throws AlgoliaException */ - protected function setFacetsQueryRules($indexName, $storeId = null) + protected function setFacetsQueryRules(string $indexName, int $storeId = null) { $this->clearFacetsQueryRules($indexName); diff --git a/Helper/MerchandisingHelper.php b/Helper/MerchandisingHelper.php index a54090a78..942d67ec0 100755 --- a/Helper/MerchandisingHelper.php +++ b/Helper/MerchandisingHelper.php @@ -85,7 +85,9 @@ public function saveQueryRule(int $storeId, // Not catching AlgoliaSearchException for disabled query rules on purpose // It displays correct error message and navigates user to pricing page + $this->algoliaHelper->setStoreId($storeId); $this->algoliaHelper->saveRule($rule, $productsIndexName); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -106,7 +108,9 @@ public function deleteQueryRule(int $storeId, int $entityId, string $entityType) // Not catching AlgoliaSearchException for disabled query rules on purpose // It displays correct error message and navigates user to pricing page + $this->algoliaHelper->setStoreId($storeId); $this->algoliaHelper->deleteRule($productsIndexName, $ruleId); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** diff --git a/Model/IndexMover.php b/Model/IndexMover.php index 594a36987..7de50cd28 100644 --- a/Model/IndexMover.php +++ b/Model/IndexMover.php @@ -44,7 +44,9 @@ public function moveIndex(string $tmpIndexName, string $indexName, int $storeId) return; } + $this->algoliaHelper->setStoreId($storeId); $this->algoliaHelper->moveIndex($tmpIndexName, $indexName); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** diff --git a/Model/Indexer/AdditionalSection.php b/Model/Indexer/AdditionalSection.php index 73eb09db2..e4dd66ca1 100755 --- a/Model/Indexer/AdditionalSection.php +++ b/Model/Indexer/AdditionalSection.php @@ -5,34 +5,19 @@ use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\Data; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class AdditionalSection implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - private $fullAction; - private $storeManager; - private $queue; - private $configHelper; - private $messageManager; - private $output; - public function __construct( - StoreManagerInterface $storeManager, - Data $helper, - Queue $queue, - ConfigHelper $configHelper, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->queue = $queue; - $this->configHelper = $configHelper; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected Data $fullAction, + protected Queue $queue, + protected ConfigHelper $configHelper, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} public function execute($ids) { @@ -41,21 +26,6 @@ public function execute($ids) public function executeFull() { - if (!$this->configHelper->credentialsAreConfigured()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); - - return; - } - $storeIds = array_keys($this->storeManager->getStores()); foreach ($storeIds as $storeId) { @@ -63,8 +33,14 @@ public function executeFull() continue; } + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + $this->queue->addToQueue( - $this->fullAction, + Data::class, 'rebuildStoreAdditionalSectionsIndex', ['storeId' => $storeId], 1 diff --git a/Model/Indexer/Category.php b/Model/Indexer/Category.php index e2d5c9ffa..38f020b9a 100755 --- a/Model/Indexer/Category.php +++ b/Model/Indexer/Category.php @@ -7,59 +7,25 @@ use Algolia\AlgoliaSearch\Helper\Entity\CategoryHelper; use Algolia\AlgoliaSearch\Model\IndicesConfigurator; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class Category implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - private $storeManager; - private $categoryHelper; - private $fullAction; - private $queue; - private $configHelper; - private $messageManager; - private $output; - public static $affectedProductIds = []; public function __construct( - StoreManagerInterface $storeManager, - CategoryHelper $categoryHelper, - Data $helper, - Queue $queue, - ConfigHelper $configHelper, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->categoryHelper = $categoryHelper; - $this->queue = $queue; - $this->configHelper = $configHelper; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected CategoryHelper $categoryHelper, + protected Data $fullAction, + protected Queue $queue, + protected ConfigHelper $configHelper, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} public function execute($categoryIds) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); - - return; - } - $storeIds = array_keys($this->storeManager->getStores()); foreach ($storeIds as $storeId) { @@ -67,6 +33,12 @@ public function execute($categoryIds) continue; } + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + $this->rebuildAffectedProducts($storeId); $categoriesPerPage = $this->configHelper->getNumberOfElementByPage(); diff --git a/Model/Indexer/CategoryObserver.php b/Model/Indexer/CategoryObserver.php index 68fb9198e..c58ddee93 100755 --- a/Model/Indexer/CategoryObserver.php +++ b/Model/Indexer/CategoryObserver.php @@ -2,8 +2,8 @@ namespace Algolia\AlgoliaSearch\Model\Indexer; -use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Model\Indexer\Category as CategoryIndexer; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Catalog\Model\Category as CategoryModel; use Magento\Catalog\Model\ResourceModel\Category as CategoryResourceModel; use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection; @@ -12,34 +12,15 @@ class CategoryObserver { - /** @var IndexerRegistry */ - private $indexerRegistry; - /** @var CategoryIndexer */ private $indexer; - /** @var ConfigHelper */ - private $configHelper; - - /** @var ResourceConnection */ - protected $resource; - - /** - * CategoryObserver constructor. - * - * @param IndexerRegistry $indexerRegistry - * @param ConfigHelper $configHelper - * @param ResourceConnection $resource - */ public function __construct( IndexerRegistry $indexerRegistry, - ConfigHelper $configHelper, - ResourceConnection $resource + protected ResourceConnection $resource, + protected AlgoliaCredentialsManager $algoliaCredentialsManager ) { - $this->indexerRegistry = $indexerRegistry; $this->indexer = $indexerRegistry->get('algolia_categories'); - $this->configHelper = $configHelper; - $this->resource = $resource; } /** @@ -54,9 +35,7 @@ public function afterSave( CategoryResourceModel $result, CategoryModel $category ) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey()) { return $result; } $categoryResource->addCommitCallback(function () use ($category) { diff --git a/Model/Indexer/DeleteProduct.php b/Model/Indexer/DeleteProduct.php index ad6078bf1..97ab9ef4a 100755 --- a/Model/Indexer/DeleteProduct.php +++ b/Model/Indexer/DeleteProduct.php @@ -3,40 +3,21 @@ namespace Algolia\AlgoliaSearch\Model\Indexer; use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; -use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\Data; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class DeleteProduct implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - private $fullAction; - private $storeManager; - private $algoliaHelper; - private $queue; - private $configHelper; - private $messageManager; - private $output; - public function __construct( - StoreManagerInterface $storeManager, - Data $helper, - AlgoliaHelper $algoliaHelper, - Queue $queue, - ConfigHelper $configHelper, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->algoliaHelper = $algoliaHelper; - $this->queue = $queue; - $this->configHelper = $configHelper; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected Data $fullAction, + protected AlgoliaHelper $algoliaHelper, + protected Queue $queue, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} public function execute($ids) { @@ -45,23 +26,6 @@ public function execute($ids) public function executeFull() { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); - - return; - } - $storeIds = array_keys($this->storeManager->getStores()); foreach ($storeIds as $storeId) { @@ -69,6 +33,12 @@ public function executeFull() continue; } + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + $this->fullAction->deleteInactiveProducts($storeId); } } diff --git a/Model/Indexer/Page.php b/Model/Indexer/Page.php index 21dbd9d2e..4602bd58c 100755 --- a/Model/Indexer/Page.php +++ b/Model/Indexer/Page.php @@ -7,74 +7,21 @@ use Algolia\AlgoliaSearch\Helper\Data; use Algolia\AlgoliaSearch\Helper\Entity\PageHelper; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class Page implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - /** - * @var Data - */ - protected $fullAction; - /** - * @var StoreManagerInterface - */ - protected $storeManager; - /** - * @var PageHelper - */ - protected $pageHelper; - /** - * @var AlgoliaHelper - */ - protected $algoliaHelper; - /** - * @var Queue - */ - protected $queue; - /** - * @var ConfigHelper - */ - protected $configHelper; - /** - * @var ManagerInterface - */ - protected $messageManager; - /** - * @var ConsoleOutput - */ - protected $output; - - /** - * @param StoreManagerInterface $storeManager - * @param PageHelper $pageHelper - * @param Data $helper - * @param AlgoliaHelper $algoliaHelper - * @param Queue $queue - * @param ConfigHelper $configHelper - * @param ManagerInterface $messageManager - * @param ConsoleOutput $output - */ public function __construct( - StoreManagerInterface $storeManager, - PageHelper $pageHelper, - Data $helper, - AlgoliaHelper $algoliaHelper, - Queue $queue, - ConfigHelper $configHelper, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->pageHelper = $pageHelper; - $this->algoliaHelper = $algoliaHelper; - $this->queue = $queue; - $this->configHelper = $configHelper; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected PageHelper $pageHelper, + protected Data $fullAction, + protected AlgoliaHelper $algoliaHelper, + protected Queue $queue, + protected ConfigHelper $configHelper, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} /** * @param $ids @@ -82,23 +29,6 @@ public function __construct( */ public function execute($ids) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); - - return; - } - $storeIds = $this->pageHelper->getStores(); foreach ($storeIds as $storeId) { @@ -106,6 +36,12 @@ public function execute($ids) continue; } + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + if ($this->isPagesInAdditionalSections($storeId)) { $data = ['storeId' => $storeId]; if (is_array($ids) && count($ids) > 0) { @@ -113,7 +49,7 @@ public function execute($ids) } $this->queue->addToQueue( - $this->fullAction, + Data::class, 'rebuildStorePageIndex', $data, is_array($ids) ? count($ids) : 1 diff --git a/Model/Indexer/PageObserver.php b/Model/Indexer/PageObserver.php index 6908dd8ec..6dc51e785 100644 --- a/Model/Indexer/PageObserver.php +++ b/Model/Indexer/PageObserver.php @@ -2,7 +2,7 @@ namespace Algolia\AlgoliaSearch\Model\Indexer; -use Algolia\AlgoliaSearch\Helper\ConfigHelper; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Framework\Indexer\IndexerRegistry; use Magento\Framework\Model\AbstractModel; @@ -10,26 +10,18 @@ class PageObserver { private $indexer; - /** - * @var ConfigHelper - */ - private $configHelper; - public function __construct( IndexerRegistry $indexerRegistry, - ConfigHelper $configHelper + protected AlgoliaCredentialsManager $algoliaCredentialsManager ) { $this->indexer = $indexerRegistry->get('algolia_pages'); - $this->configHelper = $configHelper; } public function beforeSave( \Magento\Cms\Model\ResourceModel\Page $pageResource, AbstractModel $page ) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey()) { return [$page]; } @@ -46,9 +38,7 @@ public function beforeDelete( \Magento\Cms\Model\ResourceModel\Page $pageResource, AbstractModel $page ) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey()) { return [$page]; } diff --git a/Model/Indexer/Product.php b/Model/Indexer/Product.php index f0c6bb01a..85be4476d 100755 --- a/Model/Indexer/Product.php +++ b/Model/Indexer/Product.php @@ -9,75 +9,47 @@ use Algolia\AlgoliaSearch\Model\IndexMover; use Algolia\AlgoliaSearch\Model\IndicesConfigurator; use Algolia\AlgoliaSearch\Model\Queue; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Message\ManagerInterface; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class Product implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - private $storeManager; - private $productHelper; - private $algoliaHelper; - private $fullAction; - private $configHelper; - private $queue; - private $messageManager; - private $output; - public function __construct( - StoreManagerInterface $storeManager, - ProductHelper $productHelper, - Data $helper, - AlgoliaHelper $algoliaHelper, - ConfigHelper $configHelper, - Queue $queue, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->productHelper = $productHelper; - $this->algoliaHelper = $algoliaHelper; - $this->configHelper = $configHelper; - $this->queue = $queue; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected ProductHelper $productHelper, + protected Data $fullAction, + protected AlgoliaHelper $algoliaHelper, + protected ConfigHelper $configHelper, + protected Queue $queue, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} /** * @throws NoSuchEntityException */ public function execute($productIds) { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addWarning($errorMessage); - - return; - } - - if ($productIds) { - $productIds = array_unique(array_merge($productIds, $this->productHelper->getParentProductIds($productIds))); - } - $storeIds = array_keys($this->storeManager->getStores()); + $areParentsLoaded = false; foreach ($storeIds as $storeId) { if ($this->fullAction->isIndexingEnabled($storeId) === false) { continue; } + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + + if ($productIds && !$areParentsLoaded) { + $productIds = array_unique(array_merge($productIds, $this->productHelper->getParentProductIds($productIds))); + $areParentsLoaded = true; + } + $productsPerPage = $this->configHelper->getNumberOfElementByPage(); if (is_array($productIds) && count($productIds) > 0) { diff --git a/Model/Indexer/QueueRunner.php b/Model/Indexer/QueueRunner.php index 09116693d..8b7b02ee0 100644 --- a/Model/Indexer/QueueRunner.php +++ b/Model/Indexer/QueueRunner.php @@ -4,29 +4,18 @@ use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; class QueueRunner implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { public const INDEXER_ID = 'algolia_queue_runner'; - private $configHelper; - private $queue; - private $messageManager; - private $output; - public function __construct( - ConfigHelper $configHelper, - Queue $queue, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->configHelper = $configHelper; - $this->queue = $queue; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected ConfigHelper $configHelper, + protected Queue $queue, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} public function execute($ids) { @@ -35,19 +24,8 @@ public function execute($ids) public function executeFull() { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey()) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class); return; } diff --git a/Model/Indexer/Suggestion.php b/Model/Indexer/Suggestion.php index 5e43aa87d..9173902a7 100755 --- a/Model/Indexer/Suggestion.php +++ b/Model/Indexer/Suggestion.php @@ -7,40 +7,21 @@ use Algolia\AlgoliaSearch\Helper\Data; use Algolia\AlgoliaSearch\Helper\Entity\SuggestionHelper; use Algolia\AlgoliaSearch\Model\Queue; -use Magento\Framework\Message\ManagerInterface; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Magento\Store\Model\StoreManagerInterface; -use Symfony\Component\Console\Output\ConsoleOutput; class Suggestion implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface { - private $fullAction; - private $storeManager; - private $suggestionHelper; - private $algoliaHelper; - private $queue; - private $configHelper; - private $messageManager; - private $output; - public function __construct( - StoreManagerInterface $storeManager, - SuggestionHelper $suggestionHelper, - Data $helper, - AlgoliaHelper $algoliaHelper, - Queue $queue, - ConfigHelper $configHelper, - ManagerInterface $messageManager, - ConsoleOutput $output - ) { - $this->fullAction = $helper; - $this->storeManager = $storeManager; - $this->suggestionHelper = $suggestionHelper; - $this->algoliaHelper = $algoliaHelper; - $this->queue = $queue; - $this->configHelper = $configHelper; - $this->messageManager = $messageManager; - $this->output = $output; - } + protected StoreManagerInterface $storeManager, + protected SuggestionHelper $suggestionHelper, + protected Data $fullAction, + protected AlgoliaHelper $algoliaHelper, + protected Queue $queue, + protected ConfigHelper $configHelper, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} public function execute($ids) { @@ -48,23 +29,6 @@ public function execute($ids) public function executeFull() { - if (!$this->configHelper->getApplicationID() - || !$this->configHelper->getAPIKey() - || !$this->configHelper->getSearchOnlyAPIKey()) { - $errorMessage = 'Algolia reindexing failed: - You need to configure your Algolia credentials in Stores > Configuration > Algolia Search.'; - - if (php_sapi_name() === 'cli') { - $this->output->writeln($errorMessage); - - return; - } - - $this->messageManager->addErrorMessage($errorMessage); - - return; - } - $storeIds = array_keys($this->storeManager->getStores()); foreach ($storeIds as $storeId) { @@ -72,7 +36,13 @@ public function executeFull() continue; } - $this->queue->addToQueue($this->fullAction, 'rebuildStoreSuggestionIndex', ['storeId' => $storeId], 1); + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->algoliaCredentialsManager->displayErrorMessage(self::class, $storeId); + + return; + } + + $this->queue->addToQueue(Data::class, 'rebuildStoreSuggestionIndex', ['storeId' => $storeId], 1); } } diff --git a/Model/IndicesConfigurator.php b/Model/IndicesConfigurator.php index 8179adfca..662d0485d 100644 --- a/Model/IndicesConfigurator.php +++ b/Model/IndicesConfigurator.php @@ -12,70 +12,25 @@ use Algolia\AlgoliaSearch\Helper\Entity\ProductHelper; use Algolia\AlgoliaSearch\Helper\Entity\SuggestionHelper; use Algolia\AlgoliaSearch\Helper\Logger; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Algolia\AlgoliaSearch\Service\IndexNameFetcher; use Magento\Framework\Exception\NoSuchEntityException; class IndicesConfigurator { - /** @var Data */ - protected $baseHelper; - - /** @var AlgoliaHelper */ - protected $algoliaHelper; - - /** @var ConfigHelper */ - protected $configHelper; - - /** @var ProductHelper */ - protected $productHelper; - - /** @var CategoryHelper */ - protected $categoryHelper; - - /** @var PageHelper */ - protected $pageHelper; - - /** @var SuggestionHelper */ - protected $suggestionHelper; - - /** @var AdditionalSectionHelper */ - protected $additionalSectionHelper; - - /** @var Logger */ - protected $logger; - - /** - * @param Data $baseHelper - * @param AlgoliaHelper $algoliaHelper - * @param ConfigHelper $configHelper - * @param ProductHelper $productHelper - * @param CategoryHelper $categoryHelper - * @param PageHelper $pageHelper - * @param SuggestionHelper $suggestionHelper - * @param AdditionalSectionHelper $additionalSectionHelper - * @param Logger $logger - */ public function __construct( - Data $baseHelper, - AlgoliaHelper $algoliaHelper, - ConfigHelper $configHelper, - ProductHelper $productHelper, - CategoryHelper $categoryHelper, - PageHelper $pageHelper, - SuggestionHelper $suggestionHelper, - AdditionalSectionHelper $additionalSectionHelper, - Logger $logger - ) { - $this->baseHelper = $baseHelper; - $this->algoliaHelper = $algoliaHelper; - $this->configHelper = $configHelper; - $this->productHelper = $productHelper; - $this->categoryHelper = $categoryHelper; - $this->pageHelper = $pageHelper; - $this->suggestionHelper = $suggestionHelper; - $this->additionalSectionHelper = $additionalSectionHelper; - $this->logger = $logger; - } + protected Data $baseHelper, + protected AlgoliaHelper $algoliaHelper, + protected ConfigHelper $configHelper, + protected ProductHelper $productHelper, + protected CategoryHelper $categoryHelper, + protected PageHelper $pageHelper, + protected SuggestionHelper $suggestionHelper, + protected AdditionalSectionHelper $additionalSectionHelper, + protected AlgoliaCredentialsManager $algoliaCredentialsManager, + protected Logger $logger + ) + {} /** * @param int $storeId @@ -90,7 +45,7 @@ public function saveConfigurationToAlgolia(int $storeId, bool $useTmpIndex = fal $logEventName = 'Save configuration to Algolia for store: ' . $this->logger->getStoreName($storeId); $this->logger->start($logEventName); - if (!($this->configHelper->getApplicationID() && $this->configHelper->getAPIKey())) { + if (!$this->algoliaCredentialsManager->checkCredentials($storeId)) { $this->logger->log('Algolia credentials are not filled.'); $this->logger->stop($logEventName); @@ -103,6 +58,8 @@ public function saveConfigurationToAlgolia(int $storeId, bool $useTmpIndex = fal return; } + $this->algoliaHelper->setStoreId($storeId); + $this->setCategoriesSettings($storeId); $this->algoliaHelper->waitLastTask(); @@ -126,10 +83,10 @@ public function saveConfigurationToAlgolia(int $storeId, bool $useTmpIndex = fal $this->algoliaHelper->waitLastTask(); $this->setProductsSettings($storeId, $useTmpIndex); - $this->algoliaHelper->waitLastTask(); $this->setExtraSettings($storeId, $useTmpIndex); - $this->algoliaHelper->waitLastTask(); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** @@ -273,6 +230,7 @@ protected function setExtraSettings(int $storeId, bool $saveToTmpIndicesToo): vo $this->logger->log('Index name: ' . $indexName); $this->logger->log('Extra settings: ' . json_encode($extraSettings)); $this->algoliaHelper->setSettings($indexName, $extraSettings, true); + $this->algoliaHelper->waitLastTask(); if ($section === 'products' && $saveToTmpIndicesToo) { $tempIndexName = $indexName . IndexNameFetcher::INDEX_TEMP_SUFFIX; diff --git a/Observer/AddAlgoliaAssetsObserver.php b/Observer/AddAlgoliaAssetsObserver.php index d7a5ac512..e957f7b51 100755 --- a/Observer/AddAlgoliaAssetsObserver.php +++ b/Observer/AddAlgoliaAssetsObserver.php @@ -3,7 +3,11 @@ namespace Algolia\AlgoliaSearch\Observer; use Algolia\AlgoliaSearch\Helper\ConfigHelper; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; +use Magento\Catalog\Model\Category; +use Magento\Framework\App\Request\Http; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Registry; use Magento\Framework\View\Layout; use Magento\Framework\View\Page\Config as PageConfig; @@ -11,65 +15,49 @@ /** * Algolia search observer model - * @todo Add AlgoliaCredentialsManager to this class once it's available */ class AddAlgoliaAssetsObserver implements ObserverInterface { - protected $config; - protected $registry; - protected $storeManager; - protected $pageConfig; - protected $request; + public function __construct( + protected ConfigHelper $config, + protected Registry $registry, + protected StoreManagerInterface $storeManager, + protected PageConfig $pageConfig, + protected Http $request, + protected AlgoliaCredentialsManager $algoliaCredentialsManager + ) + {} /** - * @param ConfigHelper $configHelper - * @param Registry $registry - * @param StoreManagerInterface $storeManager - * @param PageConfig $pageConfig - * @param \Magento\Framework\App\Request\Http $http + * @throws NoSuchEntityException */ - public function __construct( - ConfigHelper $configHelper, - Registry $registry, - StoreManagerInterface $storeManager, - PageConfig $pageConfig, - \Magento\Framework\App\Request\Http $http - ) { - $this->config = $configHelper; - $this->registry = $registry; - $this->storeManager = $storeManager; - $this->pageConfig = $pageConfig; - $this->request = $http; - } - public function execute(\Magento\Framework\Event\Observer $observer) { $actionName = $this->request->getFullActionName(); if ($actionName === 'swagger_index_index') { return $this; } - if ($this->config->isEnabledFrontEnd()) { - if ($this->config->getApplicationID() && $this->config->getAPIKey()) { - if ($this->config->isAutoCompleteEnabled() || $this->config->isInstantEnabled()) { + $storeId = $this->storeManager->getStore()->getId(); + if ($this->config->isEnabledFrontEnd($storeId)) { + if ($this->algoliaCredentialsManager->checkCredentials($storeId)) { + if ($this->config->isAutoCompleteEnabled($storeId) || $this->config->isInstantEnabled($storeId)) { /** @var Layout $layout */ $layout = $observer->getData('layout'); $layout->getUpdate()->addHandle('algolia_search_handle'); - $this->loadPreventBackendRenderingHandle($layout); + $this->loadPreventBackendRenderingHandle($layout, $storeId); } } } } - private function loadPreventBackendRenderingHandle(Layout $layout) + private function loadPreventBackendRenderingHandle(Layout $layout, int $storeId): void { - $storeId = $this->storeManager->getStore()->getId(); - - if ($this->config->preventBackendRendering() === false) { + if ($this->config->preventBackendRendering($storeId) === false) { return; } - /** @var \Magento\Catalog\Model\Category $category */ + /** @var Category $category */ $category = $this->registry->registry('current_category'); if (!$category) { return; @@ -79,7 +67,7 @@ private function loadPreventBackendRenderingHandle(Layout $layout) return; } - $displayMode = $this->config->getBackendRenderingDisplayMode(); + $displayMode = $this->config->getBackendRenderingDisplayMode($storeId); if ($displayMode === 'only_products' && $category->getDisplayMode() === 'PAGE') { return; } diff --git a/Service/AlgoliaCredentialsManager.php b/Service/AlgoliaCredentialsManager.php new file mode 100644 index 000000000..b3a171f59 --- /dev/null +++ b/Service/AlgoliaCredentialsManager.php @@ -0,0 +1,94 @@ +configHelper->getApplicationID($storeId) && $this->configHelper->getAPIKey($storeId); + } + + /** + * Validates the credentials set on a given store level with an additional check on the search only API Key + * + * @param int|null $storeId + * @return bool + */ + public function checkCredentialsWithSearchOnlyAPIKey(int $storeId = null): bool + { + return $this->checkCredentials($storeId) && $this->configHelper->getSearchOnlyAPIKey($storeId); + } + + /** + * Displays an error message in the console or in the admin + * + * @param string $class + * @param int|null $storeId + * @return void + */ + public function displayErrorMessage(string $class, ?int $storeId = null): void + { + try { + $storeInfo = $storeId ? ' for store '. $this->storeManager->getStore($storeId)->getName() : ''; + $errorMessage = ' +' . $class . ': Algolia credentials missing' . $storeInfo . ' + => You need to configure your credentials in Stores > Configuration > Algolia Search.'; + + if (php_sapi_name() === 'cli') { + $this->output->writeln($errorMessage); + + return; + } + + $this->messageManager->addErrorMessage($errorMessage); + } catch (NoSuchEntityException $exception) { + $this->messageManager->addErrorMessage(__("Unable to locate store details: %1", $exception->getMessage())); + } + } + + /** + * Checks if multiple application IDs are configured + * + * @return bool + */ + public function hasMultipleApplicationIDs(): bool + { + $applications = []; + + foreach ($this->storeManager->getStores() as $store) { + $storeId = $store->getId(); + if ($this->checkCredentials($storeId)) { + if (!isset($applications[$this->configHelper->getApplicationID($storeId)])) { + $applications[$this->configHelper->getApplicationID($storeId)] = true; + } + + if (count($applications) > 1) { + return true; + } + } + } + + return false; + } +} diff --git a/Setup/Patch/Data/RebuildReplicasPatch.php b/Setup/Patch/Data/RebuildReplicasPatch.php index b5f96a39c..10a120eb7 100644 --- a/Setup/Patch/Data/RebuildReplicasPatch.php +++ b/Setup/Patch/Data/RebuildReplicasPatch.php @@ -2,9 +2,9 @@ namespace Algolia\AlgoliaSearch\Setup\Patch\Data; -use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\Entity\ProductHelper; use Algolia\AlgoliaSearch\Registry\ReplicaState; +use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; use Algolia\AlgoliaSearch\Service\Product\ReplicaManager; use Magento\Framework\App\Area; use Magento\Framework\App\State as AppState; @@ -18,14 +18,14 @@ class RebuildReplicasPatch implements DataPatchInterface { public function __construct( - protected ModuleDataSetupInterface $moduleDataSetup, - protected StoreManagerInterface $storeManager, - protected ReplicaManager $replicaManager, - protected ProductHelper $productHelper, - protected AppState $appState, - protected ReplicaState $replicaState, - protected ConfigHelper $configHelper, - protected LoggerInterface $logger + protected ModuleDataSetupInterface $moduleDataSetup, + protected StoreManagerInterface $storeManager, + protected ReplicaManager $replicaManager, + protected ProductHelper $productHelper, + protected AppState $appState, + protected ReplicaState $replicaState, + protected AlgoliaCredentialsManager $algoliaCredentialsManager, + protected LoggerInterface $logger ) {} @@ -52,11 +52,6 @@ public function getAliases(): array */ public function apply(): PatchInterface { - if (!$this->configHelper->credentialsAreConfigured()) { - $this->logger->warning("Algolia credentials are not configured. Aborting replica rebuild patch. If you need to rebuild your replicas run `bin/magento algolia:replicas:rebuild`"); - return $this; - } - $this->moduleDataSetup->getConnection()->startSetup(); try { $this->appState->setAreaCode(Area::AREA_ADMINHTML); @@ -67,10 +62,19 @@ public function apply(): PatchInterface $storeIds = array_keys($this->storeManager->getStores()); // Delete all replicas before resyncing in case of incorrect replica assignments foreach ($storeIds as $storeId) { + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + $this->logger->warning("Algolia credentials are not configured for store $storeId. Skipping auto replica rebuild for this store. If you need to rebuild your replicas run `bin/magento algolia:replicas:rebuild`"); + continue; + } + $this->replicaManager->deleteReplicasFromAlgolia($storeId); } foreach ($storeIds as $storeId) { + if (!$this->algoliaCredentialsManager->checkCredentialsWithSearchOnlyAPIKey($storeId)) { + continue; + } + $this->replicaState->setChangeState(ReplicaState::REPLICA_STATE_CHANGED, $storeId); // avoids latency $this->replicaManager->syncReplicasToAlgolia($storeId, $this->productHelper->getIndexSettings($storeId)); } diff --git a/Test/Integration/Category/MultiStoreCategoriesTest.php b/Test/Integration/Category/MultiStoreCategoriesTest.php index 11af9176d..ed8c8f947 100644 --- a/Test/Integration/Category/MultiStoreCategoriesTest.php +++ b/Test/Integration/Category/MultiStoreCategoriesTest.php @@ -4,6 +4,7 @@ use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; use Algolia\AlgoliaSearch\Exceptions\ExceededRetriesException; +use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Model\Indexer\Category; use Algolia\AlgoliaSearch\Test\Integration\MultiStoreTestCase; use Magento\Catalog\Api\CategoryRepositoryInterface; @@ -55,9 +56,12 @@ public function testMultiStoreCategoryIndices() { // Check that every store has the right number of categories foreach ($this->storeManager->getStores() as $store) { + $this->algoliaHelper->setStoreId($store->getId()); $this->assertNbOfRecordsPerStore($store->getCode(), 'categories', $this->assertValues->expectedCategory); } + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + $defaultStore = $this->storeRepository->get('default'); $fixtureSecondStore = $this->storeRepository->get('fixture_second_store'); @@ -78,12 +82,14 @@ public function testMultiStoreCategoryIndices() $this->categoriesIndexer->execute([self::BAGS_CATEGORY_ID]); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $this->assertAlgoliaRecordValues( $this->indexPrefix . 'default_categories', (string) self::BAGS_CATEGORY_ID, ['name' => self::BAGS_CATEGORY_NAME] ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->assertAlgoliaRecordValues( $this->indexPrefix . 'fixture_second_store_categories', (string) self::BAGS_CATEGORY_ID, @@ -97,20 +103,25 @@ public function testMultiStoreCategoryIndices() ['is_active' => 0] ); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); $this->categoriesIndexer->execute([self::BAGS_CATEGORY_ID]); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $this->assertNbOfRecordsPerStore( $defaultStore->getCode(), 'categories', $this->assertValues->expectedCategory ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->assertNbOfRecordsPerStore( $fixtureSecondStore->getCode(), 'categories', $this->assertValues->expectedCategory - 1 ); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** diff --git a/Test/Integration/Config/MultiStoreConfigTest.php b/Test/Integration/Config/MultiStoreConfigTest.php index 76e99147c..651b7d97b 100644 --- a/Test/Integration/Config/MultiStoreConfigTest.php +++ b/Test/Integration/Config/MultiStoreConfigTest.php @@ -2,6 +2,8 @@ namespace Algolia\AlgoliaSearch\Test\Integration\Config; +use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; +use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Test\Integration\MultiStoreTestCase; @@ -26,23 +28,20 @@ public function testMultiStoreIndicesCreation() $this->setupStore($store, true); } + $defaultStore = $this->storeRepository->get('default'); + $fixtureSecondStore = $this->storeRepository->get('fixture_second_store'); + $indicesCreatedByTest = 0; - $indices = $this->algoliaHelper->listIndexes(); - foreach ($indices['items'] as $index) { - $name = $index['name']; + $this->algoliaHelper->setStoreId($defaultStore->getId()); + $indicesCreatedByTest += $this->countStoreIndices(); - if (mb_strpos($name, $this->indexPrefix) === 0) { - $indicesCreatedByTest++; - } - } + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); + $indicesCreatedByTest += $this->countStoreIndices(); // Check that the configuration created the appropriate number of indices (7 (4 mains + 3 replicas per store => 3*7=21) $this->assertEquals(21, $indicesCreatedByTest); - $defaultStore = $this->storeRepository->get('default'); - $fixtureSecondStore = $this->storeRepository->get('fixture_second_store'); - // Change category configuration at store level (attributes and ranking) $attributesFromConfig = $this->configHelper->getCategoryAdditionalAttributes($defaultStore->getId()); $attributesFromConfigAlt = $attributesFromConfig; @@ -88,10 +87,14 @@ public function testMultiStoreIndicesCreation() $fixtureSecondStore->getCode() ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->indicesConfigurator->saveConfigurationToAlgolia($fixtureSecondStore->getId()); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $defaultCategoryIndexSettings = $this->algoliaHelper->getSettings($this->indexPrefix . 'default_categories'); + + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $fixtureCategoryIndexSettings = $this->algoliaHelper->getSettings($this->indexPrefix . 'fixture_second_store_categories'); $attributeFromConfig = 'unordered(' . self::ADDITIONAL_ATTRIBUTE . ')'; @@ -102,12 +105,38 @@ public function testMultiStoreIndicesCreation() $this->assertNotContains($rankingFromConfig, $defaultCategoryIndexSettings['customRanking']); $this->assertContains($rankingFromConfig, $fixtureCategoryIndexSettings['customRanking']); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $defaultProductIndexRules = $this->algoliaHelper->searchRules($this->indexPrefix . 'default_products'); + + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $fixtureProductIndexRules = $this->algoliaHelper->searchRules($this->indexPrefix . 'fixture_second_store_products'); // Check that the Rule has only been created for the fixture store $this->assertEquals(0, $defaultProductIndexRules['nbHits']); $this->assertEquals(1, $fixtureProductIndexRules['nbHits']); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + } + + /** + * @return int + * @throws AlgoliaException + */ + protected function countStoreIndices(): int + { + $indices = $this->algoliaHelper->listIndexes(); + + $indicesCreatedByTest = 0; + + foreach ($indices['items'] as $index) { + $name = $index['name']; + + if (mb_strpos($name, $this->indexPrefix) === 0) { + $indicesCreatedByTest++; + } + } + + return $indicesCreatedByTest; } protected function tearDown(): void diff --git a/Test/Integration/MultiStoreTestCase.php b/Test/Integration/MultiStoreTestCase.php index 25ea0f71b..83f82a9c0 100644 --- a/Test/Integration/MultiStoreTestCase.php +++ b/Test/Integration/MultiStoreTestCase.php @@ -3,6 +3,8 @@ namespace Algolia\AlgoliaSearch\Test\Integration; use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; +use Algolia\AlgoliaSearch\Exceptions\ExceededRetriesException; +use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Model\IndicesConfigurator; use Magento\Framework\Exception\LocalizedException; @@ -68,17 +70,23 @@ protected function setupStore(StoreInterface $store, bool $enableInstantSearch = { $this->setConfig( 'algoliasearch_credentials/credentials/application_id', - getenv('ALGOLIA_APPLICATION_ID'), + $store->getCode() === 'fixture_second_store' && getenv('ALGOLIA_APPLICATION_ID_ALT') ? + getenv('ALGOLIA_APPLICATION_ID_ALT') : + getenv('ALGOLIA_APPLICATION_ID'), $store->getCode() ); $this->setConfig( 'algoliasearch_credentials/credentials/search_only_api_key', - getenv('ALGOLIA_SEARCH_KEY_1') ?: getenv('ALGOLIA_SEARCH_API_KEY'), + $store->getCode() === 'fixture_second_store' && getenv('ALGOLIA_SEARCH_KEY_ALT') ? + getenv('ALGOLIA_SEARCH_KEY_ALT') : + getenv('ALGOLIA_SEARCH_KEY'), $store->getCode() ); $this->setConfig( 'algoliasearch_credentials/credentials/api_key', - getenv('ALGOLIA_API_KEY'), + $store->getCode() === 'fixture_second_store' && getenv('ALGOLIA_API_KEY_ALT') ? + getenv('ALGOLIA_API_KEY_ALT') : + getenv('ALGOLIA_API_KEY'), $store->getCode() ); $this->setConfig( @@ -91,7 +99,48 @@ protected function setupStore(StoreInterface $store, bool $enableInstantSearch = $this->setConfig(ConfigHelper::IS_INSTANT_ENABLED, 1, $store->getCode()); } + $this->algoliaHelper->setStoreId($store->getId()); $this->indicesConfigurator->saveConfigurationToAlgolia($store->getId()); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + } + + /** + * @throws ExceededRetriesException + * @throws AlgoliaException + */ + protected function tearDown(): void + { + $this->clearStoresIndices(true); + $this->clearStoresIndices(); // Remaining replicas + } + + protected function clearStoresIndices($wait = false) + { + foreach ($this->storeManager->getStores() as $store) { + $this->algoliaHelper->setStoreId($store->getId()); + $deletedStoreIndices = 0; + + $indices = $this->algoliaHelper->listIndexes(); + + foreach ($indices['items'] as $index) { + $name = $index['name']; + + if (mb_strpos($name, $this->indexPrefix) === 0) { + try { + $this->algoliaHelper->deleteIndex($name); + $deletedStoreIndices++; + } catch (AlgoliaException $e) { + // Might be a replica + } + } + } + + if ($deletedStoreIndices > 0 && $wait) { + $this->algoliaHelper->waitLastTask(); + } + } + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } } diff --git a/Test/Integration/Page/MultiStorePagesTest.php b/Test/Integration/Page/MultiStorePagesTest.php index 84cb1c5a6..0a71cdba8 100644 --- a/Test/Integration/Page/MultiStorePagesTest.php +++ b/Test/Integration/Page/MultiStorePagesTest.php @@ -4,6 +4,7 @@ use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; use Algolia\AlgoliaSearch\Exceptions\ExceededRetriesException; +use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Test\Integration\MultiStoreTestCase; use Algolia\AlgoliaSearch\Model\Indexer\Page; @@ -55,6 +56,7 @@ public function testMultiStorePageIndices() { // Check that every store has the right number of pages foreach ($this->storeManager->getStores() as $store) { + $this->algoliaHelper->setStoreId($store->getId()); $this->assertNbOfRecordsPerStore( $store->getCode(), 'pages', @@ -64,6 +66,8 @@ public function testMultiStorePageIndices() ); } + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + $defaultStore = $this->storeRepository->get('default'); $fixtureSecondStore = $this->storeRepository->get('fixture_second_store'); @@ -80,17 +84,21 @@ public function testMultiStorePageIndices() $this->pagesIndexer->execute([self::ABOUT_US_PAGE_ID]); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $this->assertNbOfRecordsPerStore( $defaultStore->getCode(), 'pages', $this->assertValues->expectedPages ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->assertNbOfRecordsPerStore( $fixtureSecondStore->getCode(), 'pages', $this->assertValues->expectedExcludePages - 1 ); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** diff --git a/Test/Integration/Product/MultiStoreProductsTest.php b/Test/Integration/Product/MultiStoreProductsTest.php index 207ce43b3..f3e67e596 100644 --- a/Test/Integration/Product/MultiStoreProductsTest.php +++ b/Test/Integration/Product/MultiStoreProductsTest.php @@ -2,6 +2,7 @@ namespace Algolia\AlgoliaSearch\Test\Integration\Product; +use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Model\Indexer\Product; use Algolia\AlgoliaSearch\Test\Integration\MultiStoreTestCase; use Magento\Catalog\Api\Data\ProductInterface; @@ -69,6 +70,7 @@ public function testMultiStoreProductIndices() { // Check that every store has the right number of products foreach ($this->storeManager->getStores() as $store) { + $this->algoliaHelper->setStoreId($store->getId()); $this->assertNbOfRecordsPerStore( $store->getCode(), 'products', @@ -103,18 +105,22 @@ public function testMultiStoreProductIndices() $this->productsIndexer->execute([self::VOYAGE_YOGA_BAG_ID]); $this->algoliaHelper->waitLastTask(); + $this->algoliaHelper->setStoreId($defaultStore->getId()); $this->assertAlgoliaRecordValues( $this->indexPrefix . 'default_products', (string) self::VOYAGE_YOGA_BAG_ID, ['name' => self::VOYAGE_YOGA_BAG_NAME] ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->assertAlgoliaRecordValues( $this->indexPrefix . 'fixture_second_store_products', (string) self::VOYAGE_YOGA_BAG_ID, ['name' => self::VOYAGE_YOGA_BAG_NAME_ALT] ); + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); + // Unassign product from a single website (removed from test website (second and third store)) $baseWebsite = $this->websiteRepository->get('base'); @@ -128,6 +134,7 @@ public function testMultiStoreProductIndices() $this->algoliaHelper->waitLastTask(); // default store should have the same number of products + $this->algoliaHelper->setStoreId($defaultStore->getId()); $this->assertNbOfRecordsPerStore( $defaultStore->getCode(), 'products', @@ -135,17 +142,21 @@ public function testMultiStoreProductIndices() ); // Stores from test website must have one less product + $this->algoliaHelper->setStoreId($fixtureThirdStore->getId()); $this->assertNbOfRecordsPerStore( $fixtureThirdStore->getCode(), 'products', count(self::SKUS) - 1 ); + $this->algoliaHelper->setStoreId($fixtureSecondStore->getId()); $this->assertNbOfRecordsPerStore( $fixtureSecondStore->getCode(), 'products', count(self::SKUS) - 1 ); + + $this->algoliaHelper->setStoreId(AlgoliaHelper::ALGOLIA_DEFAULT_SCOPE); } /** diff --git a/Test/Integration/Product/ProductsIndexingTest.php b/Test/Integration/Product/ProductsIndexingTest.php index 1b42779ea..f953314d4 100644 --- a/Test/Integration/Product/ProductsIndexingTest.php +++ b/Test/Integration/Product/ProductsIndexingTest.php @@ -106,8 +106,8 @@ private function getValidTestProduct() */ protected function tearDown(): void { - parent::tearDown(); - $this->updateStockItem(self::OUT_OF_STOCK_PRODUCT_SKU, true); + + parent::tearDown(); } } diff --git a/Test/Integration/Product/ReplicaIndexingTest.php b/Test/Integration/Product/ReplicaIndexingTest.php index c0e27cc53..394ea1ac1 100644 --- a/Test/Integration/Product/ReplicaIndexingTest.php +++ b/Test/Integration/Product/ReplicaIndexingTest.php @@ -317,4 +317,30 @@ protected function assertNoSortingAttribute($sortAttr, $sortDir): void $this->assertFalse($this->hasSortingAttribute($sortAttr, $sortDir)); } + protected function tearDown(): void + { + parent::tearDown(); + + // Makes sure that the original values are restored in case a test is failing and doesn't finish + $this->configHelper->setSorting( + [ + [ + 'attribute' => 'price', + 'sort' => 'asc', + 'sortLabel' => 'Lowest Price' + ], + [ + 'attribute' => 'price', + 'sort' => 'desc', + 'sortLabel' => 'Highest Price' + ], + [ + 'attribute' => 'created_at', + 'sort' => 'desc', + 'sortLabel' => 'Newest first' + ] + ] + ); + } + } diff --git a/Test/Integration/TestCase.php b/Test/Integration/TestCase.php index 2c3f39ec0..d127fd5c3 100644 --- a/Test/Integration/TestCase.php +++ b/Test/Integration/TestCase.php @@ -162,6 +162,7 @@ protected function setConfigFromArray(array $settings): void { foreach ($settings as $key => $value) { $this->setConfig($key, $value); + $this->setConfig($key, $value, 'admin'); } } @@ -213,10 +214,17 @@ private function bootstrap() $this->configHelper = $this->getObjectManager()->create(ConfigHelper::class); + $this->indexPrefix = 'magento2_' . date('Y-m-d_H:i:s') . '_' . (getenv('INDEX_PREFIX') ?: 'circleci_'); + + // Admin + $this->setConfig('algoliasearch_credentials/credentials/application_id', getenv('ALGOLIA_APPLICATION_ID'), 'admin'); + $this->setConfig('algoliasearch_credentials/credentials/search_only_api_key', getenv('ALGOLIA_SEARCH_KEY'), 'admin'); + $this->setConfig('algoliasearch_credentials/credentials/api_key', getenv('ALGOLIA_API_KEY'), 'admin'); + $this->setConfig('algoliasearch_credentials/credentials/index_prefix', $this->indexPrefix, 'admin'); + // Default website $this->setConfig('algoliasearch_credentials/credentials/application_id', getenv('ALGOLIA_APPLICATION_ID')); - $this->setConfig('algoliasearch_credentials/credentials/search_only_api_key', getenv('ALGOLIA_SEARCH_KEY_1') ?: getenv('ALGOLIA_SEARCH_API_KEY')); + $this->setConfig('algoliasearch_credentials/credentials/search_only_api_key', getenv('ALGOLIA_SEARCH_KEY')); $this->setConfig('algoliasearch_credentials/credentials/api_key', getenv('ALGOLIA_API_KEY')); - $this->indexPrefix = 'magento2_' . date('Y-m-d_H:i:s') . '_' . (getenv('INDEX_PREFIX') ?: 'circleci_'); $this->setConfig('algoliasearch_credentials/credentials/index_prefix', $this->indexPrefix); $this->algoliaHelper = $this->getObjectManager()->create(AlgoliaHelper::class); diff --git a/Test/Integration/_files/second_website_with_two_stores_and_products.php b/Test/Integration/_files/second_website_with_two_stores_and_products.php index f07321e61..3283de0bb 100644 --- a/Test/Integration/_files/second_website_with_two_stores_and_products.php +++ b/Test/Integration/_files/second_website_with_two_stores_and_products.php @@ -66,13 +66,11 @@ } $configManager = $objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); - -$configManager->setValue('algoliasearch_credentials/credentials/application_id', getenv('ALGOLIA_APPLICATION_ID')); -$configManager->setValue('algoliasearch_credentials/credentials/search_only_api_key', getenv('ALGOLIA_SEARCH_API_KEY')); -$configManager->setValue('algoliasearch_credentials/credentials/api_key', getenv('ALGOLIA_API_KEY')); -$configManager->setValue('algoliasearch_credentials/credentials/index_prefix', 'TEMP'); // Temporarily disable indexing during product assignment to stores -$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 0); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 0, 'store', 'admin'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 0, 'store', 'default'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 0, 'store', 'fixture_second_store'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 0, 'store', 'fixture_third_store'); $productSkus = MultiStoreProductsTest::SKUS; $productRepository = Bootstrap::getObjectManager() @@ -84,7 +82,10 @@ $productRepository->save($product); } -$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 1); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 1, 'store', 'admin'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 1, 'store', 'default'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 1, 'store', 'fixture_second_store'); +$configManager->setValue('algoliasearch_credentials/credentials/enable_backend', 1, 'store', 'fixture_third_store'); /* Refresh CatalogSearch index */ /** @var IndexerRegistry $indexerRegistry */ diff --git a/view/adminhtml/templates/landingpage/search-configuration.phtml b/view/adminhtml/templates/landingpage/search-configuration.phtml index 274b74119..67937b490 100644 --- a/view/adminhtml/templates/landingpage/search-configuration.phtml +++ b/view/adminhtml/templates/landingpage/search-configuration.phtml @@ -11,15 +11,9 @@ $landingPage = $block->getLandingPage(); $landingPageId = $landingPage->getId(); $isConfig = [ - 'appId' => $configHelper->getApplicationID(), - 'apiKey' => $configHelper->getSearchOnlyAPIKey(), 'indexDataByStoreIds' => $block->getCoreHelper()->getIndexDataByStoreIds(), 'routing' => false, - 'facets' => $configHelper->getFacets(), - 'currencyCode' => $configHelper->getCurrencyCode(), - 'maxValuesPerFacet' => (int) $configHelper->getMaxValuesPerFacet(), 'landingPageConfig' => json_decode($landingPage->getConfiguration()), - 'categorySeparator' => $configHelper->getCategorySeparator(), 'searchParameters' => [ 'query' => $landingPage->getQuery(), 'hitsPerPage' => 10, @@ -79,9 +73,11 @@ $isConfig = [