Skip to content

Commit 65fd385

Browse files
authored
LYNX-103: Customer GraphQL CustomerAttributeMetadata implementation of AttributeMetadataInterface (#98)
1 parent e27f246 commit 65fd385

File tree

13 files changed

+443
-43
lines changed

13 files changed

+443
-43
lines changed

app/code/Magento/Customer/Test/Fixture/CustomerAttribute.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class CustomerAttribute implements RevertibleDataFixtureInterface
3939
'sort_order' => null,
4040
'attribute_set_id' => null,
4141
'attribute_group_id' => null,
42+
'input_filter' => null,
43+
'multiline_count' => 0,
44+
'validate_rules' => null
4245
];
4346

4447
/**
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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\Output;
9+
10+
use Magento\Customer\Api\MetadataInterface;
11+
use Magento\Customer\Model\Data\ValidationRule;
12+
use Magento\Eav\Api\Data\AttributeInterface;
13+
use Magento\EavGraphQl\Model\Output\GetAttributeDataInterface;
14+
use Magento\EavGraphQl\Model\Uid as AttributeUid;
15+
use Magento\Framework\Exception\LocalizedException;
16+
use Magento\Framework\Exception\NoSuchEntityException;
17+
use Magento\Framework\GraphQl\Query\EnumLookup;
18+
use Magento\Framework\GraphQl\Query\Uid;
19+
20+
/**
21+
* Format attributes metadata for GraphQL output
22+
*/
23+
class CustomerAttributeMetadata implements GetAttributeDataInterface
24+
{
25+
/**
26+
* @var AttributeUid
27+
*/
28+
private AttributeUid $attributeUid;
29+
30+
/**
31+
* @var Uid
32+
*/
33+
private Uid $uid;
34+
35+
/**
36+
* @var EnumLookup
37+
*/
38+
private EnumLookup $enumLookup;
39+
40+
/**
41+
* @var MetadataInterface
42+
*/
43+
private MetadataInterface $metadata;
44+
45+
/**
46+
* @var string
47+
*/
48+
private string $entityType;
49+
50+
/**
51+
* @param AttributeUid $attributeUid
52+
* @param Uid $uid
53+
* @param EnumLookup $enumLookup
54+
* @param MetadataInterface $metadata
55+
* @param string $entityType
56+
*/
57+
public function __construct(
58+
AttributeUid $attributeUid,
59+
Uid $uid,
60+
EnumLookup $enumLookup,
61+
MetadataInterface $metadata,
62+
string $entityType
63+
) {
64+
$this->attributeUid = $attributeUid;
65+
$this->uid = $uid;
66+
$this->enumLookup = $enumLookup;
67+
$this->metadata = $metadata;
68+
$this->entityType = $entityType;
69+
}
70+
71+
/**
72+
* Retrieve formatted attribute data
73+
*
74+
* @param AttributeInterface $attribute
75+
* @param string $entityType
76+
* @param int $storeId
77+
* @return array
78+
* @throws LocalizedException
79+
* @throws NoSuchEntityException
80+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
81+
*/
82+
public function execute(
83+
AttributeInterface $attribute,
84+
string $entityType,
85+
int $storeId
86+
): array {
87+
if ($entityType !== $this->entityType) {
88+
return [];
89+
}
90+
91+
$attributeMetadata = $this->metadata->getAttributeMetadata($attribute->getAttributeCode());
92+
$data = [];
93+
94+
$validationRules = array_map(function (ValidationRule $validationRule) {
95+
return [
96+
'name' => $this->enumLookup->getEnumValueFromField(
97+
'ValidationRuleEnum',
98+
strtoupper($validationRule->getName())
99+
),
100+
'value' => $validationRule->getValue()
101+
];
102+
}, $attributeMetadata->getValidationRules());
103+
104+
if ($attributeMetadata->isVisible()) {
105+
$data = [
106+
'input_filter' =>
107+
empty($attributeMetadata->getInputFilter())
108+
? 'NONE'
109+
: $this->enumLookup->getEnumValueFromField(
110+
'InputFilterEnum',
111+
strtoupper($attributeMetadata->getInputFilter())
112+
),
113+
'multiline_count' => $attributeMetadata->getMultilineCount(),
114+
'sort_order' => $attributeMetadata->getSortOrder(),
115+
'validate_rules' => $validationRules,
116+
'attributeMetadata' => $attributeMetadata
117+
];
118+
}
119+
120+
return $data;
121+
}
122+
}

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,34 @@
4040
</argument>
4141
</arguments>
4242
</type>
43+
<type name="Magento\EavGraphQl\Model\TypeResolver\AttributeMetadata">
44+
<arguments>
45+
<argument name="entityTypes" xsi:type="array">
46+
<item name="CUSTOMER" xsi:type="string">CustomerAttributeMetadata</item>
47+
<item name="CUSTOMER_ADDRESS" xsi:type="string">CustomerAttributeMetadata</item>
48+
</argument>
49+
</arguments>
50+
</type>
51+
<type name="Magento\EavGraphQl\Model\Output\GetAttributeDataComposite">
52+
<arguments>
53+
<argument name="providers" xsi:type="array">
54+
<item name="customer" xsi:type="object">GetCustomerAttributesMetadata</item>
55+
<item name="customer_address" xsi:type="object">GetCustomerAddressAttributesMetadata</item>
56+
</argument>
57+
</arguments>
58+
</type>
59+
<virtualType name="GetCustomerAttributesMetadata" type="Magento\CustomerGraphQl\Model\Output\CustomerAttributeMetadata">
60+
<arguments>
61+
<argument name="metadata" xsi:type="object">Magento\Customer\Model\Metadata\CustomerMetadata</argument>
62+
<argument name="entityType" xsi:type="string">customer</argument>
63+
</arguments>
64+
</virtualType>
65+
<virtualType name="GetCustomerAddressAttributesMetadata" type="Magento\CustomerGraphQl\Model\Output\CustomerAttributeMetadata">
66+
<arguments>
67+
<argument name="metadata" xsi:type="object">Magento\Customer\Model\Metadata\AddressMetadata</argument>
68+
<argument name="entityType" xsi:type="string">customer_address</argument>
69+
</arguments>
70+
</virtualType>
4371
<!-- Validate input customer data -->
4472
<type name="Magento\CustomerGraphQl\Model\Customer\ValidateCustomerData">
4573
<arguments>
@@ -69,6 +97,24 @@
6997
<item name="customer" xsi:type="string">customer</item>
7098
<item name="customer_address" xsi:type="string">customer_address</item>
7199
</item>
100+
<item name="InputFilterEnum" xsi:type="array">
101+
<item name="none" xsi:type="string">NONE</item>
102+
<item name="date" xsi:type="string">DATE</item>
103+
<item name="trim" xsi:type="string">TRIM</item>
104+
<item name="striptags" xsi:type="string">STRIPTAGS</item>
105+
<item name="escapehtml" xsi:type="string">ESCAPEHTML</item>
106+
</item>
107+
<item name="ValidationRuleEnum" xsi:type="array">
108+
<item name="date_range_max" xsi:type="string">DATE_RANGE_MAX</item>
109+
<item name="date_range_min" xsi:type="string">DATE_RANGE_MIN</item>
110+
<item name="file_extensions" xsi:type="string">FILE_EXTENSIONS</item>
111+
<item name="input_validation" xsi:type="string">INPUT_VALIDATION</item>
112+
<item name="max_text_length" xsi:type="string">MAX_TEXT_LENGTH</item>
113+
<item name="min_text_length" xsi:type="string">MIN_TEXT_LENGTH</item>
114+
<item name="max_file_size" xsi:type="string">MAX_FILE_SIZE</item>
115+
<item name="max_image_height" xsi:type="string">MAX_IMAGE_HEGHT</item>
116+
<item name="max_image_width" xsi:type="string">MAX_IMAGE_WIDTH</item>
117+
</item>
72118
</argument>
73119
</arguments>
74120
</type>

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,35 @@ enum AttributeEntityTypeEnum {
431431
CUSTOMER
432432
CUSTOMER_ADDRESS
433433
}
434+
435+
type CustomerAttributeMetadata implements AttributeMetadataInterface @doc(description: "Customer attribute metadata.") {
436+
input_filter: InputFilterEnum @doc(description: "The template used for the input of the attribute (e.g., 'date').")
437+
multiline_count: Int @doc(description: "The number of lines of the attribute value.")
438+
sort_order: Int @doc(description: "The position of the attribute in the form.")
439+
validate_rules: [ValidationRule] @doc(description: "The validation rules of the attribute value.")
440+
}
441+
442+
enum InputFilterEnum @doc(description: "List of templates/filters applied to customer attribute input.") {
443+
NONE @doc(description: "There are no templates or filters to be applied.")
444+
DATE @doc(description: "Forces attribute input to follow the date format.")
445+
TRIM @doc(description: "Strip whitespace (or other characters) from the beginning and end of the input.")
446+
STRIPTAGS @doc(description: "Strip HTML Tags.")
447+
ESCAPEHTML @doc(description: "Escape HTML Entities.")
448+
}
449+
450+
type ValidationRule @doc(description: "Defines a customer attribute validation rule.") {
451+
name: ValidationRuleEnum @doc(description: "Validation rule name applied to a customer attribute.")
452+
value: String @doc(description: "Validation rule value.")
453+
}
454+
455+
enum ValidationRuleEnum @doc(description: "List of validation rule names applied to a customer attribute.") {
456+
DATE_RANGE_MAX
457+
DATE_RANGE_MIN
458+
FILE_EXTENSIONS
459+
INPUT_VALIDATION
460+
MAX_TEXT_LENGTH
461+
MIN_TEXT_LENGTH
462+
MAX_FILE_SIZE
463+
MAX_IMAGE_HEIGHT
464+
MAX_IMAGE_WIDTH
465+
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ type AttributesFormOutput @doc(description: "Metadata of EAV attributes associat
113113
errors: [AttributeMetadataError!]! @doc(description: "Errors of retrieving certain attributes metadata.")
114114
}
115115

116-
117116
interface AttributeValueInterface @typeResolver(class: "Magento\\EavGraphQl\\Model\\TypeResolver\\AttributeValue") {
118117
uid: ID! @doc(description: "The unique ID of an attribute value.")
119118
code: String! @doc(description: "The attribute code.")

dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/Attribute/BooleanTest.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
namespace Magento\GraphQl\Customer\Attribute;
99

1010
use Magento\Customer\Api\CustomerMetadataInterface;
11-
use Magento\Eav\Api\Data\AttributeInterface;
12-
use Magento\Eav\Test\Fixture\Attribute;
11+
use Magento\Customer\Api\Data\AttributeMetadataInterface;
12+
use Magento\Customer\Test\Fixture\CustomerAttribute;
1313
use Magento\EavGraphQl\Model\Uid;
1414
use Magento\TestFramework\Fixture\DataFixture;
1515
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
@@ -49,7 +49,7 @@ class BooleanTest extends GraphQlAbstract
4949

5050
#[
5151
DataFixture(
52-
Attribute::class,
52+
CustomerAttribute::class,
5353
[
5454
'entity_type_id' => CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
5555
'frontend_input' => 'boolean',
@@ -60,7 +60,7 @@ class BooleanTest extends GraphQlAbstract
6060
]
6161
public function testMetadata(): void
6262
{
63-
/** @var AttributeInterface $attribute */
63+
/** @var AttributeMetadataInterface $attribute */
6464
$attribute = DataFixtureStorageManager::getStorage()->get('attribute');
6565

6666
$uid = Bootstrap::getObjectManager()->get(Uid::class)->encode(
@@ -77,7 +77,7 @@ public function testMetadata(): void
7777
[
7878
'uid' => $uid,
7979
'code' => $attribute->getAttributeCode(),
80-
'label' => $attribute->getDefaultFrontendLabel(),
80+
'label' => $attribute->getFrontendLabel(),
8181
'entity_type' => 'CUSTOMER',
8282
'frontend_input' => 'BOOLEAN',
8383
'is_required' => false,
@@ -95,7 +95,6 @@ public function testMetadata(): void
9595
'value' => '0'
9696
]
9797
]
98-
9998
]
10099
],
101100
'errors' => []
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\GraphQl\Customer\Attribute;
9+
10+
use Magento\Customer\Api\AddressMetadataInterface;
11+
use Magento\Customer\Api\Data\AttributeMetadataInterface;
12+
use Magento\Customer\Test\Fixture\CustomerAttribute;
13+
use Magento\EavGraphQl\Model\Uid;
14+
use Magento\TestFramework\Fixture\DataFixture;
15+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
16+
use Magento\TestFramework\Helper\Bootstrap;
17+
use Magento\TestFramework\TestCase\GraphQlAbstract;
18+
19+
/**
20+
* Test catalog EAV attributes metadata retrieval via GraphQL API
21+
*/
22+
class CustomerAddressAttributesTest extends GraphQlAbstract
23+
{
24+
private const QUERY = <<<QRY
25+
{
26+
attributesMetadata(attributes: [{attribute_code: "%s", entity_type: "%s"}]) {
27+
items {
28+
uid
29+
code
30+
label
31+
entity_type
32+
frontend_input
33+
is_required
34+
default_value
35+
is_unique
36+
... on CustomerAttributeMetadata {
37+
input_filter
38+
validate_rules {
39+
name
40+
value
41+
}
42+
}
43+
}
44+
errors {
45+
type
46+
message
47+
}
48+
}
49+
}
50+
QRY;
51+
52+
#[
53+
DataFixture(
54+
CustomerAttribute::class,
55+
[
56+
'entity_type_id' => AddressMetadataInterface::ATTRIBUTE_SET_ID_ADDRESS,
57+
'frontend_input' => 'date',
58+
'default_value' => '2023-03-22 00:00:00',
59+
'input_filter' => 'DATE',
60+
'validate_rules' =>
61+
'{"DATE_RANGE_MIN":"1679443200","DATE_RANGE_MAX":"1679875200","INPUT_VALIDATION":"DATE"}'
62+
],
63+
'attribute'
64+
),
65+
]
66+
public function testMetadata(): void
67+
{
68+
/** @var AttributeMetadataInterface $attribute */
69+
$attribute = DataFixtureStorageManager::getStorage()->get('attribute');
70+
71+
$uid = Bootstrap::getObjectManager()->get(Uid::class)->encode(
72+
'customer_address',
73+
$attribute->getAttributeCode()
74+
);
75+
76+
$formattedValidationRules = Bootstrap::getObjectManager()->get(FormatValidationRulesCommand::class)->execute(
77+
$attribute->getValidationRules()
78+
);
79+
80+
$result = $this->graphQlQuery(
81+
sprintf(self::QUERY, $attribute->getAttributeCode(), 'customer_address')
82+
);
83+
84+
$this->assertEquals(
85+
[
86+
'attributesMetadata' => [
87+
'items' => [
88+
[
89+
'uid' => $uid,
90+
'code' => $attribute->getAttributeCode(),
91+
'label' => $attribute->getFrontendLabel(),
92+
'entity_type' => 'CUSTOMER_ADDRESS',
93+
'frontend_input' => 'DATE',
94+
'is_required' => false,
95+
'default_value' => $attribute->getDefaultValue(),
96+
'is_unique' => false,
97+
'input_filter' => $attribute->getInputFilter(),
98+
'validate_rules' => $formattedValidationRules
99+
]
100+
],
101+
'errors' => []
102+
]
103+
],
104+
$result
105+
);
106+
}
107+
}

0 commit comments

Comments
 (0)