Skip to content

magento/magento2#28568:GraphQL query returns admin option value label… #28647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation;

use Magento\Framework\App\ResourceConnection;
use Magento\Store\Model\Store;

/**
* Fetch product attribute option data including attribute info
Expand Down Expand Up @@ -41,16 +42,18 @@ public function __construct(ResourceConnection $resourceConnection)
* Get option data. Return list of attributes with option data
*
* @param array $optionIds
* @param int|null $storeId
* @param array $attributeCodes
* @return array
* @throws \Zend_Db_Statement_Exception
*/
public function getOptions(array $optionIds, array $attributeCodes = []): array
public function getOptions(array $optionIds, ?int $storeId, array $attributeCodes = []): array
{
if (!$optionIds) {
return [];
}

$storeId = $storeId ?: Store::DEFAULT_STORE_ID;
$connection = $this->resourceConnection->getConnection();
$select = $connection->select()
->from(
Expand All @@ -70,9 +73,21 @@ public function getOptions(array $optionIds, array $attributeCodes = []): array
['option_value' => $this->resourceConnection->getTableName('eav_attribute_option_value')],
'options.option_id = option_value.option_id',
[
'option_label' => 'option_value.value',
'option_id' => 'option_value.option_id',
]
)->joinLeft(
['option_value_store' => $this->resourceConnection->getTableName('eav_attribute_option_value')],
"options.option_id = option_value_store.option_id AND option_value_store.store_id = {$storeId}",
[
'option_label' => $connection->getCheckSql(
'option_value_store.value_id > 0',
'option_value_store.value',
'option_value.value'
)
]
)->where(
'a.attribute_id = options.attribute_id AND option_value.store_id = ?',
Store::DEFAULT_STORE_ID
);

$select->where('option_value.option_id IN (?)', $optionIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function __construct(
*/
public function build(AggregationInterface $aggregation, ?int $storeId): array
{
$attributeOptions = $this->getAttributeOptions($aggregation);
$attributeOptions = $this->getAttributeOptions($aggregation, $storeId);

// build layer per attribute
$result = [];
Expand Down Expand Up @@ -133,10 +133,11 @@ private function isBucketEmpty(?BucketInterface $bucket): bool
* Get list of attributes with options
*
* @param AggregationInterface $aggregation
* @param int|null $storeId
* @return array
* @throws \Zend_Db_Statement_Exception
*/
private function getAttributeOptions(AggregationInterface $aggregation): array
private function getAttributeOptions(AggregationInterface $aggregation, ?int $storeId): array
{
$attributeOptionIds = [];
$attributes = [];
Expand All @@ -154,6 +155,6 @@ function (AggregationValueInterface $value) {
return [];
}

return $this->attributeOptionProvider->getOptions(\array_merge(...$attributeOptionIds), $attributes);
return $this->attributeOptionProvider->getOptions(\array_merge(...$attributeOptionIds), $storeId, $attributes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Catalog;

use Exception;
use Magento\Eav\Api\Data\AttributeOptionInterface;
use Magento\Eav\Model\Config;
use Magento\Framework\Exception\LocalizedException;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;

class ProductAttributeStoreOptionsTest extends GraphQlAbstract
{
/**
* Test that custom attribute option labels are returned respecting store
*
* @magentoApiDataFixture Magento/Store/_files/store.php
* @magentoApiDataFixture Magento/Catalog/_files/products_with_layered_navigation_attribute_store_options.php
* @throws LocalizedException
*/
public function testAttributeStoreLabels(): void
{
$this->attributeLabelTest('Option Default Store');
$this->attributeLabelTest('Option Test Store', ['Store' => 'test']);
}

/**
* @param $expectedLabel
* @param array $headers
* @throws LocalizedException
* @throws Exception
*/
private function attributeLabelTest($expectedLabel, array $headers = []): void
{
/** @var Config $eavConfig */
$eavConfig = Bootstrap::getObjectManager()->get(Config::class);
$attributeCode = 'test_configurable';
$attribute = $eavConfig->getAttribute('catalog_product', $attributeCode);

/** @var AttributeOptionInterface[] $options */
$options = $attribute->getOptions();
array_shift($options);
$optionValues = [];

foreach ($options as $option) {
$optionValues[] = [
'value' => $option->getValue(),
];
}

$expectedOptions = [
[
'label' => $expectedLabel,
'value' => $optionValues[0]['value']
]
];

$query = <<<QUERY
{
products(search:"Simple",
pageSize: 3
currentPage: 1
)
{
aggregations
{
attribute_code
options
{
label
value
}
}
}
}
QUERY;
$response = $this->graphQlQuery($query, [], '', $headers);
$this->assertNotEmpty($response['products']['aggregations']);
$actualAttributes = $response['products']['aggregations'];
$actualAttributeOptions = [];

foreach ($actualAttributes as $actualAttribute) {
if ($actualAttribute['attribute_code'] === $attributeCode) {
$actualAttributeOptions = $actualAttribute['options'];
}
}

$this->assertNotEmpty($actualAttributeOptions);

foreach ($actualAttributeOptions as $key => $actualAttributeOption) {
if ($actualAttributeOption['value'] === $expectedOptions[$key]['value']) {
$this->assertEquals($actualAttributeOption['label'], $expectedOptions[$key]['label']);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

use Magento\Eav\Api\AttributeRepositoryInterface;
use Magento\Store\Model\Store;
use Magento\TestFramework\Helper\Bootstrap;

$eavConfig = Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');

$eavConfig->clear();

/** @var $installer \Magento\Catalog\Setup\CategorySetup */
$installer = Bootstrap::getObjectManager()->create(\Magento\Catalog\Setup\CategorySetup::class);

if (!$attribute->getId()) {

/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
$attribute = Bootstrap::getObjectManager()->create(
\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
);

/** @var AttributeRepositoryInterface $attributeRepository */
$attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class);

/** @var $store \Magento\Store\Model\Store */
$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
$store = $store->load('test', 'code');

$attribute->setData(
[
'attribute_code' => 'test_configurable',
'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
'is_global' => 1,
'is_user_defined' => 1,
'frontend_input' => 'select',
'is_unique' => 0,
'is_required' => 0,
'is_searchable' => 1,
'is_visible_in_advanced_search' => 1,
'is_comparable' => 1,
'is_filterable' => 1,
'is_filterable_in_search' => 1,
'is_used_for_promo_rules' => 0,
'is_html_allowed_on_front' => 1,
'is_visible_on_front' => 1,
'used_in_product_listing' => 1,
'used_for_sort_by' => 1,
'frontend_label' => ['Test Configurable'],
'backend_type' => 'int',
'option' => [
'value' => ['option_0' => [
Store::DEFAULT_STORE_ID => 'Option Admin Store',
Store::DISTRO_STORE_ID => 'Option Default Store',
$store->getId() => 'Option Test Store'
], 'option_1' => ['Option 2']],
'order' => ['option_0' => 1, 'option_1' => 2],
],
'default' => ['option_0']
]
);

$attributeRepository->save($attribute);

/* Assign attribute to attribute set */
$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId());
}

$eavConfig->clear();

/** @var \Magento\Framework\ObjectManagerInterface $objectManager */
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();

/** @var $product \Magento\Catalog\Model\Product */
$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
$product->isObjectNew(true);
$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
->setId(10)
->setAttributeSetId(4)
->setName('Simple Product1')
->setSku('simple1')
->setTaxClassId('none')
->setDescription('description')
->setShortDescription('short description')
->setOptionsContainer('container1')
->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART)
->setPrice(10)
->setWeight(1)
->setMetaTitle('meta title')
->setMetaKeyword('meta keyword')
->setMetaDescription('meta description')
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
->setWebsiteIds([1])
->setCategoryIds([])
->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
->setSpecialPrice('5.99')
->save();

$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
$product->isObjectNew(true);
$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
->setId(11)
->setAttributeSetId(4)
->setName('Simple Product2')
->setSku('simple2')
->setTaxClassId('none')
->setDescription('description')
->setShortDescription('short description')
->setOptionsContainer('container1')
->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_ON_GESTURE)
->setPrice(20)
->setWeight(1)
->setMetaTitle('meta title')
->setMetaKeyword('meta keyword')
->setMetaDescription('meta description')
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
->setWebsiteIds([1])
->setCategoryIds([])
->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
->setSpecialPrice('15.99')
->save();

$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Category::class);
$category->isObjectNew(true);
$category->setId(
333
)->setCreatedAt(
'2014-06-23 09:50:07'
)->setName(
'Category 1'
)->setParentId(
2
)->setPath(
'1/2/333'
)->setLevel(
2
)->setAvailableSortBy(
['position', 'name']
)->setDefaultSortBy(
'name'
)->setIsActive(
true
)->setPosition(
1
)->setPostedProducts(
[10 => 10, 11 => 11]
)->save();

/** @var \Magento\Indexer\Model\Indexer\Collection $indexerCollection */
$indexerCollection = Bootstrap::getObjectManager()->get(\Magento\Indexer\Model\Indexer\Collection::class);
$indexerCollection->load();

/** @var \Magento\Indexer\Model\Indexer $indexer */
foreach ($indexerCollection->getItems() as $indexer) {
$indexer->reindexAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
/** @var \Magento\Framework\Registry $registry */
$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);

$registry->unregister('isSecureArea');
$registry->register('isSecureArea', true);

/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);

foreach (['simple1', 'simple2'] as $sku) {
try {
$product = $productRepository->get($sku, false, null, true);
$productRepository->delete($product);
} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) {
//Product already removed
}
}

$productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
->get(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
foreach ($productCollection as $product) {
$product->delete();
}

/** @var $category \Magento\Catalog\Model\Category */
$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Category::class);
$category->load(333);
if ($category->getId()) {
$category->delete();
}

$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
&& $attribute->getId()
) {
$attribute->delete();
}
$eavConfig->clear();

$registry->unregister('isSecureArea');
$registry->register('isSecureArea', false);