Skip to content

Commit 1adcba2

Browse files
authored
LYNX-77: EAV GraphQL attribtuesMetadata query
1 parent 4a41ec4 commit 1adcba2

File tree

15 files changed

+782
-5
lines changed

15 files changed

+782
-5
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,7 @@ public function apply(array $data = []): ?DataObject
120120
public function revert(DataObject $data): void
121121
{
122122
$service = $this->serviceFactory->create(ProductRepositoryInterface::class, 'deleteById');
123-
$service->execute(
124-
[
125-
'sku' => $data->getSku()
126-
]
127-
);
123+
$service->execute(['sku' => $data->getSku()]);
128124
}
129125

130126
/**

app/code/Magento/CatalogGraphQl/etc/graphql/di.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,20 @@
208208
</argument>
209209
</arguments>
210210
</virtualType>
211+
<type name="Magento\EavGraphQl\Model\TypeResolver\AttributeMetadata">
212+
<arguments>
213+
<argument name="entityTypes" xsi:type="array">
214+
<item name="PRODUCT" xsi:type="string">CatalogAttributeMetadata</item>
215+
</argument>
216+
</arguments>
217+
</type>
218+
<type name="Magento\Framework\GraphQl\Schema\Type\Enum\DefaultDataMapper">
219+
<arguments>
220+
<argument name="map" xsi:type="array">
221+
<item name="AttributeEntityTypeEnum" xsi:type="array">
222+
<item name="catalog_product" xsi:type="string">catalog_product</item>
223+
</item>
224+
</argument>
225+
</arguments>
226+
</type>
211227
</config>

app/code/Magento/CatalogGraphQl/etc/schema.graphqls

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,7 @@ type SimpleWishlistItem implements WishlistItemInterface @doc(description: "Cont
531531

532532
type VirtualWishlistItem implements WishlistItemInterface @doc(description: "Contains a virtual product wish list item.") {
533533
}
534+
535+
enum AttributeEntityTypeEnum {
536+
CATALOG_PRODUCT
537+
}

app/code/Magento/CustomerGraphQl/etc/schema.graphqls

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,8 @@ enum CountryCodeEnum @doc(description: "The list of country codes.") {
425425
ZM @doc(description: "Zambia")
426426
ZW @doc(description: "Zimbabwe")
427427
}
428+
429+
enum AttributeEntityTypeEnum {
430+
CUSTOMER
431+
CUSTOMER_ADDRESS
432+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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\EavGraphQl\Model;
9+
10+
use Magento\Eav\Api\AttributeRepositoryInterface;
11+
use Magento\Eav\Api\Data\AttributeInterface;
12+
use Magento\EavGraphQl\Model\Output\GetAttributeDataInterface;
13+
use Magento\Framework\Api\SearchCriteriaBuilderFactory;
14+
use Magento\Framework\Exception\LocalizedException;
15+
use Magento\Framework\Exception\RuntimeException;
16+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
17+
18+
/**
19+
* Retrieve EAV attributes details
20+
*/
21+
class GetAttributesMetadata
22+
{
23+
/**
24+
* @var Uid
25+
*/
26+
private Uid $uid;
27+
28+
/**
29+
* @var AttributeRepositoryInterface
30+
*/
31+
private AttributeRepositoryInterface $attributeRepository;
32+
33+
/**
34+
* @var SearchCriteriaBuilderFactory
35+
*/
36+
private SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory;
37+
38+
/**
39+
* @var GetAttributeDataInterface
40+
*/
41+
private GetAttributeDataInterface $getAttributeData;
42+
43+
/**
44+
* @param AttributeRepositoryInterface $attributeRepository
45+
* @param SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory
46+
* @param Uid $uid
47+
* @param GetAttributeDataInterface $getAttributeData
48+
*/
49+
public function __construct(
50+
AttributeRepositoryInterface $attributeRepository,
51+
SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory,
52+
Uid $uid,
53+
GetAttributeDataInterface $getAttributeData
54+
) {
55+
$this->attributeRepository = $attributeRepository;
56+
$this->searchCriteriaBuilderFactory = $searchCriteriaBuilderFactory;
57+
$this->uid = $uid;
58+
$this->getAttributeData = $getAttributeData;
59+
}
60+
61+
/**
62+
* Get attribute metadata details
63+
*
64+
* @param string[] $uids
65+
* @param int $storeId
66+
* @return array
67+
* @throws RuntimeException
68+
*/
69+
public function execute(array $uids, int $storeId): array
70+
{
71+
if (empty($uids)) {
72+
return [];
73+
}
74+
75+
$codes = [];
76+
$errors = [];
77+
78+
foreach ($uids as $uid) {
79+
try {
80+
list($entityType, $attributeCode) = $this->uid->decode($uid);
81+
$codes[$entityType][] = $attributeCode;
82+
} catch (GraphQlInputException $exception) {
83+
$errors[] = [
84+
'type' => 'INCORRECT_UID',
85+
'message' => $exception->getMessage()
86+
];
87+
}
88+
}
89+
90+
$items = [];
91+
92+
foreach ($codes as $entityType => $attributeCodes) {
93+
$builder = $this->searchCriteriaBuilderFactory->create();
94+
$builder->addFilter('attribute_code', $attributeCodes, 'in');
95+
try {
96+
$attributes = $this->attributeRepository->getList($entityType, $builder->create())->getItems();
97+
} catch (LocalizedException $exception) {
98+
$errors[] = [
99+
'type' => 'ENTITY_NOT_FOUND',
100+
'message' => (string) __('Entity "%entity" could not be found.', ['entity' => $entityType])
101+
];
102+
continue;
103+
}
104+
105+
$notFoundCodes = array_diff($attributeCodes, $this->getCodes($attributes));
106+
foreach ($notFoundCodes as $notFoundCode) {
107+
$errors[] = [
108+
'type' => 'ATTRIBUTE_NOT_FOUND',
109+
'message' => (string) __('Attribute code "%code" could not be found.', ['code' => $notFoundCode])
110+
];
111+
}
112+
foreach ($attributes as $attribute) {
113+
$items[] = $this->getAttributeData->execute($attribute, $entityType, $storeId);
114+
}
115+
}
116+
117+
return [
118+
'items' => $items,
119+
'errors' => $errors
120+
];
121+
}
122+
123+
/**
124+
* Retrieve an array of codes from the array of attributes
125+
*
126+
* @param AttributeInterface[] $attributes
127+
* @return AttributeInterface[]
128+
*/
129+
private function getCodes(array $attributes): array
130+
{
131+
return array_map(
132+
function (AttributeInterface $attribute) {
133+
return $attribute->getAttributeCode();
134+
},
135+
$attributes
136+
);
137+
}
138+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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\EavGraphQl\Model\Output;
9+
10+
use Magento\Eav\Api\Data\AttributeInterface;
11+
use Magento\Eav\Api\Data\AttributeOptionInterface;
12+
use Magento\EavGraphQl\Model\Uid as AttributeUid;
13+
use Magento\Framework\Exception\RuntimeException;
14+
use Magento\Framework\GraphQl\Query\EnumLookup;
15+
use Magento\Framework\GraphQl\Query\Uid;
16+
17+
/**
18+
* Format attributes for GraphQL output
19+
*/
20+
class GetAttributeData implements GetAttributeDataInterface
21+
{
22+
/**
23+
* @var AttributeUid
24+
*/
25+
private AttributeUid $attributeUid;
26+
27+
/**
28+
* @var Uid
29+
*/
30+
private Uid $uid;
31+
32+
/**
33+
* @var EnumLookup
34+
*/
35+
private EnumLookup $enumLookup;
36+
37+
/**
38+
* @param AttributeUid $attributeUid
39+
* @param Uid $uid
40+
* @param EnumLookup $enumLookup
41+
*/
42+
public function __construct(AttributeUid $attributeUid, Uid $uid, EnumLookup $enumLookup)
43+
{
44+
$this->attributeUid = $attributeUid;
45+
$this->uid = $uid;
46+
$this->enumLookup = $enumLookup;
47+
}
48+
49+
/**
50+
* Retrieve formatted attribute data
51+
*
52+
* @param AttributeInterface $attribute
53+
* @param string $entityType
54+
* @param int $storeId
55+
* @return array
56+
* @throws RuntimeException
57+
*/
58+
public function execute(
59+
AttributeInterface $attribute,
60+
string $entityType,
61+
int $storeId
62+
): array {
63+
return [
64+
'uid' => $this->attributeUid->encode($entityType, $attribute->getAttributeCode()),
65+
'code' => $attribute->getAttributeCode(),
66+
'label' => $attribute->getStoreLabel($storeId),
67+
'sort_order' => $attribute->getPosition(),
68+
'entity_type' => $this->enumLookup->getEnumValueFromField(
69+
'AttributeEntityTypeEnum',
70+
$entityType
71+
),
72+
'frontend_input' => $this->enumLookup->getEnumValueFromField(
73+
'AttributeFrontendInputEnum',
74+
$attribute->getFrontendInput()
75+
),
76+
'is_required' => $attribute->getIsRequired(),
77+
'default_value' => $attribute->getDefaultValue(),
78+
'is_unique' => $attribute->getIsUnique(),
79+
'options' => $this->getOptions($attribute),
80+
'attribute' => $attribute
81+
];
82+
}
83+
84+
/**
85+
* Retrieve formatted attribute options
86+
*
87+
* @param AttributeInterface $attribute
88+
* @return array
89+
*/
90+
private function getOptions(AttributeInterface $attribute): array
91+
{
92+
if (!$attribute->getOptions()) {
93+
return [];
94+
}
95+
return array_map(
96+
function (AttributeOptionInterface $option) {
97+
return [
98+
'uid' => $this->uid->encode($option->getValue()), // TODO retrieve option id
99+
'label' => $option->getLabel(),
100+
'value' => $option->getValue(), // TODO test option labels and values for different stores
101+
'sort_order' => $option->getSortOrder(),
102+
];
103+
},
104+
$attribute->getOptions()
105+
);
106+
}
107+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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\EavGraphQl\Model\Output;
9+
10+
use Magento\Eav\Api\Data\AttributeInterface;
11+
use Magento\EavGraphQl\Model\Uid;
12+
use Magento\Framework\Exception\RuntimeException;
13+
14+
/**
15+
* Format attributes for GraphQL output
16+
*/
17+
class GetAttributeDataComposite implements GetAttributeDataInterface
18+
{
19+
/**
20+
* @var GetAttributeDataInterface[]
21+
*/
22+
private array $providers;
23+
24+
/**
25+
* @param array $providers
26+
*/
27+
public function __construct(array $providers = [])
28+
{
29+
$this->providers = $providers;
30+
}
31+
32+
/**
33+
* Retrieve formatted attribute data
34+
*
35+
* @param AttributeInterface $attribute
36+
* @param string $entityType
37+
* @param int $storeId
38+
* @return array
39+
* @throws RuntimeException
40+
*/
41+
public function execute(
42+
AttributeInterface $attribute,
43+
string $entityType,
44+
int $storeId
45+
): array {
46+
$data = [];
47+
48+
foreach ($this->providers as $provider) {
49+
if (!$provider instanceof GetAttributeDataInterface) {
50+
throw new RuntimeException(
51+
__('Configured attribute data providers should implement GetAttributeDataInterface')
52+
);
53+
}
54+
$data[] = $provider->execute($attribute, $entityType, $storeId);
55+
}
56+
57+
return array_merge([], ...$data);
58+
}
59+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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\EavGraphQl\Model\Output;
9+
10+
use Magento\Eav\Api\Data\AttributeInterface;
11+
use Magento\Framework\Exception\RuntimeException;
12+
13+
/**
14+
* Format attributes for GraphQL output
15+
*/
16+
interface GetAttributeDataInterface
17+
{
18+
/**
19+
* Retrieve formatted attribute metadata
20+
*
21+
* @param AttributeInterface $attribute
22+
* @param string $entityType
23+
* @param int $storeId
24+
* @return array
25+
* @throws RuntimeException
26+
*/
27+
public function execute(AttributeInterface $attribute, string $entityType, int $storeId): array;
28+
}

0 commit comments

Comments
 (0)