Skip to content

Commit 2c39ba3

Browse files
ENGCOM-5606: #271 [My Account] Add support of Customer attributes #489
- Merge Pull Request magento/graphql-ce#489 from magento/graphql-ce:feature/271-Customer-Attributes-Validation - Merged commits: 1. dba9800 2. 7f6718d 3. 3735e91 4. 342675a 5. e177801 6. 9b5b0a1 7. 9f1ba1a 8. 670116c 9. 40e2363 10. d071027 11. b4db736 12. 4b7acdc 13. 48f1891 14. 3641627 15. ef078b6 16. 1c65121 17. cc69055 18. 7ee6a1a 19. f358267 20. eb48f44 21. 2eb7c15 22. 7ca7acc 23. 1c30336 24. 4382c3a 25. da8d6ac 26. 0b4c496 27. 5ae0633
2 parents c6427d1 + 5ae0633 commit 2c39ba3

File tree

6 files changed

+277
-7
lines changed

6 files changed

+277
-7
lines changed

app/code/Magento/CustomerGraphQl/Model/Customer/CreateCustomerAccount.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Magento\Framework\Api\DataObjectHelper;
1414
use Magento\Framework\Exception\LocalizedException;
1515
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
16+
use Magento\Framework\Reflection\DataObjectProcessor;
1617
use Magento\Store\Api\Data\StoreInterface;
1718

1819
/**
@@ -41,21 +42,39 @@ class CreateCustomerAccount
4142
private $changeSubscriptionStatus;
4243

4344
/**
45+
* @var ValidateCustomerData
46+
*/
47+
private $validateCustomerData;
48+
49+
/**
50+
* @var DataObjectProcessor
51+
*/
52+
private $dataObjectProcessor;
53+
54+
/**
55+
* CreateCustomerAccount constructor.
56+
*
4457
* @param DataObjectHelper $dataObjectHelper
4558
* @param CustomerInterfaceFactory $customerFactory
4659
* @param AccountManagementInterface $accountManagement
4760
* @param ChangeSubscriptionStatus $changeSubscriptionStatus
61+
* @param DataObjectProcessor $dataObjectProcessor
62+
* @param ValidateCustomerData $validateCustomerData
4863
*/
4964
public function __construct(
5065
DataObjectHelper $dataObjectHelper,
5166
CustomerInterfaceFactory $customerFactory,
5267
AccountManagementInterface $accountManagement,
53-
ChangeSubscriptionStatus $changeSubscriptionStatus
68+
ChangeSubscriptionStatus $changeSubscriptionStatus,
69+
DataObjectProcessor $dataObjectProcessor,
70+
ValidateCustomerData $validateCustomerData
5471
) {
5572
$this->dataObjectHelper = $dataObjectHelper;
5673
$this->customerFactory = $customerFactory;
5774
$this->accountManagement = $accountManagement;
5875
$this->changeSubscriptionStatus = $changeSubscriptionStatus;
76+
$this->validateCustomerData = $validateCustomerData;
77+
$this->dataObjectProcessor = $dataObjectProcessor;
5978
}
6079

