From 9b4bf8e0eedfd32055974978fae49117bdca2fa9 Mon Sep 17 00:00:00 2001 From: Damien Couchez Date: Tue, 7 Oct 2025 14:19:27 +0200 Subject: [PATCH 1/2] MAGE-1326: refactor assets observer and introduce RenderingManager class --- Observer/AddAlgoliaAssetsObserver.php | 50 +++------------ Service/RenderingManager.php | 87 +++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 Service/RenderingManager.php diff --git a/Observer/AddAlgoliaAssetsObserver.php b/Observer/AddAlgoliaAssetsObserver.php index 0d4d501dd..18bf7f081 100755 --- a/Observer/AddAlgoliaAssetsObserver.php +++ b/Observer/AddAlgoliaAssetsObserver.php @@ -4,15 +4,13 @@ use Algolia\AlgoliaSearch\Exceptions\AlgoliaException; use Algolia\AlgoliaSearch\Helper\ConfigHelper; -use Algolia\AlgoliaSearch\Registry\CurrentCategory; use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager; -use Magento\Catalog\Model\Category; +use Algolia\AlgoliaSearch\Service\RenderingManager; use Magento\Framework\App\Request\Http; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\View\Layout; -use Magento\Framework\View\Page\Config as PageConfig; use Magento\Store\Model\StoreManagerInterface; /** @@ -22,13 +20,11 @@ class AddAlgoliaAssetsObserver implements ObserverInterface { public function __construct( protected ConfigHelper $config, - protected CurrentCategory $category, + protected RenderingManager $renderingManager, protected StoreManagerInterface $storeManager, - protected PageConfig $pageConfig, protected Http $request, protected AlgoliaCredentialsManager $algoliaCredentialsManager - ) - {} + ) {} /** * @throws NoSuchEntityException|AlgoliaException @@ -39,42 +35,16 @@ public function execute(Observer $observer): void if ($actionName === 'swagger_index_index') { return; } - $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, $storeId); - } - } - } - } - - private function loadPreventBackendRenderingHandle(Layout $layout, int $storeId): void - { - if (!$this->config->preventBackendRendering($storeId)) { - return; - } - - $category = $this->category->get(); - if (!$category->getId()) { - return; - } + $storeId = $this->storeManager->getStore()->getId(); - if (!$this->config->replaceCategories($storeId)) { - return; - } + if ($this->config->isEnabledFrontEnd($storeId) && $this->algoliaCredentialsManager->checkCredentials($storeId)) { + /** @var Layout $layout */ + $layout = $observer->getData('layout'); - $displayMode = $this->config->getBackendRenderingDisplayMode($storeId); - if ($displayMode === 'only_products' - && $category->getData('display_mode') === \Magento\Catalog\Model\Category::DM_PAGE) { - return; + $this->renderingManager->handleFrontendAssets($layout, $storeId); + $this->renderingManager->handleBackendRendering($layout, $actionName, $storeId); } - - $layout->getUpdate()->addHandle('algolia_search_handle_prevent_backend_rendering'); } + } diff --git a/Service/RenderingManager.php b/Service/RenderingManager.php new file mode 100644 index 000000000..67a6d3e77 --- /dev/null +++ b/Service/RenderingManager.php @@ -0,0 +1,87 @@ +hasAlgoliaFrontend($storeId)) { + return; + } + + $layout->getUpdate()->addHandle('algolia_search_handle'); + } + + /** + * @param Layout $layout + * @param string $actionName + * @param int $storeId + * @return void + */ + public function handleBackendRendering(Layout $layout, string $actionName, int $storeId): void + { + // If the page is not a category or the catalogsearch page or if no Algolia frontend feature is enabled, no need to go further + if (!$this->isSearchPage($actionName) || !$this->hasAlgoliaFrontend($storeId)) { + return; + } + + // @todo replace this check with the new backend rendering feature (MAGE-1325) + if (!$this->config->preventBackendRendering($storeId)) { + return; + } + + $category = $this->category->get(); + // Legacy check regarding category display mode (we don't want to hide the static blocks if there's not product list + if ($category->getId() && $this->instantSearchConfigHelper->shouldReplaceCategories($storeId)) { + $displayMode = $this->config->getBackendRenderingDisplayMode($storeId); + + if ($displayMode === 'only_products' && $category->getData('display_mode') === Category::DM_PAGE) { + return; + } + } + + $layout->getUpdate()->addHandle('algolia_search_handle_prevent_backend_rendering'); + } + + /** + * @param int $storeId + * @return bool + */ + protected function hasAlgoliaFrontend(int $storeId): bool + { + return $this->autocompleteConfigHelper->isEnabled($storeId) || + $this->instantSearchConfigHelper->isEnabled($storeId); + } + + /** + * @param string $actionName + * @return bool + */ + protected function isSearchPage(string $actionName): bool + { + return $actionName === 'catalog_category_view' || $actionName === 'catalogsearch_result_index'; + } +} From 3cb7c222eddccca9b61891e4d6ea32f9f82c0f1e Mon Sep 17 00:00:00 2001 From: Damien Couchez Date: Tue, 7 Oct 2025 15:57:48 +0200 Subject: [PATCH 2/2] MAGE-1326: add unit tests --- Service/RenderingManager.php | 16 ++- Test/Unit/Service/RenderingManagerTest.php | 155 +++++++++++++++++++++ 2 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 Test/Unit/Service/RenderingManagerTest.php diff --git a/Service/RenderingManager.php b/Service/RenderingManager.php index 67a6d3e77..a2b304040 100644 --- a/Service/RenderingManager.php +++ b/Service/RenderingManager.php @@ -32,7 +32,7 @@ public function handleFrontendAssets(Layout $layout, int $storeId): void return; } - $layout->getUpdate()->addHandle('algolia_search_handle'); + $this->addHandle($layout,'algolia_search_handle'); } /** @@ -58,12 +58,22 @@ public function handleBackendRendering(Layout $layout, string $actionName, int $ if ($category->getId() && $this->instantSearchConfigHelper->shouldReplaceCategories($storeId)) { $displayMode = $this->config->getBackendRenderingDisplayMode($storeId); - if ($displayMode === 'only_products' && $category->getData('display_mode') === Category::DM_PAGE) { + if ($displayMode === 'only_products' && $category->getDisplayMode() === Category::DM_PAGE) { return; } } - $layout->getUpdate()->addHandle('algolia_search_handle_prevent_backend_rendering'); + $this->addHandle($layout, 'algolia_search_handle_prevent_backend_rendering'); + } + + /** + * @param Layout $layout + * @param string $handleName + * @return void + */ + protected function addHandle(Layout $layout, string $handleName): void + { + $layout->getUpdate()->addHandle($handleName); } /** diff --git a/Test/Unit/Service/RenderingManagerTest.php b/Test/Unit/Service/RenderingManagerTest.php new file mode 100644 index 000000000..3443d479d --- /dev/null +++ b/Test/Unit/Service/RenderingManagerTest.php @@ -0,0 +1,155 @@ +configHelper = $this->createMock(ConfigHelper::class); + $this->autocompleteConfigHelper = $this->createMock(AutocompleteHelper::class); + $this->instantSearchConfigHelper = $this->createMock(InstantSearchHelper::class); + $this->category = $this->createMock(CurrentCategory::class); + $this->storeManager = $this->createMock(StoreManagerInterface::class); + + $this->renderingManager = new RenderingManager( + $this->configHelper, + $this->autocompleteConfigHelper, + $this->instantSearchConfigHelper, + $this->category, + $this->storeManager + ); + } + + /** + * @dataProvider frontendValuesProvider + */ + public function testFrontendAssets($isAutocompleteEnabled, $isInstantSearchEnabled, $isLayoutUpdated): void + { + $this->autocompleteConfigHelper->method('isEnabled')->willReturn($isAutocompleteEnabled); + $this->instantSearchConfigHelper->method('isEnabled')->willReturn($isInstantSearchEnabled); + + $layout = $this->createMock(Layout::class); + $update = $this->createMock(ProcessorInterface::class); + $layout->method('getUpdate')->willReturn($update); + + if ($isLayoutUpdated) { + $update->expects($this->once()) + ->method('addHandle') + ->with('algolia_search_handle'); + } else { + $update->expects($this->never()) + ->method('addHandle'); + } + + $this->renderingManager->handleFrontendAssets($layout, 0); + } + + /** + * @dataProvider backendValuesProvider + */ + public function testBackendRendering($actionName, $preventBackendRendering, $isLayoutUpdated): void + { + $this->autocompleteConfigHelper->method('isEnabled')->willReturn(true); + $this->instantSearchConfigHelper->method('isEnabled')->willReturn(true); + $this->configHelper->method('preventBackendRendering')->willReturn($preventBackendRendering); + + $layout = $this->createMock(Layout::class); + $update = $this->createMock(ProcessorInterface::class); + $layout->method('getUpdate')->willReturn($update); + + if ($isLayoutUpdated) { + $update->expects($this->once()) + ->method('addHandle') + ->with('algolia_search_handle_prevent_backend_rendering'); + } else { + $update->expects($this->never()) + ->method('addHandle'); + } + + $this->renderingManager->handleBackendRendering($layout, $actionName, 0); + } + + /** + * @dataProvider displayValuesProvider + */ + public function testDisplayMode($displayMode, $categoryDisplayMode, $isLayoutUpdated): void + { + $this->autocompleteConfigHelper->method('isEnabled')->willReturn(true); + $this->instantSearchConfigHelper->method('isEnabled')->willReturn(true); + $this->instantSearchConfigHelper->method('shouldReplaceCategories')->willReturn(true); + $this->configHelper->method('preventBackendRendering')->willReturn(true); + $this->configHelper->method('getBackendRenderingDisplayMode')->willReturn($displayMode); + + $currentCategory = $this->createMock(Category::class); + $this->category->method('get')->willReturn($currentCategory); + $currentCategory->method('getId')->willReturn(1); + $currentCategory->method('getDisplayMode')->willReturn($categoryDisplayMode); + + $layout = $this->createMock(Layout::class); + $update = $this->createMock(ProcessorInterface::class); + $layout->method('getUpdate')->willReturn($update); + + if ($isLayoutUpdated) { + $update->expects($this->once()) + ->method('addHandle') + ->with('algolia_search_handle_prevent_backend_rendering'); + } else { + $update->expects($this->never()) + ->method('addHandle'); + } + + $this->renderingManager->handleBackendRendering($layout, 'catalog_category_view', 0); + } + + public static function frontendValuesProvider(): array + { + return [ + ['isAutocompleteEnabled' => true, 'isInstantSearchEnabled' => true, 'isLayoutUpdated' => true], + ['isAutocompleteEnabled' => false, 'isInstantSearchEnabled' => true, 'isLayoutUpdated' => true], + ['isAutocompleteEnabled' => true, 'isInstantSearchEnabled' => false, 'isLayoutUpdated' => true], + ['isAutocompleteEnabled' => false, 'isInstantSearchEnabled' => false, 'isLayoutUpdated' => false] + ]; + } + + public static function backendValuesProvider(): array + { + return [ + ['actionName' => 'catalog_category_view','preventBackendRendering' => true, 'isLayoutUpdated' => true], + ['actionName' => 'catalogsearch_result_index', 'preventBackendRendering' => true, 'isLayoutUpdated' => true], + ['actionName' => 'foo_bar', 'preventBackendRendering' => true, 'isLayoutUpdated' => false], + ['actionName' => 'catalog_category_view', 'preventBackendRendering' => false, 'isLayoutUpdated' => false] + ]; + } + + public static function displayValuesProvider(): array + { + return [ + ['displayMode' => 'all', 'categoryDisplayMode' => 'PAGE', 'isLayoutUpdated' => true], + ['displayMode' => 'all', 'categoryDisplayMode' => 'PRODUCTS', 'isLayoutUpdated' => true], + ['displayMode' => 'all', 'categoryDisplayMode' => 'PRODUCTS_AND_PAGE', 'isLayoutUpdated' => true], + ['displayMode' => 'only_products', 'categoryDisplayMode' => 'PAGE', 'isLayoutUpdated' => false], + ['displayMode' => 'only_products', 'categoryDisplayMode' => 'PRODUCTS', 'isLayoutUpdated' => true], + ['displayMode' => 'only_products', 'categoryDisplayMode' => 'PRODUCTS_AND_PAGE', 'isLayoutUpdated' => true], + ]; + } +}