Skip to content

Commit 58de8cb

Browse files
ENGCOM-3668: GraphQL-57: Manage Address Book #194
- Merge Pull Request magento/graphql-ce#194 from pfantini/graphql-ce:57-manage-address-book - Merged commits: 1. 09c9e6b 2. fbefe29 3. 7aaba83 4. 47adffd 5. 9041bdb 6. cfc82be 7. 6c6fdbc 8. 6436bcb 9. bfd4fc1 10. 71d242c 11. 468b290 12. c6de6a1 13. af50831 14. cbe1ea3 15. ec4c985 16. b0ab652 17. f41405d 18. 2894aaa 19. b41627b
2 parents b1d3061 + b41627b commit 58de8cb

25 files changed

+1889
-147
lines changed
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\CustomerGraphQl\Model\Customer\Address;
9+
10+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
11+
12+
/**
13+
* Customer address create data validator
14+
*/
15+
class CustomerAddressCreateDataValidator
16+
{
17+
/**
18+
* @var GetAllowedAddressAttributes
19+
*/
20+
private $getAllowedAddressAttributes;
21+
22+
/**
23+
* @param GetAllowedAddressAttributes $getAllowedAddressAttributes
24+
*/
25+
public function __construct(GetAllowedAddressAttributes $getAllowedAddressAttributes)
26+
{
27+
$this->getAllowedAddressAttributes = $getAllowedAddressAttributes;
28+
}
29+
30+
/**
31+
* Validate customer address create data
32+
*
33+
* @param array $addressData
34+
* @return void
35+
* @throws GraphQlInputException
36+
*/
37+
public function validate(array $addressData): void
38+
{
39+
$attributes = $this->getAllowedAddressAttributes->execute();
40+
$errorInput = [];
41+
42+
foreach ($attributes as $attributeName => $attributeInfo) {
43+
if ($attributeInfo->getIsRequired()
44+
&& (!isset($addressData[$attributeName]) || empty($addressData[$attributeName]))
45+
) {
46+
$errorInput[] = $attributeName;
47+
}
48+
}
49+
50+
if ($errorInput) {
51+
throw new GraphQlInputException(
52+
__('Required parameters are missing: %1', [implode(', ', $errorInput)])
53+
);
54+
}
55+
}
56+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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\Address;
9+
10+
use Magento\Customer\Api\Data\AddressInterface;
11+
use Magento\Customer\Api\Data\CustomerInterface;
12+
use Magento\Framework\Api\CustomAttributesDataInterface;
13+
use Magento\Customer\Api\AddressRepositoryInterface;
14+
use Magento\Customer\Model\ResourceModel\Customer as CustomerResourceModel;
15+
use Magento\Customer\Model\CustomerFactory;
16+
use Magento\Framework\Webapi\ServiceOutputProcessor;
17+
use Magento\Framework\Serialize\SerializerInterface;
18+
19+
/**
20+
* Customer Address field data provider, used for GraphQL request processing.
21+
*/
22+
class CustomerAddressDataProvider
23+
{
24+
/**
25+
* @var ServiceOutputProcessor
26+
*/
27+
private $serviceOutputProcessor;
28+
29+
/**
30+
* @var SerializerInterface
31+
*/
32+
private $jsonSerializer;
33+
34+
/**
35+
* @var CustomerResourceModel
36+
*/
37+
private $customerResourceModel;
38+
39+
/**
40+
* @var CustomerFactory
41+
*/
42+
private $customerFactory;
43+
44+
/**
45+
* @param ServiceOutputProcessor $serviceOutputProcessor
46+
* @param SerializerInterface $jsonSerializer
47+
* @param CustomerResourceModel $customerResourceModel
48+
* @param CustomerFactory $customerFactory
49+
*/
50+
public function __construct(
51+
ServiceOutputProcessor $serviceOutputProcessor,
52+
SerializerInterface $jsonSerializer,
53+
CustomerResourceModel $customerResourceModel,
54+
CustomerFactory $customerFactory
55+
) {
56+
$this->serviceOutputProcessor = $serviceOutputProcessor;
57+
$this->jsonSerializer = $jsonSerializer;
58+
$this->customerResourceModel = $customerResourceModel;
59+
$this->customerFactory = $customerFactory;
60+
}
61+
62+
/**
63+
* Curate shipping and billing default options
64+
*
65+
* @param array $address
66+
* @param AddressInterface $addressObject
67+
* @return array
68+
*/
69+
private function curateAddressDefaultValues(array $address, AddressInterface $addressObject) : array
70+
{
71+
$customerModel = $this->customerFactory->create();
72+
$this->customerResourceModel->load($customerModel, $addressObject->getCustomerId());
73+
$address[CustomerInterface::DEFAULT_BILLING] =
74+
($customerModel->getDefaultBillingAddress()
75+
&& $addressObject->getId() == $customerModel->getDefaultBillingAddress()->getId());
76+
$address[CustomerInterface::DEFAULT_SHIPPING] =
77+
($customerModel->getDefaultShippingAddress()
78+
&& $addressObject->getId() == $customerModel->getDefaultShippingAddress()->getId());
79+
return $address;
80+
}
81+
82+
/**
83+
* Transform single customer address data from object to in array format
84+
*
85+
* @param AddressInterface $addressObject
86+
* @return array
87+
*/
88+
public function getAddressData(AddressInterface $addressObject): array
89+
{
90+
$address = $this->serviceOutputProcessor->process(
91+
$addressObject,
92+
AddressRepositoryInterface::class,
93+
'getById'
94+
);
95+
$address = $this->curateAddressDefaultValues($address, $addressObject);
96+
97+
if (isset($address[CustomAttributesDataInterface::EXTENSION_ATTRIBUTES_KEY])) {
98+
$address = array_merge($address, $address[CustomAttributesDataInterface::EXTENSION_ATTRIBUTES_KEY]);
99+
}
100+
$customAttributes = [];
101+
if (isset($address[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES])) {
102+
foreach ($address[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES] as $attribute) {
103+
$isArray = false;
104+
if (is_array($attribute['value'])) {
105+
$isArray = true;
106+
foreach ($attribute['value'] as $attributeValue) {
107+
if (is_array($attributeValue)) {
108+
$customAttributes[$attribute['attribute_code']] = $this->jsonSerializer->serialize(
109+
$attribute['value']
110+
);
111+
continue;
112+
}
113+
$customAttributes[$attribute['attribute_code']] = implode(',', $attribute['value']);
114+
continue;
115+
}
116+
}
117+
if ($isArray) {
118+
continue;
119+
}
120+
$customAttributes[$attribute['attribute_code']] = $attribute['value'];
121+
}
122+
}
123+
$address = array_merge($address, $customAttributes);
124+
125+
return $address;
126+
}
127+
}
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\CustomerGraphQl\Model\Customer\Address;
9+
10+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
11+
12+
/**
13+
* Customer address update data validator. Patch update is allowed
14+
*/
15+
class CustomerAddressUpdateDataValidator
16+
{
17+
/**
18+
* @var GetAllowedAddressAttributes
19+
*/
20+
private $getAllowedAddressAttributes;
21+
22+
/**
23+
* @param GetAllowedAddressAttributes $getAllowedAddressAttributes
24+
*/
25+
public function __construct(GetAllowedAddressAttributes $getAllowedAddressAttributes)
26+
{
27+
$this->getAllowedAddressAttributes = $getAllowedAddressAttributes;
28+
}
29+
30+
/**
31+
* Validate customer address update data
32+
*
33+
* @param array $addressData
34+
* @return void
35+
* @throws GraphQlInputException
36+
*/
37+
public function validate(array $addressData): void
38+
{
39+
$attributes = $this->getAllowedAddressAttributes->execute();
40+
$errorInput = [];
41+
42+
foreach ($attributes as $attributeName => $attributeInfo) {
43+
if ($attributeInfo->getIsRequired()
44+
&& (isset($addressData[$attributeName]) && empty($addressData[$attributeName]))
45+
) {
46+
$errorInput[] = $attributeName;
47+
}
48+
}
49+
50+
if ($errorInput) {
51+
throw new GraphQlInputException(
52+
__('Required parameters are missing: %1', [implode(', ', $errorInput)])
53+
);
54+
}
55+
}
56+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Address;
9+
10+
use Magento\Customer\Api\AddressMetadataManagementInterface;
11+
use Magento\Eav\Model\Config;
12+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
13+
14+
/**
15+
* Get allowed address attributes
16+
*/
17+
class GetAllowedAddressAttributes
18+
{
19+
/**
20+
* @var Config
21+
*/
22+
private $eavConfig;
23+
24+
/**
25+
* @param Config $eavConfig
26+
*/
27+
public function __construct(Config $eavConfig)
28+
{
29+
$this->eavConfig = $eavConfig;
30+
}
31+
32+
/**
33+
* Get allowed address attributes
34+
*
35+
* @return AbstractAttribute[]
36+
*/
37+
public function execute(): array
38+
{
39+
$attributes = $this->eavConfig->getEntityAttributes(
40+
AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS
41+
);
42+
foreach ($attributes as $attributeCode => $attribute) {
43+
if (false === $attribute->getIsVisibleOnFront()) {
44+
unset($attributes[$attributeCode]);
45+
}
46+
}
47+
return $attributes;
48+
}
49+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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\Address;
9+
10+
use Magento\Customer\Api\AddressRepositoryInterface;
11+
use Magento\Customer\Api\Data\AddressInterface;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
14+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
15+
16+
/**
17+
* Get customer address for user
18+
*/
19+
class GetCustomerAddressForUser
20+
{
21+
/**
22+
* @var AddressRepositoryInterface
23+
*/
24+
private $addressRepository;
25+
26+
/**
27+
* @param AddressRepositoryInterface $addressRepository
28+
*/
29+
public function __construct(AddressRepositoryInterface $addressRepository)
30+
{
31+
$this->addressRepository = $addressRepository;
32+
}
33+
34+
/**
35+
* Get customer address for user
36+
*
37+
* @param int $addressId
38+
* @param int $userId
39+
* @return AddressInterface
40+
* @throws GraphQlAuthorizationException
41+
* @throws GraphQlNoSuchEntityException
42+
*/
43+
public function execute(int $addressId, int $userId): AddressInterface
44+
{
45+
try {
46+
/** @var AddressInterface $address */
47+
$address = $this->addressRepository->getById($addressId);
48+
} catch (NoSuchEntityException $e) {
49+
throw new GraphQlNoSuchEntityException(
50+
__('Address id %1 does not exist.', [$addressId])
51+
);
52+
}
53+
54+
if ($address->getCustomerId() != $userId) {
55+
throw new GraphQlAuthorizationException(
56+
__('Current customer does not have permission to address id %1', [$addressId])
57+
);
58+
}
59+
return $address;
60+
}
61+
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@ public function getCustomerById(int $customerId): array
7070
return $this->processCustomer($customer);
7171
}
7272

73+
/**
74+
* Curate default shipping and default billing keys
75+
*
76+
* @param array $arrayAddress
77+
* @return array
78+
*/
79+
private function curateAddressData(array $arrayAddress) : array
80+
{
81+
foreach ($arrayAddress as $key => $address) {
82+
if (!isset($address['default_shipping'])) {
83+
$arrayAddress[$key]['default_shipping'] = false;
84+
}
85+
if (!isset($address['default_billing'])) {
86+
$arrayAddress[$key]['default_billing'] = false;
87+
}
88+
}
89+
return $arrayAddress;
90+
}
91+
7392
/**
7493
* Transform single customer data from object to in array format
7594
*
@@ -83,6 +102,7 @@ private function processCustomer(CustomerInterface $customer): array
83102
CustomerRepositoryInterface::class,
84103
'get'
85104
);
105+
$customerData['addresses'] = $this->curateAddressData($customerData['addresses']);
86106
if (isset($customerData['extension_attributes'])) {
87107
$customerData = array_merge($customerData, $customerData['extension_attributes']);
88108
}

app/code/Magento/CustomerGraphQl/Model/Customer/UpdateAccountInformation.php renamed to app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerData.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
use Magento\Store\Model\StoreManagerInterface;
1616

1717
/**
18-
* Update account information
18+
* Update customer data
1919
*/
20-
class UpdateAccountInformation
20+
class UpdateCustomerData
2121
{
2222
/**
2323
* @var CustomerRepositoryInterface

0 commit comments

Comments
 (0)