6180
/**
@@ -91,6 +110,15 @@ public function execute(array $data, StoreInterface $store): CustomerInterface
91110
private function createAccount(array $data, StoreInterface $store): CustomerInterface
92111
{
93112
$customerDataObject = $this->customerFactory->create();
113+
/**
114+
* Add required attributes for customer entity
115+
*/
116+
$requiredDataAttributes = $this->dataObjectProcessor->buildOutputDataArray(
117+
$customerDataObject,
118+
CustomerInterface::class
119+
);
120+
$data = array_merge($requiredDataAttributes, $data);
121+
$this->validateCustomerData->execute($data);
94122
$this->dataObjectHelper->populateWithArray(
95123
$customerDataObject,
96124
$data,
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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\CustomerMetadataManagementInterface;
11+
use Magento\Customer\Api\Data\CustomerInterface;
12+
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
13+
use Magento\Eav\Model\AttributeRepository;
14+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
15+
use Magento\Framework\Api\SearchCriteriaBuilder;
16+
use Magento\Framework\Exception\InputException;
17+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
18+
use Magento\Framework\Reflection\DataObjectProcessor;
19+
20+
/**
21+
* Get allowed address attributes
22+
*/
23+
class GetAllowedCustomerAttributes
24+
{
25+
/**
26+
* @var AttributeRepository
27+
*/
28+
private $attributeRepository;
29+
30+
/**
31+
* @var CustomerInterfaceFactory\
32+
*/
33+
private $customerDataFactory;
34+
35+
/**
36+
* @var DataObjectProcessor
37+
*/
38+
private $dataObjectProcessor;
39+
40+
/**
41+
* @var SearchCriteriaBuilder
42+
*/
43+
private $searchCriteriaBuilder;
44+
45+
/**
46+
* GetAllowedCustomerAttributes constructor.
47+
*
48+
* @param AttributeRepository $attributeRepository
49+
* @param CustomerInterfaceFactory $customerDataFactory
50+
* @param DataObjectProcessor $dataObjectProcessor
51+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
52+
*/
53+
public function __construct(
54+
AttributeRepository $attributeRepository,
55+
CustomerInterfaceFactory $customerDataFactory,
56+
DataObjectProcessor $dataObjectProcessor,
57+
SearchCriteriaBuilder $searchCriteriaBuilder
58+
) {
59+
$this->attributeRepository = $attributeRepository;
60+
$this->customerDataFactory = $customerDataFactory;
61+
$this->dataObjectProcessor = $dataObjectProcessor;
62+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
63+
}
64+
65+
/**
66+
* Get allowed customer attributes
67+
*
68+
* @param array $attributeKeys
69+
*
70+
* @throws GraphQlInputException
71+
*
72+
* @return AbstractAttribute[]
73+
*/
74+
public function execute($attributeKeys): array
75+
{
76+
$this->searchCriteriaBuilder->addFilter('attribute_code', $attributeKeys, 'in');
77+
$searchCriteria = $this->searchCriteriaBuilder->create();
78+
try {
79+
$attributesSearchResult = $this->attributeRepository->getList(
80+
CustomerMetadataManagementInterface::ENTITY_TYPE_CUSTOMER,
81+
$searchCriteria
82+
);
83+
} catch (InputException $exception) {
84+
throw new GraphQlInputException(__($exception->getMessage()));
85+
}
86+
87+
/** @var AbstractAttribute[] $attributes */
88+
$attributes = $attributesSearchResult->getItems();
89+
90+
foreach ($attributes as $index => $attribute) {
91+
if (false === $attribute->getIsVisibleOnFront()) {
92+
unset($attributes[$index]);
93+
}
94+
}
95+
96+
return $attributes;
97+
}
98+
}

app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerAccount.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77

88
namespace Magento\CustomerGraphQl\Model\Customer;
99

10+
use Magento\Customer\Api\Data\CustomerInterface;
11+
use Magento\Framework\Exception\NoSuchEntityException;
1012
use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException;
1113
use Magento\Framework\GraphQl\Exception\GraphQlAuthenticationException;
1214
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
13-
use Magento\Customer\Api\Data\CustomerInterface;
15+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
1416
use Magento\Framework\Api\DataObjectHelper;
1517
use Magento\Store\Api\Data\StoreInterface;
1618

@@ -41,6 +43,11 @@ class UpdateCustomerAccount
4143
*/
4244
private $changeSubscriptionStatus;
4345

46+
/**
47+
* @var ValidateCustomerData
48+
*/
49+
private $validateCustomerData;
50+
4451
/**
4552
* @var array
4653
*/
@@ -51,24 +58,27 @@ class UpdateCustomerAccount
5158
* @param CheckCustomerPassword $checkCustomerPassword
5259
* @param DataObjectHelper $dataObjectHelper
5360
* @param ChangeSubscriptionStatus $changeSubscriptionStatus
61+
* @param ValidateCustomerData $validateCustomerData
5462
* @param array $restrictedKeys
5563
*/
5664
public function __construct(
5765
SaveCustomer $saveCustomer,
5866
CheckCustomerPassword $checkCustomerPassword,
5967
DataObjectHelper $dataObjectHelper,
6068
ChangeSubscriptionStatus $changeSubscriptionStatus,
69+
ValidateCustomerData $validateCustomerData,
6170
array $restrictedKeys = []
6271
) {
6372
$this->saveCustomer = $saveCustomer;
6473
$this->checkCustomerPassword = $checkCustomerPassword;
6574
$this->dataObjectHelper = $dataObjectHelper;
6675
$this->restrictedKeys = $restrictedKeys;
6776
$this->changeSubscriptionStatus = $changeSubscriptionStatus;
77+
$this->validateCustomerData = $validateCustomerData;
6878
}
6979

7080
/**
71-
* Update customer account data
81+
* Update customer account
7282
*
7383
* @param CustomerInterface $customer
7484
* @param array $data
@@ -77,7 +87,7 @@ public function __construct(
7787
* @throws GraphQlAlreadyExistsException
7888
* @throws GraphQlAuthenticationException
7989
* @throws GraphQlInputException
80-
* @throws \Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException
90+
* @throws GraphQlNoSuchEntityException
8191
*/
8292
public function execute(CustomerInterface $customer, array $data, StoreInterface $store): void
8393
{
@@ -89,11 +99,15 @@ public function execute(CustomerInterface $customer, array $data, StoreInterface
8999
$this->checkCustomerPassword->execute($data['password'], (int)$customer->getId());
90100
$customer->setEmail($data['email']);
91101
}
92-
102+
$this->validateCustomerData->execute($data);
93103
$filteredData = array_diff_key($data, array_flip($this->restrictedKeys));
94104
$this->dataObjectHelper->populateWithArray($customer, $filteredData, CustomerInterface::class);
95105

96-
$customer->setStoreId($store->getId());
106+
try {
107+
$customer->setStoreId($store->getId());
108+
} catch (NoSuchEntityException $exception) {
109+
throw new GraphQlNoSuchEntityException(__($exception->getMessage()), $exception);
110+
}
97111

98112
$this->saveCustomer->execute($customer);
99113

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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\Framework\GraphQl\Exception\GraphQlInputException;
11+
12+
/**
13+
* Class ValidateCustomerData
14+
*/
15+
class ValidateCustomerData
16+
{
17+
/**
18+
* Get allowed/required customer attributes
19+
*
20+
* @var GetAllowedCustomerAttributes
21+
*/
22+
private $getAllowedCustomerAttributes;
23+
24+
/**
25+
* ValidateCustomerData constructor.
26+
*
27+
* @param GetAllowedCustomerAttributes $getAllowedCustomerAttributes
28+
*/
29+
public function __construct(GetAllowedCustomerAttributes $getAllowedCustomerAttributes)
30+
{
31+
$this->getAllowedCustomerAttributes = $getAllowedCustomerAttributes;
32+
}
33+
34+
/**
35+
* Validate customer data
36+
*
37+
* @param array $customerData
38+
*
39+
* @return void
40+
*
41+
* @throws GraphQlInputException
42+
*/
43+
public function execute(array $customerData): void
44+
{
45+
$attributes = $this->getAllowedCustomerAttributes->execute(array_keys($customerData));
46+
$errorInput = [];
47+
48+
foreach ($attributes as $attributeInfo) {
49+
if ($attributeInfo->getIsRequired()
50+
&& (!isset($customerData[$attributeInfo->getAttributeCode()])
51+
|| $customerData[$attributeInfo->getAttributeCode()] == '')
52+
) {
53+
$errorInput[] = $attributeInfo->getDefaultFrontendLabel();
54+
}
55+
}
56+
57+
if ($errorInput) {
58+
throw new GraphQlInputException(
59+
__('Required parameters are missing: %1', [implode(', ', $errorInput)])
60+
);
61+
}
62+
}
63+
}

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public function testCreateCustomerIfInputDataIsEmpty()
139139

140140
/**
141141
* @expectedException \Exception
142-
* @expectedExceptionMessage The customer email is missing. Enter and try again.
142+
* @expectedExceptionMessage Required parameters are missing: Email
143143
*/
144144
public function testCreateCustomerIfEmailMissed()
145145
{
@@ -241,6 +241,41 @@ public function testCreateCustomerIfPassedAttributeDosNotExistsInCustomerInput()
241241
$this->graphQlMutation($query);
242242
}
243243

244+
/**
245+
* @expectedException \Exception
246+
* @expectedExceptionMessage Required parameters are missing: First Name
247+
*/
248+
public function testCreateCustomerIfNameEmpty()
249+
{
250+
$newEmail = 'customer_created' . rand(1, 2000000) . '@example.com';
251+
$newFirstname = '';
252+
$newLastname = 'Rowe';
253+
$currentPassword = 'test123#';
254+
255+
$query = <<<QUERY
256+
mutation {
257+
createCustomer(
258+
input: {
259+
email: "{$newEmail}"
260+
firstname: "{$newFirstname}"
261+
lastname: "{$newLastname}"
262+
password: "{$currentPassword}"
263+
is_subscribed: true
264+
}
265+
) {
266+
customer {
267+
id
268+
firstname
269+
lastname
270+
email
271+
is_subscribed
272+
}
273+
}
274+
}
275+
QUERY;
276+
$this->graphQlMutation($query);
277+
}
278+
244279
public function tearDown()
245280
{
246281
$newEmail = 'new_customer@example.com';

0 commit comments

Comments
 (0)