Skip to content

Commit 0a834cc

Browse files
authored
Merge pull request #8417 from magento-lynx/eav-graphql
2 parents ca30c47 + 7b33900 commit 0a834cc

File tree

59 files changed

+2197
-996
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2197
-996
lines changed

app/code/Magento/Catalog/Test/Fixture/Attribute.php

+61-8
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
use Magento\Catalog\Api\ProductAttributeManagementInterface;
1212
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1313
use Magento\Catalog\Model\Product;
14+
use Magento\Catalog\Model\ResourceModel\Attribute as ResourceModelAttribute;
15+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
16+
use Magento\Eav\Model\AttributeFactory;
1417
use Magento\Eav\Setup\EavSetup;
1518
use Magento\Framework\DataObject;
19+
use Magento\TestFramework\Fixture\Api\DataMerger;
1620
use Magento\TestFramework\Fixture\Api\ServiceFactory;
1721
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
1822
use Magento\TestFramework\Fixture\Data\ProcessorInterface;
@@ -30,12 +34,12 @@ class Attribute implements RevertibleDataFixtureInterface
3034
'is_filterable_in_grid' => true,
3135
'position' => 0,
3236
'apply_to' => [],
33-
'is_searchable' => '0',
34-
'is_visible_in_advanced_search' => '0',
35-
'is_comparable' => '0',
36-
'is_used_for_promo_rules' => '0',
37-
'is_visible_on_front' => '0',
38-
'used_in_product_listing' => '0',
37+
'is_searchable' => false,
38+
'is_visible_in_advanced_search' => false,
39+
'is_comparable' => false,
40+
'is_used_for_promo_rules' => false,
41+
'is_visible_on_front' => false,
42+
'used_in_product_listing' => false,
3943
'is_visible' => true,
4044
'scope' => 'store',
4145
'attribute_code' => 'product_attribute%uniqid%',
@@ -49,7 +53,6 @@ class Attribute implements RevertibleDataFixtureInterface
4953
'backend_type' => 'varchar',
5054
'is_unique' => '0',
5155
'validation_rules' => []
52-
5356
];
5457

