Skip to content

Commit 965a450

Browse files
author
Joan He
committed
Merge remote-tracking branch 'upstream/2.3-develop' into MC-5570
2 parents 1d2fad9 + bdf7c3e commit 965a450

33 files changed

+1971
-163
lines changed

app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
<severity value="CRITICAL"/>
1818
<testCaseId value="MAGETWO-61717"/>
1919
<group value="Catalog"/>
20+
<!-- skip due to MAGETWO-97424 -->
21+
<group value="skip"/>
2022
</annotations>
2123
<before>
2224
<createData entity="Simple_US_Customer" stepKey="createCustomer"/>

app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ define([
291291
images = this.options.spConfig.images[this.simpleProduct];
292292

293293
if (images) {
294+
images = this._sortImages(images);
295+
294296
if (this.options.gallerySwitchStrategy === 'prepend') {
295297
images = images.concat(initialImages);
296298
}
@@ -309,7 +311,17 @@ define([
309311
$(this.options.mediaGallerySelector).AddFotoramaVideoEvents();
310312
}
311313

312-
galleryObject.first();
314+
},
315+
316+
/**
317+
* Sorting images array
318+
*
319+
* @private
320+
*/
321+
_sortImages: function (images) {
322+
return _.sortBy(images, function (image) {
323+
return image.position;
324+
});
313325
},
314326

315327
/**
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+
}

0 commit comments

Comments
 (0)