Skip to content

Commit 06cb7ca

Browse files
MC-22739: Layered Navigation with different Scope for attribute
1 parent 08fd66d commit 06cb7ca

File tree

4 files changed

+226
-22
lines changed

4 files changed

+226
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Store\Api\WebsiteRepositoryInterface;
10+
use Magento\TestFramework\Helper\Bootstrap;
11+
12+
require __DIR__ . '/category_with_different_price_products.php';
13+
require __DIR__ . '/../../Store/_files/second_website_with_two_stores.php';
14+
15+
$objectManager = Bootstrap::getObjectManager();
16+
/** @var ProductRepositoryInterface $productRepository */
17+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
18+
/** @var WebsiteRepositoryInterface $websiteRepository */
19+
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
20+
$defaultWebsiteId = $websiteRepository->get('base')->getId();
21+
$websiteId = $websiteRepository->get('test')->getId();
22+
23+
$product = $productRepository->get('simple1000');
24+
$product->setWebsiteIds([$defaultWebsiteId, $websiteId]);
25+
$productRepository->save($product);
26+
27+
$product = $productRepository->get('simple1001');
28+
$product->setWebsiteIds([$defaultWebsiteId, $websiteId]);
29+
$productRepository->save($product);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
require __DIR__ . '/category_with_different_price_products_rollback.php';
9+
require __DIR__ . '/../../Store/_files/second_website_with_two_stores_rollback.php';
10+

dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/AbstractFiltersTest.php

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,9 @@ protected function setUp()
7474
$this->objectManager = Bootstrap::getObjectManager();
7575
$this->categoryCollectionFactory = $this->objectManager->create(CollectionFactory::class);
7676
$this->layout = $this->objectManager->get(LayoutInterface::class);
77-
$layerResolver = $this->objectManager->create(Resolver::class);
78-
79-
if ($this->getLayerType() === Resolver::CATALOG_LAYER_SEARCH) {
80-
$layerResolver->create(Resolver::CATALOG_LAYER_SEARCH);
81-
$this->navigationBlock = $this->objectManager->create(
82-
SearchNavigationBlock::class,
83-
[
84-
'layerResolver' => $layerResolver,
85-
]
86-
);
87-
} else {
88-
$this->navigationBlock = $this->objectManager->create(CategoryNavigationBlock::class);
89-
}
90-
9177
$this->attributeRepository = $this->objectManager->create(ProductAttributeRepositoryInterface::class);
9278
$this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class);
79+
$this->createNavigationBlockInstance();
9380
}
9481

