Skip to content

Commit 86ecde0

Browse files
committed
ACP2E-4223: Improved validation for rest api
1 parent e885088 commit 86ecde0

File tree

19 files changed

+906
-363
lines changed

19 files changed

+906
-363
lines changed

app/code/Magento/Checkout/Model/GuestShippingInformationManagement.php

Lines changed: 1 addition & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@
66
namespace Magento\Checkout\Model;
77

88
use Magento\Checkout\Api\Data\ShippingInformationInterface;
9-
use Magento\Customer\Model\AddressFactory;
10-
use Magento\Framework\Exception\InputException;
11-
use Magento\Framework\Exception\LocalizedException;
12-
use Magento\Framework\Validator\Factory as ValidatorFactory;
13-
use Magento\Quote\Api\Data\AddressInterface;
149

1510
class GuestShippingInformationManagement implements \Magento\Checkout\Api\GuestShippingInformationManagementInterface
1611
{
@@ -24,145 +19,31 @@ class GuestShippingInformationManagement implements \Magento\Checkout\Api\GuestS
2419
*/
2520
protected $shippingInformationManagement;
2621

27-
/**
28-
* @var ValidatorFactory
29-
*/
30-
private $validatorFactory;
31-
32-
/**
33-
* @var AddressFactory
34-
*/
35-
private $addressFactory;
36-
3722
/**
3823
* @param \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory
3924
* @param \Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement
40-
* @param ValidatorFactory $validatorFactory
41-
* @param AddressFactory $addressFactory
4225
* @codeCoverageIgnore
4326
*/
4427
public function __construct(
4528
\Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory,
46-
\Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement,
47-
ValidatorFactory $validatorFactory,
48-
AddressFactory $addressFactory
29+
\Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement
4930
) {
5031
$this->quoteIdMaskFactory = $quoteIdMaskFactory;
5132
$this->shippingInformationManagement = $shippingInformationManagement;
52-
$this->validatorFactory = $validatorFactory;
53-
$this->addressFactory = $addressFactory;
5433
}
5534

5635
/**
5736
* @inheritDoc
58-
*
59-
* @throws InputException
6037
*/
6138
public function saveAddressInformation(
6239
$cartId,
6340
ShippingInformationInterface $addressInformation
6441
) {
65-
$shippingAddress = $addressInformation->getShippingAddress();
66-
if ($shippingAddress) {
67-
$this->validateAddressAttributes($shippingAddress, 'shipping');
68-
}
69-
7042
/** @var $quoteIdMask \Magento\Quote\Model\QuoteIdMask */
7143
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id');
7244
return $this->shippingInformationManagement->saveAddressInformation(
7345
(int) $quoteIdMask->getQuoteId(),
7446
$addressInformation
7547
);
7648
}
77-
78-
/**
79-
* Validate address attributes using customer_address validator with custom attributes
80-
*
81-
* @param AddressInterface $address
82-
* @param string $addressType
83-
* @return void
84-
* @throws InputException
85-
*/
86-
private function validateAddressAttributes(AddressInterface $address, string $addressType): void
87-
{
88-
try {
89-
$customerAddress = $this->createCustomerAddressFromQuoteAddress($address, $addressType);
90-
$extensionAttributes = $address->getExtensionAttributes();
91-
if ($extensionAttributes) {
92-
$extensionAttributesData = $extensionAttributes->__toArray();
93-
foreach ($extensionAttributesData as $attributeCode => $value) {
94-
if ($value !== null && $value !== '') {
95-
$customerAddress->setData($attributeCode, $value);
96-
}
97-
}
98-
}
99-
$customerAddress->setSkipRequiredValidation(true);
100-
$validator = $this->validatorFactory->createValidator('customer_address', 'save');
101-
if (!$validator->isValid($customerAddress)) {
102-
$this->throwValidationException($validator->getMessages(), $addressType);
103-
}
104-
} catch (LocalizedException $e) {
105-
throw new InputException(__($e->getMessage()));
106-
}
107-
}
108-
109-
/**
110-
* Create customer address object from quote address
111-
*
112-
* @param AddressInterface $address
113-
* @param string $addressType
114-
* @return \Magento\Customer\Model\Address
115-
*/
116-
private function createCustomerAddressFromQuoteAddress(
117-
AddressInterface $address,
118-
string $addressType
119-
): \Magento\Customer\Model\Address {
120-
$customerAddress = $this->addressFactory->create();
121-
$customerAddress->setData([
122-
'firstname' => $address->getFirstname(),
123-
'lastname' => $address->getLastname(),
124-
'street' => $address->getStreet(),
125-
'city' => $address->getCity(),
126-
'region' => $address->getRegion(),
127-
'region_id' => $address->getRegionId(),
128-
'region_code' => $address->getRegionCode(),
129-
'postcode' => $address->getPostcode(),
130-
'country_id' => $address->getCountryId(),
131-
'telephone' => $address->getTelephone(),
132-
'company' => $address->getCompany(),
133-
'email' => $address->getEmail(),
134-
'address_type' => $addressType
135-
]);
136-
137-
return $customerAddress;
138-
}
139-
140-
/**
141-
* Process validator messages and throw validation exception
142-
*
143-
* @param array $messages
144-
* @param string $addressType
145-
* @return void
146-
* @throws InputException
147-
*/
148-
private function throwValidationException(array $messages, string $addressType): void
149-
{
150-
$errorMessages = [];
151-
foreach ($messages as $message) {
152-
if (is_array($message)) {
153-
foreach ($message as $msg) {
154-
$errorMessages[] = $msg;
155-
}
156-
} else {
157-
$errorMessages[] = $message;
158-
}
159-
}
160-
throw new InputException(
161-
__(
162-
'The %1 address contains invalid data: %2',
163-
$addressType,
164-
implode(', ', $errorMessages)
165-
)
166-
);
167-
}
16849
}

