Skip to content

Commit 09c9e6b

Browse files
committed
GraphQL-57: Manager Address Book
1 parent ab5c07d commit 09c9e6b

File tree

3 files changed

+746
-0
lines changed

3 files changed

+746
-0
lines changed
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
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\Resolver;
9+
10+
use Magento\Authorization\Model\UserContextInterface;
11+
use Magento\Customer\Api\CustomerRepositoryInterface;
12+
use Magento\Customer\Api\Data\CustomerInterface;
13+
use Magento\Customer\Api\AddressMetadataManagementInterface;
14+
use Magento\Customer\Api\AddressRepositoryInterface;
15+
use Magento\Customer\Api\Data\AddressInterfaceFactory;
16+
use Magento\Customer\Api\Data\AddressInterface;
17+
use Magento\Customer\Api\Data\RegionInterfaceFactory;
18+
use Magento\Customer\Api\Data\AddressExtensionInterfaceFactory;
19+
use Magento\Framework\Api\AttributeInterfaceFactory;
20+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
21+
use Magento\Framework\GraphQl\Config\Element\Field;
22+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
23+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
24+
use Magento\Framework\GraphQl\Query\ResolverInterface;
25+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
26+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
27+
use Magento\Framework\Exception\NoSuchEntityException;
28+
use Magento\CustomerGraphQl\Model\Resolver\Address\AddressDataProvider;
29+
use Magento\Eav\Model\Config;
30+
31+
/**
32+
* Customers Address Update
33+
*/
34+
class Address implements ResolverInterface
35+
{
36+
/**
37+
* Customer address attributes
38+
* @var array
39+
*/
40+
const ADDRESS_ATTRIBUTES = [
41+
AddressInterface::REGION,
42+
AddressInterface::REGION_ID,
43+
AddressInterface::COUNTRY_ID,
44+
AddressInterface::STREET,
45+
AddressInterface::COMPANY,
46+
AddressInterface::TELEPHONE,
47+
AddressInterface::FAX,
48+
AddressInterface::POSTCODE,
49+
AddressInterface::CITY,
50+
AddressInterface::FIRSTNAME,
51+
AddressInterface::LASTNAME,
52+
AddressInterface::MIDDLENAME,
53+
AddressInterface::PREFIX,
54+
AddressInterface::SUFFIX,
55+
AddressInterface::VAT_ID
56+
];
57+
58+
/**
59+
* Input data key
60+
*/
61+
const CUSTOM_ATTRIBUTE_KEY = 'custom_attributes';
62+
const EXTENSION_ATTRIBUTE_KEY = 'extension_attributes';
63+
64+
/**
65+
* Mutation Address type
66+
*/
67+
const MUTATION_ADDRESS_CREATE = 'customerAddressCreate';
68+
const MUTATION_ADDRESS_UPDATE = 'customerAddressUpdate';
69+
const MUTATION_ADDRESS_DELETE = 'customerAddressDelete';
70+
71+
/**
72+
* @var CustomerRepositoryInterface
73+
*/
74+
private $customerRepository;
75+
76+
/**
77+
* @var AddressRepositoryInterface
78+
*/
79+
private $addressRepositoryInterface;
80+
81+
/**
82+
* @var AddressInterfaceFactory
83+
*/
84+
private $addressInterfaceFactory;
85+
86+
/**
87+
* @var RegionInterfaceFactory
88+
*/
89+
private $regionInterfaceFactory;
90+
91+
/**
92+
* @var AttributeInterfaceFactory
93+
*/
94+
private $attributeInterfaceFactory;
95+
96+
/**
97+
* @var AddressExtensionInterfaceFactory
98+
*/
99+
private $addressExtensionInterfaceFactory;
100+
101+
/**
102+
* @var Config
103+
*/
104+
private $eavConfig;
105+
106+
/**
107+
* @var AddressDataProvider
108+
*/
109+
private $addressDataProvider;
110+
111+
/**
112+
* @param CustomerRepositoryInterface $customerRepository
113+
* @param AddressRepositoryInterface $addressRepositoryInterface
114+
* @param AddressInterfaceFactory $addressInterfaceFactory
115+
* @param RegionInterfaceFactory $regionInterfaceFactory
116+
* @param AttributeInterfaceFactory $attributeInterfaceFactory
117+
* @param AddressExtensionInterfaceFactory $addressExtensionInterfaceFactory
118+
* @param Config $eavConfig
119+
* @param AddressDataProvider $addressDataProvider
120+
*/
121+
public function __construct(
122+
CustomerRepositoryInterface $customerRepository,
123+
AddressRepositoryInterface $addressRepositoryInterface,
124+
AddressInterfaceFactory $addressInterfaceFactory,
125+
RegionInterfaceFactory $regionInterfaceFactory,
126+
AttributeInterfaceFactory $attributeInterfaceFactory,
127+
AddressExtensionInterfaceFactory $addressExtensionInterfaceFactory,
128+
Config $eavConfig,
129+
AddressDataProvider $addressDataProvider
130+
) {
131+
$this->customerRepository = $customerRepository;
132+
$this->addressRepositoryInterface = $addressRepositoryInterface;
133+
$this->addressInterfaceFactory = $addressInterfaceFactory;
134+
$this->regionInterfaceFactory = $regionInterfaceFactory;
135+
$this->attributeInterfaceFactory = $attributeInterfaceFactory;
136+
$this->addressExtensionInterfaceFactory = $addressExtensionInterfaceFactory;
137+
$this->eavConfig = $eavConfig;
138+
$this->addressDataProvider = $addressDataProvider;
139+
}
140+
141+
/**
142+
* {@inheritdoc}
143+
*/
144+
public function resolve(
145+
Field $field,
146+
$context,
147+
ResolveInfo $info,
148+
array $value = null,
149+
array $args = null
150+
) {
151+
/** @var ContextInterface $context */
152+
if ((!$context->getUserId()) || $context->getUserType() == UserContextInterface::USER_TYPE_GUEST) {
153+
throw new GraphQlAuthorizationException(
154+
__(
155+
'Current customer does not have access to the resource "%1"',
156+
[\Magento\Customer\Model\Customer::ENTITY]
157+
)
158+
);
159+
}
160+
/** @var \Magento\Customer\Api\Data\CustomerInterface $customer */
161+
$customer = $this->customerRepository->getById($context->getUserId());
162+
switch ($field->getName()) {
163+
case self::MUTATION_ADDRESS_CREATE:
164+
return $this->addressDataProvider->processCustomerAddress(
165+
$this->processCustomerAddressCreate($customer, $args['input'])
166+
);
167+
case self::MUTATION_ADDRESS_UPDATE:
168+
return $this->addressDataProvider->processCustomerAddress(
169+
$this->processCustomerAddressUpdate($customer, $args['id'], $args['input'])
170+
);
171+
case self::MUTATION_ADDRESS_DELETE:
172+
return $this->processCustomerAddressDelete($customer, $args['id']);
173+
default:
174+
return [];
175+
}
176+
}
177+
178+
/**
179+
* Get input address attribute errors
180+
* @param $addressInput
181+
* @return bool|string
182+
*/
183+
private function getAddressInputError($addressInput)
184+
{
185+
foreach (self::ADDRESS_ATTRIBUTES as $attribute) {
186+
if ($this->isAttributeRequired($attribute) && !isset($addressInput[$attribute])) {
187+
return $attribute;
188+
}
189+
}
190+
return false;
191+
}
192+
193+
/**
194+
* Check if attribute is set as required
195+
* @param $attributeName
196+
* @return bool
197+
*/
198+
private function isAttributeRequired($attributeName)
199+
{
200+
return $this->eavConfig->getAttribute(
201+
AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS,
202+
$attributeName
203+
)->getIsRequired();
204+
}
205+
206+
/**
207+
* @param AddressInterface $address
208+
* @param array $addressInput
209+
* @return AddressInterface
210+
*/
211+
private function fillAddress($address, $addressInput)
212+
{
213+
if (isset($addressInput[AddressInterface::REGION])) {
214+
/** @var \Magento\Customer\Api\Data\RegionInterface $newRegion */
215+
$newRegion = $this->regionInterfaceFactory->create($addressInput[AddressInterface::REGION]);
216+
$address->setRegion($newRegion);
217+
}
218+
if (isset($addressInput[AddressInterface::REGION_ID])) {
219+
$address->setRegionId($addressInput[AddressInterface::REGION_ID]);
220+
}
221+
if (isset($addressInput[AddressInterface::COUNTRY_ID])) {
222+
$address->setCountryId($addressInput[AddressInterface::COUNTRY_ID]);
223+
}
224+
if (isset($addressInput[AddressInterface::STREET])) {
225+
$address->setStreet($addressInput[AddressInterface::STREET]);
226+
}
227+
if (isset($addressInput[AddressInterface::COMPANY])) {
228+
$address->setCompany($addressInput[AddressInterface::COMPANY]);
229+
}
230+
if (isset($addressInput[AddressInterface::TELEPHONE])) {
231+
$address->setTelephone($addressInput[AddressInterface::TELEPHONE]);
232+
}
233+
if (isset($addressInput[AddressInterface::FAX])) {
234+
$address->setFax($addressInput[AddressInterface::FAX]);
235+
}
236+
if (isset($addressInput[AddressInterface::POSTCODE])) {
237+
$address->setPostcode($addressInput[AddressInterface::POSTCODE]);
238+
}
239+
if (isset($addressInput[AddressInterface::CITY])) {
240+
$address->setCity($addressInput[AddressInterface::CITY]);
241+
}
242+
if (isset($addressInput[AddressInterface::FIRSTNAME])) {
243+
$address->setFirstname($addressInput[AddressInterface::FIRSTNAME]);
244+
}
245+
if (isset($addressInput[AddressInterface::LASTNAME])) {
246+
$address->setLastname($addressInput[AddressInterface::LASTNAME]);
247+
}
248+
if (isset($addressInput[AddressInterface::MIDDLENAME])) {
249+
$address->setMiddlename($addressInput[AddressInterface::MIDDLENAME]);
250+
}
251+
if (isset($addressInput[AddressInterface::PREFIX])) {
252+
$address->setPrefix($addressInput[AddressInterface::PREFIX]);
253+
}
254+
if (isset($addressInput[AddressInterface::SUFFIX])) {
255+
$address->setSuffix($addressInput[AddressInterface::SUFFIX]);
256+
}
257+
if (isset($addressInput[AddressInterface::VAT_ID])) {
258+
$address->setVatId($addressInput[AddressInterface::VAT_ID]);
259+
}
260+
if (isset($addressInput[AddressInterface::DEFAULT_BILLING])) {
261+
$address->setIsDefaultBilling($addressInput[AddressInterface::DEFAULT_BILLING]);
262+
}
263+
if (isset($addressInput[AddressInterface::DEFAULT_SHIPPING])) {
264+
$address->setIsDefaultShipping($addressInput[AddressInterface::DEFAULT_SHIPPING]);
265+
}
266+
if (isset($addressInput[AddressInterface::DEFAULT_SHIPPING])) {
267+
$address->setIsDefaultShipping($addressInput[AddressInterface::DEFAULT_SHIPPING]);
268+
}
269+
if (isset($addressInput[self::CUSTOM_ATTRIBUTE_KEY])) {
270+
foreach ($addressInput[self::CUSTOM_ATTRIBUTE_KEY] as $attribute) {
271+
$address->setCustomAttribute($attribute['attribute_code'], $attribute['value']);
272+
}
273+
}
274+
if (isset($addressInput[self::EXTENSION_ATTRIBUTE_KEY])) {
275+
$extensionAttributes = $address->getExtensionAttributes();
276+
if (!$extensionAttributes) {
277+
/** @var \Magento\Customer\Api\Data\AddressExtensionInterface $newExtensionAttribute */
278+
$extensionAttributes = $this->addressExtensionInterfaceFactory->create();
279+
}
280+
foreach ($addressInput[self::EXTENSION_ATTRIBUTE_KEY] as $attribute) {
281+
$extensionAttributes->setData($attribute['attribute_code'], $attribute['value']);
282+
}
283+
$address->setExtensionAttributes($extensionAttributes);
284+
}
285+
return $address;
286+
}
287+
288+
/**
289+
* Process customer address create
290+
* @param CustomerInterface $customer
291+
* @param array $addressInput
292+
* @return AddressInterface
293+
* @throws GraphQlInputException
294+
*/
295+
private function processCustomerAddressCreate($customer, $addressInput)
296+
{
297+
$errorInput = $this->getAddressInputError($addressInput);
298+
if ($errorInput) {
299+
throw new GraphQlInputException(__('Required parameter %1 is missing', [$errorInput]));
300+
}
301+
/** @var AddressInterface $newAddress */
302+
$newAddress = $this->fillAddress(
303+
$this->addressInterfaceFactory->create(),
304+
$addressInput
305+
);
306+
$newAddress->setCustomerId($customer->getId());
307+
return $this->addressRepositoryInterface->save($newAddress);
308+
}
309+
310+
/**
311+
* Process customer address update
312+
* @param CustomerInterface $customer
313+
* @param int $addressId
314+
* @param array $addressInput
315+
* @return AddressInterface
316+
* @throws GraphQlAuthorizationException
317+
* @throws GraphQlNoSuchEntityException
318+
*/
319+
private function processCustomerAddressUpdate($customer, $addressId, $addressInput)
320+
{
321+
try {
322+
/** @var AddressInterface $address */
323+
$address = $this->addressRepositoryInterface->getById($addressId);
324+
} catch (NoSuchEntityException $exception) {
325+
throw new GraphQlNoSuchEntityException(
326+
__('Address id %1 does not exist.', [$addressId])
327+
);
328+
}
329+
if ($address->getCustomerId() != $customer->getId()) {
330+
throw new GraphQlAuthorizationException(
331+
__('Current customer does not have permission to update address id %1', [$addressId])
332+
);
333+
}
334+
return $this->addressRepositoryInterface->save(
335+
$this->fillAddress($address, $addressInput)
336+
);
337+
}
338+
339+
/**
340+
* Process customer address delete
341+
* @param CustomerInterface $customer
342+
* @param int $addressId
343+
* @return bool
344+
* @throws GraphQlAuthorizationException
345+
* @throws GraphQlNoSuchEntityException
346+
*/
347+
private function processCustomerAddressDelete($customer, $addressId)
348+
{
349+
try {
350+
/** @var AddressInterface $address */
351+
$address = $this->addressRepositoryInterface->getById($addressId);
352+
} catch (NoSuchEntityException $exception) {
353+
throw new GraphQlNoSuchEntityException(
354+
__('Address id %1 does not exist.', [$addressId])
355+
);
356+
}
357+
if ($address->getCustomerId() != $customer->getId()) {
358+
throw new GraphQlAuthorizationException(
359+
__('Current customer does not have permission to delete address id %1', [$addressId])
360+
);
361+
}
362+
if ($address->isDefaultBilling()) {
363+
throw new GraphQlAuthorizationException(
364+
__('Customer Address %1 is set as default billing address and can not be deleted', [$addressId])
365+
);
366+
}
367+
if ($address->isDefaultShipping()) {
368+
throw new GraphQlAuthorizationException(
369+
__('Customer Address %1 is set as default shipping address and can not be deleted', [$addressId])
370+
);
371+
}
372+
return $this->addressRepositoryInterface->delete($address);
373+
}
374+
}

0 commit comments

Comments
 (0)