9582
/**
@@ -121,7 +108,7 @@ protected function getCategoryFiltersAndAssert(
121108
array $expectation,
122109
string $categoryName
123110
): void {
124-
$this->updateAttribute($this->getAttributeCode(), $attributeData);
111+
$this->updateAttribute($attributeData);
125112
$this->updateProducts($products, $this->getAttributeCode());
126113
$this->clearInstanceAndReindexSearch();
127114
$category = $this->loadCategory($categoryName, Store::DEFAULT_STORE_ID);
@@ -150,7 +137,7 @@ protected function getSearchFiltersAndAssert(
150137
array $attributeData,
151138
array $expectation
152139
): void {
153-
$this->updateAttribute($this->getAttributeCode(), $attributeData);
140+
$this->updateAttribute($attributeData);
154141
$this->updateProducts($products, $this->getAttributeCode());
155142
$this->clearInstanceAndReindexSearch();
156143
$this->navigationBlock->getRequest()->setParams(['q' => 'Simple Product']);
@@ -188,15 +175,13 @@ function (AbstractFilter $filter) use ($code) {
188175
/**
189176
* Updates attribute data.
190177
*
191-
* @param string $attributeCode
192178
* @param array $data
193179
* @return void
194180
*/
195181
protected function updateAttribute(
196-
string $attributeCode,
197182
array $data
198183
): void {
199-
$attribute = $this->attributeRepository->get($attributeCode);
184+
$attribute = $this->attributeRepository->get($this->getAttributeCode());
200185
$attribute->addData($data);
201186
$this->attributeRepository->save($attribute);
202187
}
@@ -226,14 +211,18 @@ protected function prepareFilterItems(AbstractFilter $filter): array
226211
*
227212
* @param array $products
228213
* @param string $attributeCode
214+
* @param int $storeId
229215
* @return void
230216
*/
231-
protected function updateProducts(array $products, string $attributeCode): void
232-
{
217+
protected function updateProducts(
218+
array $products,
219+
string $attributeCode,
220+
int $storeId = Store::DEFAULT_STORE_ID
221+
): void {
233222
$attribute = $this->attributeRepository->get($attributeCode);
234223

235224
foreach ($products as $productSku => $stringValue) {
236-
$product = $this->productRepository->get($productSku, false, Store::DEFAULT_STORE_ID, true);
225+
$product = $this->productRepository->get($productSku, false, $storeId, true);
237226
$product->addData(
238227
[$attribute->getAttributeCode() => $attribute->getSource()->getOptionId($stringValue)]
239228
);
@@ -275,4 +264,26 @@ protected function loadCategory(string $categoryName, int $storeId): CategoryInt
275264

276265
return $category;
277266
}
267+
268+
/**
269+
* Creates navigation block instance.
270+
*
271+
* @return void
272+
*/
273+
protected function createNavigationBlockInstance(): void
274+
{
275+
$layerResolver = $this->objectManager->create(Resolver::class);
276+
277+
if ($this->getLayerType() === Resolver::CATALOG_LAYER_SEARCH) {
278+
$layerResolver->create(Resolver::CATALOG_LAYER_SEARCH);
279+
$this->navigationBlock = $this->objectManager->create(
280+
SearchNavigationBlock::class,
281+
[
282+
'layerResolver' => $layerResolver,
283+
]
284+
);
285+
} else {
286+
$this->navigationBlock = $this->objectManager->create(CategoryNavigationBlock::class);
287+
}
288+
}
278289
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\LayeredNavigation\Block\Navigation\Category;
9+
10+
use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
11+
use Magento\Catalog\Model\Layer\Resolver;
12+
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
13+
use Magento\LayeredNavigation\Block\Navigation\AbstractFiltersTest;
14+
use Magento\Store\Model\StoreManagerInterface;
15+
16+
/**
17+
* Provides tests for custom filter with different scopes in navigation block on category page.
18+
*
19+
* @magentoAppArea frontend
20+
* @magentoAppIsolation enabled
21+
* @magentoDbIsolation disabled
22+
*/
23+
class FilterScopeTest extends AbstractFiltersTest
24+
{
25+
/**
26+
* @var StoreManagerInterface
27+
*/
28+
private $storeManager;
29+
30+
/**
31+
* @var int
32+
*/
33+
private $oldStoreId;
34+
35+
/**
36+
* @var int
37+
*/
38+
private $currentStoreId;
39+
40+
/**
41+
* @inheritdoc
42+
*/
43+
protected function setUp()
44+
{
45+
parent::setUp();
46+
$this->storeManager = $this->objectManager->create(StoreManagerInterface::class);
47+
$this->oldStoreId = (int)$this->storeManager->getStore()->getId();
48+
$this->currentStoreId = (int)$this->storeManager->getStore('fixture_second_store')->getId();
49+
}
50+
51+
/**
52+
* @magentoDataFixture Magento/Catalog/_files/product_dropdown_attribute.php
53+
* @magentoDataFixture Magento/Catalog/_files/category_with_different_price_products_on_two_websites.php
54+
* @dataProvider filtersWithScopeDataProvider
55+
* @param int $scope
56+
* @param array $products
57+
* @param array $expectation
58+
* @return void
59+
*/
60+
public function testGetFilters(int $scope, array $products, array $expectation): void
61+
{
62+
$this->updateAttribute(
63+
[
64+
'is_filterable' => AbstractFilter::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS,
65+
'is_global' => $scope,
66+
]
67+
);
68+
$this->updateProductsOnStore($products);
69+
$this->clearInstanceAndReindexSearch();
70+
$this->storeManager->setCurrentStore($this->currentStoreId);
71+
$this->navigationBlock->getLayer()->setCurrentCategory(
72+
$this->loadCategory('Category 999', $this->currentStoreId)
73+
);
74+
$this->navigationBlock->setLayout($this->layout);
75+
$filter = $this->getFilterByCode($this->navigationBlock->getFilters(), $this->getAttributeCode());
76+
$this->assertNotNull($filter);
77+
$this->assertEquals($expectation, $this->prepareFilterItems($filter));
78+
$this->storeManager->setCurrentStore($this->oldStoreId);
79+
}
80+
81+
/**
82+
* @return array
83+
*/
84+
public function filtersWithScopeDataProvider(): array
85+
{
86+
return [
87+
'with_scope_store' => [
88+
'scope' => ScopedAttributeInterface::SCOPE_STORE,
89+
'products' => [
90+
'default' => ['simple1000' => 'Option 1', 'simple1001' => 'Option 2'],
91+
'fixture_second_store' => ['simple1000' => 'Option 2', 'simple1001' => 'Option 3'],
92+
],
93+
'expectation' => [
94+
['label' => 'Option 2', 'count' => 1],
95+
['label' => 'Option 3', 'count' => 1],
96+
],
97+
],
98+
'with_scope_website' => [
99+
'scope' => ScopedAttributeInterface::SCOPE_WEBSITE,
100+
'products' => [
101+
'default' => ['simple1000' => 'Option 3', 'simple1001' => 'Option 2'],
102+
'fixture_second_store' => ['simple1000' => 'Option 1', 'simple1001' => 'Option 2'],
103+
],
104+
'expectation' => [
105+
['label' => 'Option 1', 'count' => 1],
106+
['label' => 'Option 2', 'count' => 1],
107+
],
108+
],
109+
'with_scope_global' => [
110+
'scope' => ScopedAttributeInterface::SCOPE_GLOBAL,
111+
'products' => [
112+
'default' => ['simple1000' => 'Option 1'],
113+
'fixture_second_store' => ['simple1001' => 'Option 2'],
114+
],
115+
'expectation' => [
116+
['label' => 'Option 1', 'count' => 1],
117+
['label' => 'Option 2', 'count' => 1],
118+
],
119+
],
120+
];
121+
}
122+
123+
/**
124+
* @inheritdoc
125+
*/
126+
protected function getLayerType(): string
127+
{
128+
return Resolver::CATALOG_LAYER_CATEGORY;
129+
}
130+
131+
/**
132+
* @inheritdoc
133+
*/
134+
protected function getAttributeCode(): string
135+
{
136+
return 'dropdown_attribute';
137+
}
138+
139+
/**
140+
* Updates products data for store.
141+
*
142+
* @param array $productsData
143+
* @return void
144+
*/
145+
private function updateProductsOnStore(array $productsData): void
146+
{
147+
foreach ($productsData as $storeCode => $products) {
148+
$storeId = (int)$this->storeManager->getStore($storeCode)->getId();
149+
$this->storeManager->setCurrentStore($storeId);
150+
$this->updateProducts($products, $this->getAttributeCode(), $storeId);
151+
}
152+
$this->storeManager->setCurrentStore($this->oldStoreId);
153+
}
154+
}

0 commit comments

Comments
 (0)