5558
private const DEFAULT_ATTRIBUTE_SET_DATA = [
@@ -78,29 +81,59 @@ class Attribute implements RevertibleDataFixtureInterface
7881
*/
7982
private $productAttributeManagement;
8083

84+
/**
85+
* @var AttributeFactory
86+
*/
87+
private AttributeFactory $attributeFactory;
88+
89+
/**
90+
* @var DataMerger
91+
*/
92+
private DataMerger $dataMerger;
93+
94+
/**
95+
* @var ResourceModelAttribute
96+
*/
97+
private ResourceModelAttribute $resourceModelAttribute;
98+
8199
/**
82100
* @param ServiceFactory $serviceFactory
83101
* @param ProcessorInterface $dataProcessor
84102
* @param EavSetup $eavSetup
103+
* @param ProductAttributeManagementInterface $productAttributeManagement
104+
* @param AttributeFactory $attributeFactory
105+
* @param DataMerger $dataMerger
106+
* @param ResourceModelAttribute $resourceModelAttribute
85107
*/
86108
public function __construct(
87109
ServiceFactory $serviceFactory,
88110
ProcessorInterface $dataProcessor,
89111
EavSetup $eavSetup,
90-
ProductAttributeManagementInterface $productAttributeManagement
112+
ProductAttributeManagementInterface $productAttributeManagement,
113+
AttributeFactory $attributeFactory,
114+
DataMerger $dataMerger,
115+
ResourceModelAttribute $resourceModelAttribute
91116
) {
92117
$this->serviceFactory = $serviceFactory;
93118
$this->dataProcessor = $dataProcessor;
94119
$this->eavSetup = $eavSetup;
95120
$this->productAttributeManagement = $productAttributeManagement;
121+
$this->attributeFactory = $attributeFactory;
122+
$this->dataMerger = $dataMerger;
123+
$this->resourceModelAttribute = $resourceModelAttribute;
96124
}
97125

98126
/**
99127
* {@inheritdoc}
100128
* @param array $data Parameters. Same format as Attribute::DEFAULT_DATA.
129+
* @return DataObject|null
101130
*/
102131
public function apply(array $data = []): ?DataObject
103132
{
133+
if (array_key_exists('additional_data', $data)) {
134+
return $this->applyAttributeWithAdditionalData($data);
135+
}
136+
104137
$service = $this->serviceFactory->create(ProductAttributeRepositoryInterface::class, 'save');
105138

106139
/**
@@ -139,6 +172,26 @@ public function revert(DataObject $data): void
139172
);
140173
}
141174

175+
/**
176+
* @param array $data Parameters. Same format as Attribute::DEFAULT_DATA.
177+
* @return DataObject|null
178+
*/
179+
private function applyAttributeWithAdditionalData(array $data = []): ?DataObject
180+
{
181+
$defaultData = array_merge(self::DEFAULT_DATA, ['additional_data' => null]);
182+
/** @var EavAttribute $attr */
183+
$attr = $this->attributeFactory->createAttribute(EavAttribute::class, $defaultData);
184+
$mergedData = $this->dataProcessor->process($this, $this->dataMerger->merge($defaultData, $data));
185+
186+
$attributeSetData = $this->prepareAttributeSetData(
187+
array_intersect_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA)
188+
);
189+
190+
$attr->setData(array_merge($mergedData, $attributeSetData));
191+
$this->resourceModelAttribute->save($attr);
192+
return $attr;
193+
}
194+
142195
/**
143196
* Prepare attribute data
144197
*

app/code/Magento/CatalogGraphQl/Model/Output/AttributeMetadata.php

+16-6
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,32 @@ public function execute(
5252
}
5353

5454
$metadata = [
55-
'is_searchable' => $attribute->getIsSearchable() === "1",
56-
'is_filterable' => $attribute->getIsFilterable() === "1",
5755
'is_comparable' => $attribute->getIsComparable() === "1",
56+
'is_filterable' => $attribute->getIsFilterable() === "1",
57+
'is_filterable_in_search' => $attribute->getIsFilterableInSearch() === "1",
58+
'is_searchable' => $attribute->getIsSearchable() === "1",
5859
'is_html_allowed_on_front' => $attribute->getIsHtmlAllowedOnFront() === "1",
5960
'is_used_for_price_rules' => $attribute->getIsUsedForPriceRules() === "1",
60-
'is_filterable_in_search' => $attribute->getIsFilterableInSearch() === "1",
61-
'used_in_product_listing' => $attribute->getUsedInProductListing() === "1",
62-
'is_wysiwyg_enabled' => $attribute->getIsWysiwygEnabled() === "1",
6361
'is_used_for_promo_rules' => $attribute->getIsUsedForPromoRules() === "1",
64-
'apply_to' => null,
62+
'is_visible_in_advanced_search' => $attribute->getIsVisibleInAdvancedSearch() === "1",
63+
'is_visible_on_front' => $attribute->getIsVisibleOnFront() === "1",
64+
'is_wysiwyg_enabled' => $attribute->getIsWysiwygEnabled() === "1",
65+
'used_in_product_listing' => $attribute->getUsedInProductListing() === "1",
66+
'apply_to' => null
6567
];
6668

6769
if (!empty($attribute->getApplyTo())) {
6870
$metadata['apply_to'] = array_map('strtoupper', $attribute->getApplyTo());
6971
}
7072

73+
if (!empty($attribute->getAdditionalData())) {
74+
$additionalData = json_decode($attribute->getAdditionalData(), true);
75+
$metadata = array_merge(
76+
$metadata,
77+
array_map('strtoupper', $additionalData)
78+
);
79+
}
80+
7181
return $metadata;
7282
}
7383
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductCustomAttributes.php

+25-47
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212
use Magento\Catalog\Model\Product;
1313
use Magento\CatalogGraphQl\Model\ProductDataProvider;
1414
use Magento\Eav\Api\Data\AttributeInterface;
15-
use Magento\Eav\Model\AttributeRepository;
1615
use Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface;
17-
use Magento\EavGraphQl\Model\Resolver\AttributeFilter;
18-
use Magento\Framework\Api\SearchCriteriaBuilder;
16+
use Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes;
1917
use Magento\GraphQl\Model\Query\ContextInterface;
2018
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
2119
use Magento\Framework\GraphQl\Config\Element\Field;
@@ -27,16 +25,6 @@
2725
*/
2826
class ProductCustomAttributes implements ResolverInterface
2927
{
30-
/**
31-
* @var AttributeRepository
32-
*/
33-
private AttributeRepository $attributeRepository;
34-
35-
/**
36-
* @var SearchCriteriaBuilder
37-
*/
38-
private SearchCriteriaBuilder $searchCriteriaBuilder;
39-
4028
/**
4129
* @var GetAttributeValueInterface
4230
*/
@@ -48,36 +36,30 @@ class ProductCustomAttributes implements ResolverInterface
4836
private ProductDataProvider $productDataProvider;
4937

5038
/**
51-
* @var AttributeFilter
39+
* @var GetFilteredAttributes
5240
*/
53-
private AttributeFilter $attributeFilter;
41+
private GetFilteredAttributes $getFilteredAttributes;
5442

5543
/**
5644
* @var FilterProductCustomAttribute
5745
*/
5846
private FilterProductCustomAttribute $filterCustomAttribute;
5947

6048
/**
61-
* @param AttributeRepository $attributeRepository
62-
* @param SearchCriteriaBuilder $searchCriteriaBuilder
6349
* @param GetAttributeValueInterface $getAttributeValue
6450
* @param ProductDataProvider $productDataProvider
65-
* @param AttributeFilter $attributeFilter
51+
* @param GetFilteredAttributes $getFilteredAttributes
6652
* @param FilterProductCustomAttribute $filterCustomAttribute
6753
*/
6854
public function __construct(
69-
AttributeRepository $attributeRepository,
70-
SearchCriteriaBuilder $searchCriteriaBuilder,
7155
GetAttributeValueInterface $getAttributeValue,
7256
ProductDataProvider $productDataProvider,
73-
AttributeFilter $attributeFilter,
57+
GetFilteredAttributes $getFilteredAttributes,
7458
FilterProductCustomAttribute $filterCustomAttribute
7559
) {
76-
$this->attributeRepository = $attributeRepository;
77-
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
7860
$this->getAttributeValue = $getAttributeValue;
7961
$this->productDataProvider = $productDataProvider;
80-
$this->attributeFilter = $attributeFilter;
62+
$this->getFilteredAttributes = $getFilteredAttributes;
8163
$this->filterCustomAttribute = $filterCustomAttribute;
8264
}
8365

@@ -99,25 +81,18 @@ public function resolve(
9981
array $value = null,
10082
array $args = null
10183
) {
102-
$filterArgs = $args['filter'] ?? [];
84+
$filtersArgs = $args['filters'] ?? [];
10385

104-
$searchCriteriaBuilder = $this->attributeFilter->execute($filterArgs, $this->searchCriteriaBuilder);
105-
106-
$searchCriteriaBuilder = $searchCriteriaBuilder
107-
->addFilter('is_visible', true)
108-
->addFilter('backend_type', 'static', 'neq')
109-
->create();
110-
111-
$productCustomAttributes = $this->attributeRepository->getList(
112-
ProductAttributeInterface::ENTITY_TYPE_CODE,
113-
$searchCriteriaBuilder
114-
)->getItems();
86+
$productCustomAttributes = $this->getFilteredAttributes->execute(
87+
$filtersArgs,
88+
ProductAttributeInterface::ENTITY_TYPE_CODE
89+
);
11590

11691
$attributeCodes = array_map(
11792
function (AttributeInterface $customAttribute) {
11893
return $customAttribute->getAttributeCode();
11994
},
120-
$productCustomAttributes
95+
$productCustomAttributes['items']
12196
);
12297

12398
$filteredAttributeCodes = $this->filterCustomAttribute->execute(array_flip($attributeCodes));
@@ -141,15 +116,18 @@ function (AttributeInterface $customAttribute) {
141116
];
142117
}
143118

144-
return array_map(
145-
function (array $customAttribute) {
146-
return $this->getAttributeValue->execute(
147-
ProductAttributeInterface::ENTITY_TYPE_CODE,
148-
$customAttribute['attribute_code'],
149-
$customAttribute['value']
150-
);
151-
},
152-
$customAttributes
153-
);
119+
return [
120+
'items' => array_map(
121+
function (array $customAttribute) {
122+
return $this->getAttributeValue->execute(
123+
ProductAttributeInterface::ENTITY_TYPE_CODE,
124+
$customAttribute['attribute_code'],
125+
$customAttribute['value']
126+
);
127+
},
128+
$customAttributes
129+
),
130+
'errors' => $productCustomAttributes['errors']
131+
];
154132
}
155133
}

