Skip to content

Commit 50df6e9

Browse files
authored
LYNX-101: EAV GraphQL attributeForms query
1 parent a1d0d57 commit 50df6e9

File tree

11 files changed

+484
-4
lines changed

11 files changed

+484
-4
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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\Customer\Test\Fixture;
9+
10+
use Magento\Customer\Model\Attribute;
11+
use Magento\Customer\Model\ResourceModel\Attribute as ResourceModelAttribute;
12+
use Magento\Eav\Api\AttributeRepositoryInterface;
13+
use Magento\Eav\Model\AttributeFactory;
14+
use Magento\Framework\DataObject;
15+
use Magento\Framework\Exception\InvalidArgumentException;
16+
use Magento\TestFramework\Fixture\Api\DataMerger;
17+
use Magento\TestFramework\Fixture\Data\ProcessorInterface;
18+
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
19+
20+
class CustomerAttribute implements RevertibleDataFixtureInterface
21+
{
22+
private const DEFAULT_DATA = [
23+
'entity_type_id' => null,
24+
'attribute_id' => null,
25+
'attribute_code' => 'attribute%uniqid%',
26+
'default_frontend_label' => 'Attribute%uniqid%',
27+
'frontend_labels' => [],
28+
'frontend_input' => 'text',
29+
'backend_type' => 'varchar',
30+
'is_required' => false,
31+
'is_user_defined' => true,
32+
'note' => null,
33+
'backend_model' => null,
34+
'source_model' => null,
35+
'default_value' => null,
36+
'is_unique' => '0',
37+
'frontend_class' => null,
38+
'used_in_forms' => [],
39+
];
40+
41+
/**
42+
* @var DataMerger
43+
*/
44+
private DataMerger $dataMerger;
45+
46+
/**
47+
* @var ProcessorInterface
48+
*/
49+
private ProcessorInterface $processor;
50+
51+
/**
52+
* @var AttributeFactory
53+
*/
54+
private AttributeFactory $attributeFactory;
55+
56+
/**
57+
* @var ResourceModelAttribute
58+
*/
59+
private ResourceModelAttribute $resourceModelAttribute;
60+
61+
/**
62+
* @var AttributeRepositoryInterface
63+
*/
64+
private AttributeRepositoryInterface $attributeRepository;
65+
66+
/**
67+
* @param DataMerger $dataMerger
68+
* @param ProcessorInterface $processor
69+
* @param AttributeRepositoryInterface $attributeRepository
70+
* @param AttributeFactory $attributeFactory
71+
* @param ResourceModelAttribute $resourceModelAttribute
72+
*/
73+
public function __construct(
74+
DataMerger $dataMerger,
75+
ProcessorInterface $processor,
76+
AttributeRepositoryInterface $attributeRepository,
77+
AttributeFactory $attributeFactory,
78+
ResourceModelAttribute $resourceModelAttribute
79+
) {
80+
$this->dataMerger = $dataMerger;
81+
$this->processor = $processor;
82+
$this->attributeFactory = $attributeFactory;
83+
$this->resourceModelAttribute = $resourceModelAttribute;
84+
$this->attributeRepository = $attributeRepository;
85+
}
86+
87+
/**
88+
* @inheritdoc
89+
*/
90+
public function apply(array $data = []): ?DataObject
91+
{
92+
if (empty($data['entity_type_id'])) {
93+
throw new InvalidArgumentException(
94+
__(
95+
'"%field" value is required to create an attribute',
96+
[
97+
'field' => 'entity_type_id'
98+
]
99+
)
100+
);
101+
}
102+
103+
/** @var Attribute $attr */
104+
$attr = $this->attributeFactory->createAttribute(Attribute::class, self::DEFAULT_DATA);
105+
$mergedData = $this->processor->process($this, $this->dataMerger->merge(self::DEFAULT_DATA, $data));
106+
$attr->setData($mergedData);
107+
$this->resourceModelAttribute->save($attr);
108+
return $attr;
109+
}
110+
111+
/**
112+
* @inheritdoc
113+
*/
114+
public function revert(DataObject $data): void
115+
{
116+
$this->attributeRepository->deleteById($data['attribute_id']);
117+
}
118+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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\CustomerGraphQl\Model\Customer;
9+
10+
use Magento\Customer\Api\MetadataInterface;
11+
use Magento\EavGraphQl\Model\GetAttributesFormInterface;
12+
use Magento\EavGraphQl\Model\Uid;
13+
14+
/**
15+
* Attributes form provider for customer
16+
*/
17+
class GetAttributesForm implements GetAttributesFormInterface
18+
{
19+
/**
20+
* @var MetadataInterface
21+
*/
22+
private MetadataInterface $entity;
23+
24+
/**
25+
* @var Uid
26+
*/
27+
private Uid $uid;
28+
29+
/**
30+
* @var string
31+
*/
32+
private string $type;
33+
34+
/**
35+
* @param MetadataInterface $metadata
36+
* @param Uid $uid
37+
* @param string $type
38+
*/
39+
public function __construct(MetadataInterface $metadata, Uid $uid, string $type)
40+
{
41+
$this->entity = $metadata;
42+
$this->uid = $uid;
43+
$this->type = $type;
44+
}
45+
46+
/**
47+
* @inheritDoc
48+
*/
49+
public function execute(string $formCode): ?array
50+
{
51+
$attributes = [];
52+
foreach ($this->entity->getAttributes($formCode) as $attribute) {
53+
$attributes[] = $this->uid->encode($this->type, $attribute->getAttributeCode());
54+
}
55+
return $attributes;
56+
}
57+
}

app/code/Magento/CustomerGraphQl/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"magento/module-authorization": "*",
88
"magento/module-customer": "*",
99
"magento/module-eav": "*",
10+
"magento/module-eav-graph-ql": "*",
1011
"magento/module-graph-ql": "*",
1112
"magento/module-newsletter": "*",
1213
"magento/module-integration": "*",

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,24 @@
7272
</argument>
7373
</arguments>
7474
</type>
75+
<type name="Magento\EavGraphQl\Model\GetAttributesFormComposite">
76+
<arguments>
77+
<argument name="providers" xsi:type="array">
78+
<item name="customer" xsi:type="object">GetCustomerAttributesForm</item>
79+
<item name="customer_address" xsi:type="object">GetCustomerAddressAttributesForm</item>
80+
</argument>
81+
</arguments>
82+
</type>
83+
<virtualType name="GetCustomerAttributesForm" type="Magento\CustomerGraphQl\Model\Customer\GetAttributesForm">
84+
<arguments>
85+
<argument name="metadata" xsi:type="object">Magento\Customer\Api\CustomerMetadataInterface</argument>
86+
<argument name="type" xsi:type="string">customer</argument>
87+
</arguments>
88+
</virtualType>
89+
<virtualType name="GetCustomerAddressAttributesForm" type="Magento\CustomerGraphQl\Model\Customer\GetAttributesForm">
90+
<arguments>
91+
<argument name="metadata" xsi:type="object">Magento\Customer\Api\AddressMetadataInterface</argument>
92+
<argument name="type" xsi:type="string">customer_address</argument>
93+
</arguments>
94+
</virtualType>
7595
</config>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\Framework\Exception\LocalizedException;
11+
use Magento\Framework\Exception\NotFoundException;
12+
use Magento\Framework\Exception\RuntimeException;
13+
14+
/**
15+
* Format attributes form provider for GraphQL output
16+
*/
17+
class GetAttributesFormComposite implements GetAttributesFormInterface
18+
{
19+
/**
20+
* @var GetAttributesFormInterface[]
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+
* Returns right GetAttributesFormInterface to use for form with $formCode
34+
*
35+
* @param string $formCode
36+
* @return array
37+
* @throws RuntimeException
38+
*/
39+
public function execute(string $formCode): ?array
40+
{
41+
foreach ($this->providers as $provider) {
42+
if (!$provider instanceof GetAttributesFormInterface) {
43+
throw new RuntimeException(
44+
__('Configured attribute data providers should implement GetAttributesFormInterface')
45+
);
46+
}
47+
48+
try {
49+
return $provider->execute($formCode);
50+
} catch (LocalizedException $e) {
51+
continue;
52+
}
53+
}
54+
return null;
55+
}
56+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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\Framework\Exception\LocalizedException;
11+
12+
/**
13+
* Interface for getting form attributes metadata.
14+
*/
15+
interface GetAttributesFormInterface
16+
{
17+
/**
18+
* Retrieve all attributes filtered by form code
19+
*
20+
* @param string $formCode
21+
* @throws LocalizedException
22+
*/
23+
public function execute(string $formCode): ?array;
24+
}

app/code/Magento/EavGraphQl/Model/Output/GetAttributeData.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@ function (AttributeOptionInterface $option) use ($attribute) {
104104
'uid' => $this->uid->encode($value),
105105
'label' => $label,
106106
'value' => $value,
107-
'is_default' =>
108-
$attribute->getDefaultValue() ?
109-
in_array($value, explode(',', $attribute->getDefaultValue())): null
107+
'is_default' => $attribute->getDefaultValue() ?
108+
in_array($value, explode(',', $attribute->getDefaultValue())) : null
110109
];
111110
},
112111
$attribute->getOptions()

app/code/Magento/EavGraphQl/Model/Output/GetAttributeDataComposite.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
namespace Magento\EavGraphQl\Model\Output;
99

1010
use Magento\Eav\Api\Data\AttributeInterface;
11-
use Magento\EavGraphQl\Model\Uid;
1211
use Magento\Framework\Exception\RuntimeException;
1312

1413
/**
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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\Resolver;
9+
10+
use Magento\EavGraphQl\Model\GetAttributesFormComposite;
11+
use Magento\EavGraphQl\Model\GetAttributesMetadata;
12+
use Magento\Framework\GraphQl\Config\Element\Field;
13+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
14+
use Magento\Framework\GraphQl\Query\ResolverInterface;
15+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
16+
17+
/**
18+
* Load EAV attributes associated to a form
19+
*/
20+
class AttributesForm implements ResolverInterface
21+
{
22+
/**
23+
* @var GetAttributesFormComposite $getAttributesFormComposite
24+
*/
25+
private GetAttributesFormComposite $getAttributesFormComposite;
26+
27+
/**
28+
* @var GetAttributesMetadata
29+
*/
30+
private GetAttributesMetadata $getAttributesMetadata;
31+
32+
/**
33+
* @param GetAttributesFormComposite $providerFormComposite
34+
* @param GetAttributesMetadata $getAttributesMetadata
35+
*/
36+
public function __construct(
37+
GetAttributesFormComposite $providerFormComposite,
38+
GetAttributesMetadata $getAttributesMetadata
39+
) {
40+
$this->getAttributesFormComposite = $providerFormComposite;
41+
$this->getAttributesMetadata = $getAttributesMetadata;
42+
}
43+
44+
/**
45+
* @inheritdoc
46+
*/
47+
public function resolve(
48+
Field $field,
49+
$context,
50+
ResolveInfo $info,
51+
array $value = null,
52+
array $args = null
53+
) {
54+
if (empty($args['type'])) {
55+
throw new GraphQlInputException(__('Required parameter "%1" of type string.', 'type'));
56+
}
57+
58+
$attributes = $this->getAttributesFormComposite->execute($args['type']);
59+
if ($this->isAdminFormType($args['type']) || $attributes === null) {
60+
return [
61+
'items' => [],
62+
'errors' => [
63+
[
64+
'type' => 'ENTITY_NOT_FOUND',
65+
'message' => (string) __('Form "%form" could not be found.', ['form' => $args['type']])
66+
]
67+
]
68+
];
69+
}
70+
71+
return $this->getAttributesMetadata->execute(
72+
$attributes,
73+
(int)$context->getExtensionAttributes()->getStore()->getId()
74+
);
75+
}
76+
77+
/**
78+
* Check if passed form type is an admin form
79+
*
80+
* @param string $type
81+
* @return bool
82+
*/
83+
private function isAdminFormType(string $type): bool
84+
{
85+
return str_starts_with($type, 'adminhtml_');
86+
}
87+
}

0 commit comments

Comments
 (0)