Skip to content

Commit 04562fb

Browse files
authored
Merge pull request #1844 from algolia/feat/MAGE-1326-prevent-backend-rendering
MAGE-1236: Add Backend Rendering Manager
2 parents 4fe2979 + 3cb7c22 commit 04562fb

File tree

3 files changed

+262
-40
lines changed

3 files changed

+262
-40
lines changed

Observer/AddAlgoliaAssetsObserver.php

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44

55
use Algolia\AlgoliaSearch\Exceptions\AlgoliaException;
66
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
7-
use Algolia\AlgoliaSearch\Registry\CurrentCategory;
87
use Algolia\AlgoliaSearch\Service\AlgoliaCredentialsManager;
9-
use Magento\Catalog\Model\Category;
8+
use Algolia\AlgoliaSearch\Service\RenderingManager;
109
use Magento\Framework\App\Request\Http;
1110
use Magento\Framework\Event\Observer;
1211
use Magento\Framework\Event\ObserverInterface;
1312
use Magento\Framework\Exception\NoSuchEntityException;
1413
use Magento\Framework\View\Layout;
15-
use Magento\Framework\View\Page\Config as PageConfig;
1614
use Magento\Store\Model\StoreManagerInterface;
1715

1816
/**
@@ -22,13 +20,11 @@ class AddAlgoliaAssetsObserver implements ObserverInterface
2220
{
2321
public function __construct(
2422
protected ConfigHelper $config,
25-
protected CurrentCategory $category,
23+
protected RenderingManager $renderingManager,
2624
protected StoreManagerInterface $storeManager,
27-
protected PageConfig $pageConfig,
2825
protected Http $request,
2926
protected AlgoliaCredentialsManager $algoliaCredentialsManager
30-
)
31-
{}
27+
) {}
3228

3329
/**
3430
* @throws NoSuchEntityException|AlgoliaException
@@ -39,42 +35,16 @@ public function execute(Observer $observer): void
3935
if ($actionName === 'swagger_index_index') {
4036
return;
4137
}
42-
$storeId = $this->storeManager->getStore()->getId();
43-
if ($this->config->isEnabledFrontEnd($storeId)) {
44-
if ($this->algoliaCredentialsManager->checkCredentials($storeId)) {
45-
if ($this->config->isAutoCompleteEnabled($storeId) || $this->config->isInstantEnabled($storeId)) {
46-
/** @var Layout $layout */
47-
$layout = $observer->getData('layout');
48-
$layout->getUpdate()->addHandle('algolia_search_handle');
49-
50-
$this->loadPreventBackendRenderingHandle($layout, $storeId);
51-
}
52-
}
53-
}
54-
}
55-
56-
private function loadPreventBackendRenderingHandle(Layout $layout, int $storeId): void
57-
{
58-
if (!$this->config->preventBackendRendering($storeId)) {
59-
return;
60-
}
61-
62-
$category = $this->category->get();
6338

64-
if (!$category->getId()) {
65-
return;
66-
}
39+
$storeId = $this->storeManager->getStore()->getId();
6740

68-
if (!$this->config->replaceCategories($storeId)) {
69-
return;
70-
}
41+
if ($this->config->isEnabledFrontEnd($storeId) && $this->algoliaCredentialsManager->checkCredentials($storeId)) {
42+
/** @var Layout $layout */
43+
$layout = $observer->getData('layout');
7144

72-
$displayMode = $this->config->getBackendRenderingDisplayMode($storeId);
73-
if ($displayMode === 'only_products'
74-
&& $category->getData('display_mode') === \Magento\Catalog\Model\Category::DM_PAGE) {
75-
return;
45+
$this->renderingManager->handleFrontendAssets($layout, $storeId);
46+
$this->renderingManager->handleBackendRendering($layout, $actionName, $storeId);
7647
}
77-
78-
$layout->getUpdate()->addHandle('algolia_search_handle_prevent_backend_rendering');
7948
}
49+
8050
}

