Skip to content

Commit e49a100

Browse files
committed
Merge remote-tracking branch '2515/31253_default_store_breadcrumbs_returned_for_products_which_in_both_root_categories' into BUG#AC2515
2 parents d74bbf7 + 95f9e7a commit e49a100

File tree

4 files changed

+224
-6
lines changed

4 files changed

+224
-6
lines changed

app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Magento\Framework\DB\Query\Generator as QueryGenerator;
1414
use Magento\Framework\DB\Select;
1515
use Magento\Framework\EntityManager\MetadataPool;
16+
use Magento\Store\Api\Data\StoreInterface;
1617
use Magento\Store\Model\Store;
1718

1819
// phpcs:disable Magento2.Classes.AbstractApi
@@ -126,9 +127,9 @@ abstract class AbstractAction
126127
private $queryGenerator;
127128

128129
/**
129-
* @var int
130+
* @var StoreInterface
130131
*/
131-
private $currentStoreId = 0;
132+
private $currentStore;
132133

133134
/**
134135
* @param ResourceConnection $resource
@@ -171,14 +172,36 @@ protected function reindex()
171172
{
172173
foreach ($this->storeManager->getStores() as $store) {
173174
if ($this->getPathFromCategoryId($store->getRootCategoryId())) {
174-
$this->currentStoreId = $store->getId();
175+
$this->setCurrentStore($store);
175176
$this->reindexRootCategory($store);
176177
$this->reindexAnchorCategories($store);
177178
$this->reindexNonAnchorCategories($store);
178179
}
179180
}
180181
}
181182

183+
/**
184+
* Set current store
185+
*
186+
* @param StoreInterface $store
187+
* @return $this
188+
*/
189+
private function setCurrentStore(StoreInterface $store): self
190+
{
191+
$this->currentStore = $store;
192+
return $this;
193+
}
194+
195+
/**
196+
* Get current store
197+
*
198+
* @return StoreInterface
199+
*/
200+
private function getCurrentStore(): StoreInterface
201+
{
202+
return $this->currentStore;
203+
}
204+
182205
/**
183206
* Return validated table name
184207
*
@@ -484,6 +507,7 @@ protected function hasAnchorSelect(Store $store)
484507
*/
485508
protected function createAnchorSelect(Store $store)
486509
{
510+
$this->setCurrentStore($store);
487511
$isAnchorAttributeId = $this->config->getAttribute(
488512
\Magento\Catalog\Model\Category::ENTITY,
489513
'is_anchor'
@@ -690,7 +714,7 @@ protected function fillTempCategoryTreeIndex($temporaryName)
690714
['ccacs' => $this->getTable('catalog_category_entity_int')],
691715
'ccacs.' . $categoryLinkField . ' = c.' . $categoryLinkField
692716
. ' AND ccacs.attribute_id = ccacd.attribute_id AND ccacs.store_id = ' .
693-
$this->currentStoreId,
717+
$this->getCurrentStore()->getId(),
694718
[]
695719
)->where(
696720
$this->connection->getIfNullSql('ccacs.value', 'ccacd.value') . ' = ?',
@@ -702,8 +726,14 @@ protected function fillTempCategoryTreeIndex($temporaryName)
702726
foreach ($selects as $select) {
703727
$values = [];
704728

705-
foreach ($this->connection->fetchAll($select) as $category) {
706-
foreach (explode('/', $category['path']) as $parentId) {
729+
$categories = $this->connection->fetchAll($select);
730+
foreach ($categories as $category) {
731+
$categoriesTree = explode('/', $category['path']);
732+
foreach ($categoriesTree as $parentId) {
733+
if (!in_array($this->getCurrentStore()->getRootCategoryId(), $categoriesTree, true)) {
734+
break;
735+
}
736+
707737
if ($parentId !== $category['entity_id']) {
708738
$values[] = [$parentId, $category['entity_id']];
709739
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\GraphQl\Catalog\Product;
10+
11+
use Magento\TestFramework\TestCase\GraphQlAbstract;
12+
13+
/**
14+
* Test for product categories
15+
*/
16+
class ProductCategoriesTest extends GraphQlAbstract
17+
{
18+
/**
19+
* @magentoApiDataFixture Magento/Catalog/_files/product_in_two_root_categories.php
20+
*/
21+
public function testProductCategoriesInDefaultStore(): void
22+
{
23+
$response = $this->graphQlQuery(
24+
$this->getQuery('in-stock-product'),
25+
[],
26+
'',
27+
['Store' => 'default']
28+
);
29+
30+
$product = current($response['products']['items']);
31+
$categories = $product['categories'];
32+
33+
self::assertCount(1, $categories);
34+
self::assertEquals('Category 1', $categories[0]['name']);
35+
self::assertEquals('category-1', $categories[0]['url_path']);
36+
self::assertEquals('category-1', $categories[0]['url_path']);
37+
self::assertNull($categories[0]['breadcrumbs']);
38+
}
39+
40+
/**
41+
* @magentoApiDataFixture Magento/Catalog/_files/product_in_two_root_categories.php
42+
*/
43+
public function testProductCategoriesInNonDefaultStore(): void
44+
{
45+
$response = $this->graphQlQuery(
46+
$this->getQuery('in-stock-product'),
47+
[],
48+
'',
49+
['Store' => 'test_store_1']
50+
);
51+
52+
$product = current($response['products']['items']);
53+
$categories = $product['categories'];
54+
55+
self::assertCount(2, $categories);
56+
self::assertEquals('Second Root Subcategory', $categories[0]['name']);
57+
self::assertEquals('second-root-subcategory', $categories[0]['url_path']);
58+
self::assertNull($categories[0]['breadcrumbs']);
59+
self::assertEquals('Second Root Subsubcategory', $categories[1]['name']);
60+
self::assertEquals('second-root-subcategory/second-root-subsubcategory', $categories[1]['url_path']);
61+
self::assertCount(1, $categories[1]['breadcrumbs']);
62+
self::assertEquals('Second Root Subcategory', $categories[1]['breadcrumbs'][0]['category_name']);
63+
self::assertEquals(2, $categories[1]['breadcrumbs'][0]['category_level']);
64+
}
65+
66+
/**
67+
* @magentoApiDataFixture Magento/Catalog/_files/product_in_two_root_categories.php
68+
* @magentoApiDataFixture Magento/Store/_files/second_store.php
69+
*/
70+
public function testProductCategoriesInNotRelevantStore(): void
71+
{
72+
$response = $this->graphQlQuery(
73+
$this->getQuery('in-stock-product'),
74+
[],
75+
'',
76+
['Store' => 'fixture_second_store']
77+
);
78+
79+
self::assertEmpty($response['products']['items']);
80+
}
81+
82+
/**
83+
* Get query
84+
*
85+
* @param string $sku
86+
* @return string
87+
*/
88+
private function getQuery(string $sku): string
89+
{
90+
return <<<QUERY
91+
{
92+
products(filter: { sku: { eq: "{$sku}"} }){
93+
items {
94+
categories {
95+
name
96+
id
97+
url_path
98+
breadcrumbs {
99+
category_id
100+
category_name
101+
category_level
102+
}
103+
}
104+
}
105+
}
106+
}
107+
QUERY;
108+
}
109+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Magento\Catalog\Api\CategoryRepositoryInterface;
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Catalog\Model\CategoryFactory;
13+
use Magento\Catalog\Model\ResourceModel\Category\Collection;
14+
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
15+
use Magento\Store\Api\WebsiteRepositoryInterface;
16+
use Magento\TestFramework\Helper\Bootstrap;
17+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
18+
19+
Resolver::getInstance()->requireDataFixture('Magento/Store/_files/store_with_second_root_category.php');
20+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_category.php');
21+
22+
$objectManager = Bootstrap::getObjectManager();
23+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
24+
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
25+
$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class);
26+
$categoryCollectionFactory = $objectManager->get(CollectionFactory::class);
27+
$categoryFactory = $objectManager->get(CategoryFactory::class);
28+
29+
$defaultWebsiteId = $websiteRepository->get('base')->getId();
30+
$secondWebsiteId = $websiteRepository->get('test')->getId();
31+
32+
/** @var $categoryCollection Collection */
33+
$categoryCollection = $categoryCollectionFactory->create();
34+
$categoryCollection->addFieldToFilter('name', ['eq' => 'Second Root Category']);
35+
$secondRootCategory = $categoryCollection->getFirstItem();
36+
37+
$subCategory = $categoryFactory->create();
38+
$subCategory
39+
->setName('Second Root Subcategory')
40+
->setParentId($secondRootCategory->getEntityId())
41+
->setLevel(2)
42+
->setAvailableSortBy(['position', 'name'])
43+
->setDefaultSortBy('name')
44+
->setIsActive(true)
45+
->setPosition(1);
46+
$subCategory = $categoryRepository->save($subCategory);
47+
48+
$subSubCategory = $categoryFactory->create();
49+
$subSubCategory
50+
->setName('Second Root Subsubcategory')
51+
->setParentId($subCategory->getEntityId())
52+
->setLevel(2)
53+
->setAvailableSortBy(['position', 'name'])
54+
->setDefaultSortBy('name')
55+
->setIsActive(true)
56+
->setPosition(1);
57+
$subSubCategory = $categoryRepository->save($subSubCategory);
58+
59+
/** @var $product ProductInterface */
60+
$product = $productRepository->get('in-stock-product');
61+
$product
62+
->setUrlKey('in-stock-product')
63+
->setWebsiteIds([$defaultWebsiteId, $secondWebsiteId])
64+
->setCategoryIds(
65+
[2, 333, $secondRootCategory->getEntityId(), $subCategory->getEntityId(), $subSubCategory->getEntityId()]
66+
);
67+
$productRepository->save($product);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
10+
11+
Resolver::getInstance()->requireDataFixture('Magento/Store/_files/store_with_second_root_category_rollback.php');
12+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_category_rollback.php');

0 commit comments

Comments
 (0)