app/code/Magento/Checkout/Model/ShippingInformationManagement.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Magento\Quote\Model\Quote;
2727
use Magento\Quote\Model\Quote\TotalsCollector;
2828
use Magento\Quote\Model\QuoteAddressValidator;
29+
use Magento\Quote\Model\QuoteAddressValidationService;
2930
use Magento\Quote\Model\ShippingAssignmentFactory;
3031
use Magento\Quote\Model\ShippingFactory;
3132
use Psr\Log\LoggerInterface as Logger;
@@ -34,6 +35,7 @@
3435
* Class checkout shipping information management
3536
*
3637
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
38+
* @SuppressWarnings(PHPMD.TooManyFields)
3739
*/
3840
class ShippingInformationManagement implements ShippingInformationManagementInterface
3941
{
@@ -107,6 +109,11 @@ class ShippingInformationManagement implements ShippingInformationManagementInte
107109
*/
108110
private $addressComparator;
109111

112+
/**
113+
* @var QuoteAddressValidationService
114+
*/
115+
private $quoteAddressValidationService;
116+
110117
/**
111118
* @param PaymentMethodManagementInterface $paymentMethodManagement
112119
* @param PaymentDetailsFactory $paymentDetailsFactory
@@ -121,6 +128,7 @@ class ShippingInformationManagement implements ShippingInformationManagementInte
121128
* @param ShippingAssignmentFactory|null $shippingAssignmentFactory
122129
* @param ShippingFactory|null $shippingFactory
123130
* @param AddressComparatorInterface|null $addressComparator
131+
* @param QuoteAddressValidationService|null $quoteAddressValidationService
124132
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
125133
*/
126134
public function __construct(
@@ -137,6 +145,7 @@ public function __construct(
137145
?ShippingAssignmentFactory $shippingAssignmentFactory = null,
138146
?ShippingFactory $shippingFactory = null,
139147
?AddressComparatorInterface $addressComparator = null,
148+
?QuoteAddressValidationService $quoteAddressValidationService = null
140149
) {
141150
$this->paymentMethodManagement = $paymentMethodManagement;
142151
$this->paymentDetailsFactory = $paymentDetailsFactory;
@@ -155,6 +164,8 @@ public function __construct(
155164
->get(ShippingFactory::class);
156165
$this->addressComparator = $addressComparator
157166
?? ObjectManager::getInstance()->get(AddressComparatorInterface::class);
167+
$this->quoteAddressValidationService = $quoteAddressValidationService ?: ObjectManager::getInstance()
168+
->get(QuoteAddressValidationService::class);
158169
}
159170

160171
/**
@@ -177,6 +188,7 @@ public function saveAddressInformation(
177188

178189
$address = $addressInformation->getShippingAddress();
179190
$this->validateAddress($address);
191+
180192
$this->updateCustomerShippingAddressId($quote, $address);
181193
if (!$address->getCustomerAddressId()) {
182194
$address->setCustomerAddressId(null);
@@ -201,6 +213,8 @@ public function saveAddressInformation(
201213

202214
$quote->setIsMultiShipping(false);
203215

216+
$this->quoteAddressValidationService->validateAddressesWithRules($quote, $address, $billingAddress);
217+
204218
$this->quoteRepository->save($quote);
205219
} catch (LocalizedException $e) {
206220
$this->logger->critical($e);

app/code/Magento/Checkout/Test/Unit/Model/GuestShippingInformationManagementTest.php

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111
use Magento\Checkout\Api\Data\ShippingInformationInterface;
1212
use Magento\Checkout\Api\ShippingInformationManagementInterface;
1313
use Magento\Checkout\Model\GuestShippingInformationManagement;
14-
use Magento\Customer\Model\Address;
15-
use Magento\Customer\Model\AddressFactory;
16-
use Magento\Framework\Exception\InputException;
17-
use Magento\Framework\Validator\Factory as ValidatorFactory;
18-
use Magento\Framework\Validator\ValidatorInterface;
19-
use Magento\Quote\Api\Data\AddressInterface;
2014
use Magento\Quote\Model\QuoteIdMask;
2115
use Magento\Quote\Model\QuoteIdMaskFactory;
2216
use PHPUnit\Framework\MockObject\MockObject;
@@ -37,16 +31,6 @@ class GuestShippingInformationManagementTest extends TestCase
3731
*/
3832
protected $quoteIdMaskFactoryMock;
3933

40-
/**
41-
* @var ValidatorFactory|MockObject
42-
*/
43-
protected $validatorFactoryMock;
44-
45-
/**
46-
* @var AddressFactory|MockObject
47-
*/
48-
protected $addressFactoryMock;
49-
5034
/**
5135
* @var GuestShippingInformationManagement
5236
*/
@@ -61,13 +45,9 @@ protected function setUp(): void
6145
$this->shippingInformationManagementMock = $this->createMock(
6246
ShippingInformationManagementInterface::class
6347
);
64-
$this->validatorFactoryMock = $this->createMock(ValidatorFactory::class);
65-
$this->addressFactoryMock = $this->createMock(AddressFactory::class);
6648
$this->model = new GuestShippingInformationManagement(
6749
$this->quoteIdMaskFactoryMock,
68-
$this->shippingInformationManagementMock,
69-
$this->validatorFactoryMock,
70-
$this->addressFactoryMock
50+
$this->shippingInformationManagementMock
7151
);
7252
}
7353

@@ -76,23 +56,6 @@ public function testSaveAddressInformation()
7656
$cartId = 'masked_id';
7757
$quoteId = '100';
7858
$addressInformationMock = $this->getMockForAbstractClass(ShippingInformationInterface::class);
79-
$shippingAddressMock = $this->getMockForAbstractClass(AddressInterface::class);
80-
$addressInformationMock->expects($this->once())
81-
->method('getShippingAddress')
82-
->willReturn($shippingAddressMock);
83-
$shippingAddressMock->expects($this->once())
84-
->method('getExtensionAttributes')
85-
->willReturn(null);
86-
$customerAddressMock = $this->createMock(Address::class);
87-
$this->addressFactoryMock->expects($this->once())
88-
->method('create')
89-
->willReturn($customerAddressMock);
90-
$validatorMock = $this->createMock(ValidatorInterface::class);
91-
$this->validatorFactoryMock->expects($this->once())
92-
->method('createValidator')
93-
->with('customer_address', 'save')
94-
->willReturn($validatorMock);
95-
$validatorMock->expects($this->once())->method('isValid')->willReturn(true);
9659
$quoteIdMaskMock = $this->getMockBuilder(QuoteIdMask::class)
9760
->addMethods(['getQuoteId'])
9861
->onlyMethods(['load'])
@@ -114,37 +77,4 @@ public function testSaveAddressInformation()
11477
->willReturn($paymentInformationMock);
11578
$this->model->saveAddressInformation($cartId, $addressInformationMock);
11679
}
117-
118-
/**
119-
* Validate save address information when it is invalid
120-
*
121-
* @return void
122-
* @throws \PHPUnit\Framework\MockObject\Exception
123-
*/
124-
public function testSaveAddressInformationWithInvalidAddress()
125-
{
126-
$cartId = 'masked_id';
127-
$addressInformationMock = $this->getMockForAbstractClass(ShippingInformationInterface::class);
128-
$shippingAddressMock = $this->getMockForAbstractClass(AddressInterface::class);
129-
$addressInformationMock->expects($this->once())
130-
->method('getShippingAddress')
131-
->willReturn($shippingAddressMock);
132-
$shippingAddressMock->method('getExtensionAttributes')->willReturn(null);
133-
$customerAddressMock = $this->createMock(Address::class);
134-
$this->addressFactoryMock->expects($this->once())->method('create')->willReturn($customerAddressMock);
135-
$validatorMock = $this->createMock(ValidatorInterface::class);
136-
$this->validatorFactoryMock->expects($this->once())
137-
->method('createValidator')
138-
->with('customer_address', 'save')
139-
->willReturn($validatorMock);
140-
$validatorMock->expects($this->once())->method('isValid')->willReturn(false);
141-
$validatorMock->expects($this->once())
142-
->method('getMessages')
143-
->willReturn(['First Name is not valid!', 'Last Name is not valid!']);
144-
$this->expectException(InputException::class);
145-
$this->expectExceptionMessage(
146-
'The shipping address contains invalid data: First Name is not valid!, Last Name is not valid!'
147-
);
148-
$this->model->saveAddressInformation($cartId, $addressInformationMock);
149-
}
15080
}

app/code/Magento/Eav/Model/Attribute/Data/Multiselect.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ public function validateValue($value)
105105
}
106106

107107
if (!empty($value) && $attribute->getSourceModel()) {
108-
$values = is_array($value) ? $value : explode(',', (string) $value);
108+
if (is_array($value)) {
109+
$values = $value;
110+
} else {
111+
$values = preg_split('/[,\n\r]+/', (string) $value);
112+
}
113+
$values = array_map('trim', $values);
109114
$errors = array_merge(
110115
$errors,
111116
$this->validateBySource($values)

0 commit comments

Comments
 (0)