Skip to content

Commit 7b71780

Browse files
ENGCOM-7677: #28568:GraphQL query returns admin option value label… #28647
- Merge Pull Request #28647 from gallyamov/magento2:28568_admin_option_labels - Merged commits: 1. 5294b5d 2. 9d99f17 3. 1787ee2 4. f54b149 5. 68f8c77 6. ddaed60
2 parents c284664 + ddaed60 commit 7b71780

File tree

5 files changed

+334
-5
lines changed

5 files changed

+334
-5
lines changed

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation;
99

1010
use Magento\Framework\App\ResourceConnection;
11+
use Magento\Store\Model\Store;
1112

1213
/**
1314
* Fetch product attribute option data including attribute info
@@ -41,16 +42,18 @@ public function __construct(ResourceConnection $resourceConnection)
4142
* Get option data. Return list of attributes with option data
4243
*
4344
* @param array $optionIds
45+
* @param int|null $storeId
4446
* @param array $attributeCodes
4547
* @return array
4648
* @throws \Zend_Db_Statement_Exception
4749
*/
48-
public function getOptions(array $optionIds, array $attributeCodes = []): array
50+
public function getOptions(array $optionIds, ?int $storeId, array $attributeCodes = []): array
4951
{
5052
if (!$optionIds) {
5153
return [];
5254
}
5355

56+
$storeId = $storeId ?: Store::DEFAULT_STORE_ID;
5457
$connection = $this->resourceConnection->getConnection();
5558
$select = $connection->select()
5659
->from(
@@ -70,9 +73,21 @@ public function getOptions(array $optionIds, array $attributeCodes = []): array
7073
['option_value' => $this->resourceConnection->getTableName('eav_attribute_option_value')],
7174
'options.option_id = option_value.option_id',
7275
[
73-
'option_label' => 'option_value.value',
7476
'option_id' => 'option_value.option_id',
7577
]
78+
)->joinLeft(
79+
['option_value_store' => $this->resourceConnection->getTableName('eav_attribute_option_value')],
80+
"options.option_id = option_value_store.option_id AND option_value_store.store_id = {$storeId}",
81+
[
82+
'option_label' => $connection->getCheckSql(
83+
'option_value_store.value_id > 0',
84+
'option_value_store.value',
85+
'option_value.value'
86+
)
87+
]
88+
)->where(
89+
'a.attribute_id = options.attribute_id AND option_value.store_id = ?',
90+
Store::DEFAULT_STORE_ID
7691
);
7792

7893
$select->where('option_value.option_id IN (?)', $optionIds);

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function __construct(
7171
*/
7272
public function build(AggregationInterface $aggregation, ?int $storeId): array
7373
{
74-
$attributeOptions = $this->getAttributeOptions($aggregation);
74+
$attributeOptions = $this->getAttributeOptions($aggregation, $storeId);
7575

7676
// build layer per attribute
7777
$result = [];
@@ -133,10 +133,11 @@ private function isBucketEmpty(?BucketInterface $bucket): bool
133133
* Get list of attributes with options
134134
*
135135
* @param AggregationInterface $aggregation
136+
* @param int|null $storeId
136137
* @return array
137138
* @throws \Zend_Db_Statement_Exception
138139
*/
139-
private function getAttributeOptions(AggregationInterface $aggregation): array
140+
private function getAttributeOptions(AggregationInterface $aggregation, ?int $storeId): array
140141
{
141142
$attributeOptionIds = [];
142143
$attributes = [];
@@ -154,6 +155,6 @@ function (AggregationValueInterface $value) {
154155
return [];
155156
}
156157

157-
return $this->attributeOptionProvider->getOptions(\array_merge(...$attributeOptionIds), $attributes);
158+
return $this->attributeOptionProvider->getOptions(\array_merge(...$attributeOptionIds), $storeId, $attributes);
158159
}
159160
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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\GraphQl\Catalog;
9+
10+
use Exception;
11+
use Magento\Eav\Api\Data\AttributeOptionInterface;
12+
use Magento\Eav\Model\Config;
13+
use Magento\Framework\Exception\LocalizedException;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
use Magento\TestFramework\TestCase\GraphQlAbstract;
16+
17+
class ProductAttributeStoreOptionsTest extends GraphQlAbstract
18+
{
19+
/**
20+
* Test that custom attribute option labels are returned respecting store
21+
*
22+
* @magentoApiDataFixture Magento/Store/_files/store.php
23+
* @magentoApiDataFixture Magento/Catalog/_files/products_with_layered_navigation_attribute_store_options.php
24+
* @throws LocalizedException
25+
*/
26+
public function testAttributeStoreLabels(): void
27+
{
28+
$this->attributeLabelTest('Option Default Store');
29+
$this->attributeLabelTest('Option Test Store', ['Store' => 'test']);
30+
}
31+
32+
/**
33+
* @param $expectedLabel
34+
* @param array $headers
35+
* @throws LocalizedException
36+
* @throws Exception
37+
*/
38+
private function attributeLabelTest($expectedLabel, array $headers = []): void
39+
{
40+
/** @var Config $eavConfig */
41+
$eavConfig = Bootstrap::getObjectManager()->get(Config::class);
42+
$attributeCode = 'test_configurable';
43+
$attribute = $eavConfig->getAttribute('catalog_product', $attributeCode);
44+
45+
/** @var AttributeOptionInterface[] $options */
46+
$options = $attribute->getOptions();
47+
array_shift($options);
48+
$optionValues = [];
49+
50+
foreach ($options as $option) {
51+
$optionValues[] = [
52+
'value' => $option->getValue(),
53+
];
54+
}
55+
56+
$expectedOptions = [
57+
[
58+
'label' => $expectedLabel,
59+
'value' => $optionValues[0]['value']
60+
]
61+
];
62+
63+
$query = <<<QUERY
64+
{
65+
products(search:"Simple",
66+
pageSize: 3
67+
currentPage: 1
68+
)
69+
{
70+
aggregations
71+
{
72+
attribute_code
73+
options
74+
{
75+
label
76+
value
77+
}
78+
}
79+
}
80+
}
81+
QUERY;
82+
$response = $this->graphQlQuery($query, [], '', $headers);
83+
$this->assertNotEmpty($response['products']['aggregations']);
84+
$actualAttributes = $response['products']['aggregations'];
85+
$actualAttributeOptions = [];
86+
87+
foreach ($actualAttributes as $actualAttribute) {
88+
if ($actualAttribute['attribute_code'] === $attributeCode) {
89+
$actualAttributeOptions = $actualAttribute['options'];
90+
}
91+
}
92+
93+
$this->assertNotEmpty($actualAttributeOptions);
94+
95+
foreach ($actualAttributeOptions as $key => $actualAttributeOption) {
96+
if ($actualAttributeOption['value'] === $expectedOptions[$key]['value']) {
97+
$this->assertEquals($actualAttributeOption['label'], $expectedOptions[$key]['label']);
98+
}
99+
}
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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\Eav\Api\AttributeRepositoryInterface;
9+
use Magento\Store\Model\Store;
10+
use Magento\TestFramework\Helper\Bootstrap;
11+
12+
$eavConfig = Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
13+
$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
14+
15+
$eavConfig->clear();
16+
17+
/** @var $installer \Magento\Catalog\Setup\CategorySetup */
18+
$installer = Bootstrap::getObjectManager()->create(\Magento\Catalog\Setup\CategorySetup::class);
19+
20+
if (!$attribute->getId()) {
21+
22+
/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
23+
$attribute = Bootstrap::getObjectManager()->create(
24+
\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
25+
);
26+
27+
/** @var AttributeRepositoryInterface $attributeRepository */
28+
$attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class);
29+
30+
/** @var $store \Magento\Store\Model\Store */
31+
$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
32+
$store = $store->load('test', 'code');
33+
34+
$attribute->setData(
35+
[
36+
'attribute_code' => 'test_configurable',
37+
'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
38+
'is_global' => 1,
39+
'is_user_defined' => 1,
40+
'frontend_input' => 'select',
41+
'is_unique' => 0,
42+
'is_required' => 0,
43+
'is_searchable' => 1,
44+
'is_visible_in_advanced_search' => 1,
45+
'is_comparable' => 1,
46+
'is_filterable' => 1,
47+
'is_filterable_in_search' => 1,
48+
'is_used_for_promo_rules' => 0,
49+
'is_html_allowed_on_front' => 1,
50+
'is_visible_on_front' => 1,
51+
'used_in_product_listing' => 1,
52+
'used_for_sort_by' => 1,
53+
'frontend_label' => ['Test Configurable'],
54+
'backend_type' => 'int',
55+
'option' => [
56+
'value' => ['option_0' => [
57+
Store::DEFAULT_STORE_ID => 'Option Admin Store',
58+
Store::DISTRO_STORE_ID => 'Option Default Store',
59+
$store->getId() => 'Option Test Store'
60+
], 'option_1' => ['Option 2']],
61+
'order' => ['option_0' => 1, 'option_1' => 2],
62+
],
63+
'default' => ['option_0']
64+
]
65+
);
66+
67+
$attributeRepository->save($attribute);
68+
69+
/* Assign attribute to attribute set */
70+
$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId());
71+
}
72+
73+
$eavConfig->clear();
74+
75+
/** @var \Magento\Framework\ObjectManagerInterface $objectManager */
76+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
77+
78+
/** @var $product \Magento\Catalog\Model\Product */
79+
$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
80+
$product->isObjectNew(true);
81+
$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
82+
->setId(10)
83+
->setAttributeSetId(4)
84+
->setName('Simple Product1')
85+
->setSku('simple1')
86+
->setTaxClassId('none')
87+
->setDescription('description')
88+
->setShortDescription('short description')
89+
->setOptionsContainer('container1')
90+
->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART)
91+
->setPrice(10)
92+
->setWeight(1)
93+
->setMetaTitle('meta title')
94+
->setMetaKeyword('meta keyword')
95+
->setMetaDescription('meta description')
96+
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
97+
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
98+
->setWebsiteIds([1])
99+
->setCategoryIds([])
100+
->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
101+
->setSpecialPrice('5.99')
102+
->save();
103+
104+
$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
105+
$product->isObjectNew(true);
106+
$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
107+
->setId(11)
108+
->setAttributeSetId(4)
109+
->setName('Simple Product2')
110+
->setSku('simple2')
111+
->setTaxClassId('none')
112+
->setDescription('description')
113+
->setShortDescription('short description')
114+
->setOptionsContainer('container1')
115+
->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_ON_GESTURE)
116+
->setPrice(20)
117+
->setWeight(1)
118+
->setMetaTitle('meta title')
119+
->setMetaKeyword('meta keyword')
120+
->setMetaDescription('meta description')
121+
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
122+
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
123+
->setWebsiteIds([1])
124+
->setCategoryIds([])
125+
->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
126+
->setSpecialPrice('15.99')
127+
->save();
128+
129+
$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Category::class);
130+
$category->isObjectNew(true);
131+
$category->setId(
132+
333
133+
)->setCreatedAt(
134+
'2014-06-23 09:50:07'
135+
)->setName(
136+
'Category 1'
137+
)->setParentId(
138+
2
139+
)->setPath(
140+
'1/2/333'
141+
)->setLevel(
142+
2
143+
)->setAvailableSortBy(
144+
['position', 'name']
145+
)->setDefaultSortBy(
146+
'name'
147+
)->setIsActive(
148+
true
149+
)->setPosition(
150+
1
151+
)->setPostedProducts(
152+
[10 => 10, 11 => 11]
153+
)->save();
154+
155+
/** @var \Magento\Indexer\Model\Indexer\Collection $indexerCollection */
156+
$indexerCollection = Bootstrap::getObjectManager()->get(\Magento\Indexer\Model\Indexer\Collection::class);
157+
$indexerCollection->load();
158+
159+
/** @var \Magento\Indexer\Model\Indexer $indexer */
160+
foreach ($indexerCollection->getItems() as $indexer) {
161+
$indexer->reindexAll();
162+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
9+
/** @var \Magento\Framework\Registry $registry */
10+
$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
11+
12+
$registry->unregister('isSecureArea');
13+
$registry->register('isSecureArea', true);
14+
15+
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
16+
$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
17+
18+
foreach (['simple1', 'simple2'] as $sku) {
19+
try {
20+
$product = $productRepository->get($sku, false, null, true);
21+
$productRepository->delete($product);
22+
} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) {
23+
//Product already removed
24+
}
25+
}
26+
27+
$productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
28+
->get(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
29+
foreach ($productCollection as $product) {
30+
$product->delete();
31+
}
32+
33+
/** @var $category \Magento\Catalog\Model\Category */
34+
$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Category::class);
35+
$category->load(333);
36+
if ($category->getId()) {
37+
$category->delete();
38+
}
39+
40+
$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
41+
$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
42+
if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
43+
&& $attribute->getId()
44+
) {
45+
$attribute->delete();
46+
}
47+
$eavConfig->clear();
48+
49+
$registry->unregister('isSecureArea');
50+
$registry->register('isSecureArea', false);

0 commit comments

Comments
 (0)