Service/RenderingManager.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Service;
4+
5+
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
6+
use Algolia\AlgoliaSearch\Helper\Configuration\AutocompleteHelper;
7+
use Algolia\AlgoliaSearch\Helper\Configuration\InstantSearchHelper;
8+
use Algolia\AlgoliaSearch\Registry\CurrentCategory;
9+
use Magento\Catalog\Model\Category;
10+
use Magento\Framework\View\Layout;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
13+
class RenderingManager
14+
{
15+
public function __construct(
16+
protected ConfigHelper $config,
17+
protected AutocompleteHelper $autocompleteConfigHelper,
18+
protected InstantSearchHelper $instantSearchConfigHelper,
19+
protected CurrentCategory $category,
20+
protected StoreManagerInterface $storeManager
21+
) {}
22+
23+
/**
24+
* @param Layout $layout
25+
* @param int $storeId
26+
* @return void
27+
*/
28+
public function handleFrontendAssets(Layout $layout, int $storeId): void
29+
{
30+
// If an Algolia frontend feature is enabled, add the frontend assets
31+
if (!$this->hasAlgoliaFrontend($storeId)) {
32+
return;
33+
}
34+
35+
$this->addHandle($layout,'algolia_search_handle');
36+
}
37+
38+
/**
39+
* @param Layout $layout
40+
* @param string $actionName
41+
* @param int $storeId
42+
* @return void
43+
*/
44+
public function handleBackendRendering(Layout $layout, string $actionName, int $storeId): void
45+
{
46+
// If the page is not a category or the catalogsearch page or if no Algolia frontend feature is enabled, no need to go further
47+
if (!$this->isSearchPage($actionName) || !$this->hasAlgoliaFrontend($storeId)) {
48+
return;
49+
}
50+
51+
// @todo replace this check with the new backend rendering feature (MAGE-1325)
52+
if (!$this->config->preventBackendRendering($storeId)) {
53+
return;
54+
}
55+
56+
$category = $this->category->get();
57+
// Legacy check regarding category display mode (we don't want to hide the static blocks if there's not product list
58+
if ($category->getId() && $this->instantSearchConfigHelper->shouldReplaceCategories($storeId)) {
59+
$displayMode = $this->config->getBackendRenderingDisplayMode($storeId);
60+
61+
if ($displayMode === 'only_products' && $category->getDisplayMode() === Category::DM_PAGE) {
62+
return;
63+
}
64+
}
65+
66+
$this->addHandle($layout, 'algolia_search_handle_prevent_backend_rendering');
67+
}
68+
69+
/**
70+
* @param Layout $layout
71+
* @param string $handleName
72+
* @return void
73+
*/
74+
protected function addHandle(Layout $layout, string $handleName): void
75+
{
76+
$layout->getUpdate()->addHandle($handleName);
77+
}
78+
79+
/**
80+
* @param int $storeId
81+
* @return bool
82+
*/
83+
protected function hasAlgoliaFrontend(int $storeId): bool
84+
{
85+
return $this->autocompleteConfigHelper->isEnabled($storeId) ||
86+
$this->instantSearchConfigHelper->isEnabled($storeId);
87+
}
88+
89+
/**
90+
* @param string $actionName
91+
* @return bool
92+
*/
93+
protected function isSearchPage(string $actionName): bool
94+
{
95+
return $actionName === 'catalog_category_view' || $actionName === 'catalogsearch_result_index';
96+
}
97+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Test\Unit\Service;
4+
5+
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
6+
use Algolia\AlgoliaSearch\Helper\Configuration\AutocompleteHelper;
7+
use Algolia\AlgoliaSearch\Helper\Configuration\InstantSearchHelper;
8+
use Algolia\AlgoliaSearch\Registry\CurrentCategory;
9+
use Algolia\AlgoliaSearch\Service\RenderingManager;
10+
use Magento\Catalog\Model\Category;
11+
use Magento\Framework\View\Layout;
12+
use Magento\Framework\View\Layout\ProcessorInterface;
13+
use Magento\Store\Model\StoreManagerInterface;
14+
use PHPUnit\Framework\TestCase;
15+
16+
class RenderingManagerTest extends TestCase
17+
{
18+
protected ?ConfigHelper $configHelper;
19+
protected ?AutocompleteHelper $autocompleteConfigHelper;
20+
protected ?InstantSearchHelper $instantSearchConfigHelper;
21+
protected ?CurrentCategory $category;
22+
protected ?StoreManagerInterface $storeManager;
23+
24+
protected ?RenderingManager $renderingManager;
25+
26+
public function setUp(): void
27+
{
28+
$this->configHelper = $this->createMock(ConfigHelper::class);
29+
$this->autocompleteConfigHelper = $this->createMock(AutocompleteHelper::class);
30+
$this->instantSearchConfigHelper = $this->createMock(InstantSearchHelper::class);
31+
$this->category = $this->createMock(CurrentCategory::class);
32+
$this->storeManager = $this->createMock(StoreManagerInterface::class);
33+
34+
$this->renderingManager = new RenderingManager(
35+
$this->configHelper,
36+
$this->autocompleteConfigHelper,
37+
$this->instantSearchConfigHelper,
38+
$this->category,
39+
$this->storeManager
40+
);
41+
}
42+
43+
/**
44+
* @dataProvider frontendValuesProvider
45+
*/
46+
public function testFrontendAssets($isAutocompleteEnabled, $isInstantSearchEnabled, $isLayoutUpdated): void
47+
{
48+
$this->autocompleteConfigHelper->method('isEnabled')->willReturn($isAutocompleteEnabled);
49+
$this->instantSearchConfigHelper->method('isEnabled')->willReturn($isInstantSearchEnabled);
50+
51+
$layout = $this->createMock(Layout::class);
52+
$update = $this->createMock(ProcessorInterface::class);
53+
$layout->method('getUpdate')->willReturn($update);
54+
55+
if ($isLayoutUpdated) {
56+
$update->expects($this->once())
57+
->method('addHandle')
58+
->with('algolia_search_handle');
59+
} else {
60+
$update->expects($this->never())
61+
->method('addHandle');
62+
}
63+
64+
$this->renderingManager->handleFrontendAssets($layout, 0);
65+
}
66+
67+
/**
68+
* @dataProvider backendValuesProvider
69+
*/
70+
public function testBackendRendering($actionName, $preventBackendRendering, $isLayoutUpdated): void
71+
{
72+
$this->autocompleteConfigHelper->method('isEnabled')->willReturn(true);
73+
$this->instantSearchConfigHelper->method('isEnabled')->willReturn(true);
74+
$this->configHelper->method('preventBackendRendering')->willReturn($preventBackendRendering);
75+
76+
$layout = $this->createMock(Layout::class);
77+
$update = $this->createMock(ProcessorInterface::class);
78+
$layout->method('getUpdate')->willReturn($update);
79+
80+
if ($isLayoutUpdated) {
81+
$update->expects($this->once())
82+
->method('addHandle')
83+
->with('algolia_search_handle_prevent_backend_rendering');
84+
} else {
85+
$update->expects($this->never())
86+
->method('addHandle');
87+
}
88+
89+
$this->renderingManager->handleBackendRendering($layout, $actionName, 0);
90+
}
91+
92+
/**
93+
* @dataProvider displayValuesProvider
94+
*/
95+
public function testDisplayMode($displayMode, $categoryDisplayMode, $isLayoutUpdated): void
96+
{
97+
$this->autocompleteConfigHelper->method('isEnabled')->willReturn(true);
98+
$this->instantSearchConfigHelper->method('isEnabled')->willReturn(true);
99+
$this->instantSearchConfigHelper->method('shouldReplaceCategories')->willReturn(true);
100+
$this->configHelper->method('preventBackendRendering')->willReturn(true);
101+
$this->configHelper->method('getBackendRenderingDisplayMode')->willReturn($displayMode);
102+
103+
$currentCategory = $this->createMock(Category::class);
104+
$this->category->method('get')->willReturn($currentCategory);
105+
$currentCategory->method('getId')->willReturn(1);
106+
$currentCategory->method('getDisplayMode')->willReturn($categoryDisplayMode);
107+
108+
$layout = $this->createMock(Layout::class);
109+
$update = $this->createMock(ProcessorInterface::class);
110+
$layout->method('getUpdate')->willReturn($update);
111+
112+
if ($isLayoutUpdated) {
113+
$update->expects($this->once())
114+
->method('addHandle')
115+
->with('algolia_search_handle_prevent_backend_rendering');
116+
} else {
117+
$update->expects($this->never())
118+
->method('addHandle');
119+
}
120+
121+
$this->renderingManager->handleBackendRendering($layout, 'catalog_category_view', 0);
122+
}
123+
124+
public static function frontendValuesProvider(): array
125+
{
126+
return [
127+
['isAutocompleteEnabled' => true, 'isInstantSearchEnabled' => true, 'isLayoutUpdated' => true],
128+
['isAutocompleteEnabled' => false, 'isInstantSearchEnabled' => true, 'isLayoutUpdated' => true],
129+
['isAutocompleteEnabled' => true, 'isInstantSearchEnabled' => false, 'isLayoutUpdated' => true],
130+
['isAutocompleteEnabled' => false, 'isInstantSearchEnabled' => false, 'isLayoutUpdated' => false]
131+
];
132+
}
133+
134+
public static function backendValuesProvider(): array
135+
{
136+
return [
137+
['actionName' => 'catalog_category_view','preventBackendRendering' => true, 'isLayoutUpdated' => true],
138+
['actionName' => 'catalogsearch_result_index', 'preventBackendRendering' => true, 'isLayoutUpdated' => true],
139+
['actionName' => 'foo_bar', 'preventBackendRendering' => true, 'isLayoutUpdated' => false],
140+
['actionName' => 'catalog_category_view', 'preventBackendRendering' => false, 'isLayoutUpdated' => false]
141+
];
142+
}
143+
144+
public static function displayValuesProvider(): array
145+
{
146+
return [
147+
['displayMode' => 'all', 'categoryDisplayMode' => 'PAGE', 'isLayoutUpdated' => true],
148+
['displayMode' => 'all', 'categoryDisplayMode' => 'PRODUCTS', 'isLayoutUpdated' => true],
149+
['displayMode' => 'all', 'categoryDisplayMode' => 'PRODUCTS_AND_PAGE', 'isLayoutUpdated' => true],
150+
['displayMode' => 'only_products', 'categoryDisplayMode' => 'PAGE', 'isLayoutUpdated' => false],
151+
['displayMode' => 'only_products', 'categoryDisplayMode' => 'PRODUCTS', 'isLayoutUpdated' => true],
152+
['displayMode' => 'only_products', 'categoryDisplayMode' => 'PRODUCTS_AND_PAGE', 'isLayoutUpdated' => true],
153+
];
154+
}
155+
}

0 commit comments

Comments
 (0)