app/code/Magento/CatalogGraphQl/Test/Unit/DataProvider/Product/SearchCriteriaBuilderTest.php

+38-40
Original file line numberDiff line numberDiff line change
@@ -114,46 +114,44 @@ public function testBuild(): void
114114
->method('getAttribute')
115115
->with(Product::ENTITY, 'price')
116116
->willReturn($attributeInterface);
117-
$sortOrderList = ['relevance','_id'];
118-
$sortIncrementIndex = 0;
119-
foreach ($sortOrderList as $sortList) {
120-
$this->sortOrderBuilder->expects($this->at($sortIncrementIndex++))
121-
->method('setField')
122-
->with($sortList)
123-
->willReturnSelf();
124-
$this->sortOrderBuilder->expects($this->at($sortIncrementIndex++))
125-
->method('setDirection')
126-
->with('DESC')
127-
->willReturnSelf();
128-
$this->sortOrderBuilder->expects($this->at($sortIncrementIndex++))
129-
->method('create')
130-
->willReturn([]);
131-
}
132-
$filterOrderList = [1=>'search_term', 2=>'visibility'];
133-
$filterIncrementIndex = 0;
134-
foreach ($filterOrderList as $index => $filterList) {
135-
$this->filterBuilder->expects($this->at($filterIncrementIndex++))
136-
->method('setField')
137-
->with($filterList)
138-
->willReturnSelf();
139-
$this->filterBuilder->expects($this->at($filterIncrementIndex++))
140-
->method('setValue')
141-
->with('')
142-
->willReturnSelf();
143-
if ($index==2) {
144-
$this->filterBuilder->expects($this->at($filterIncrementIndex++))
145-
->method('setConditionType')
146-
->with('in')
147-
->willReturnSelf();
148-
} else {
149-
$this->filterBuilder->expects($this->at($filterIncrementIndex++))
150-
->method('setConditionType')
151-
->with('')
152-
->willReturnSelf();
153-
}
154-
155-
$this->filterBuilder->expects($this->at($filterIncrementIndex++))->method('create')->willReturn($filter);
156-
}
117+
$sortOrderList = ['relevance', '_id'];
118+
119+
$this->sortOrderBuilder->expects($this->exactly(2))
120+
->method('setField')
121+
->withConsecutive([$sortOrderList[0]], [$sortOrderList[1]])
122+
->willReturnSelf();
123+
124+
$this->sortOrderBuilder->expects($this->exactly(2))
125+
->method('setDirection')
126+
->with('DESC')
127+
->willReturnSelf();
128+
129+
$this->sortOrderBuilder->expects($this->exactly(2))
130+
->method('create')
131+
->willReturn([]);
132+
133+
$filterOrderList = ['search_term', 'visibility'];
134+
135+
$this->filterBuilder->expects($this->exactly(2))
136+
->method('setField')
137+
->withConsecutive([$filterOrderList[0]], [$filterOrderList[1]])
138+
->willReturnSelf();
139+
140+
$this->filterBuilder->expects($this->exactly(2))
141+
->method('setValue')
142+
->with('')
143+
->willReturnSelf();
144+
145+
$this->filterBuilder->expects($this->exactly(2))
146+
->method('setConditionType')
147+
->withConsecutive([''], ['in'])
148+
->willReturnSelf();
149+
150+
$this->filterBuilder
151+
->expects($this->exactly(2))
152+
->method('create')
153+
->willReturn($filter);
154+
157155
$this->filterGroupBuilder->expects($this->any())
158156
->method('addFilter')
159157
->with($filter)

0 commit comments

Comments
 (0)