Skip to content

Commit 546d238

Browse files
author
Mariana Lashch
committed
Merge branch 'MAGETWO-91951' into mpi-PR-1106
2 parents 16b06b0 + 8a2d9f7 commit 546d238

File tree

13 files changed

+1031
-33
lines changed

13 files changed

+1031
-33
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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\Checkout\Controller\Cart;
9+
10+
use Magento\Checkout\Model\Cart\RequestQuantityProcessor;
11+
use Magento\Framework\App\Action\Context;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Checkout\Model\Session as CheckoutSession;
14+
use Magento\Framework\Serialize\Serializer\Json;
15+
use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
16+
use Magento\Quote\Model\Quote\Item;
17+
use Psr\Log\LoggerInterface;
18+
19+
class UpdateItemQty extends \Magento\Framework\App\Action\Action
20+
{
21+
/**
22+
* @var RequestQuantityProcessor
23+
*/
24+
private $quantityProcessor;
25+
26+
/**
27+
* @var FormKeyValidator
28+
*/
29+
private $formKeyValidator;
30+
31+
/**
32+
* @var CheckoutSession
33+
*/
34+
private $checkoutSession;
35+
36+
/**
37+
* @var Json
38+
*/
39+
private $json;
40+
41+
/**
42+
* @var LoggerInterface
43+
*/
44+
private $logger;
45+
46+
/**
47+
* @param Context $context,
48+
* @param RequestQuantityProcessor $quantityProcessor
49+
* @param FormKeyValidator $formKeyValidator
50+
* @param CheckoutSession $checkoutSession
51+
* @param Json $json
52+
* @param LoggerInterface $logger
53+
*/
54+
public function __construct(
55+
Context $context,
56+
RequestQuantityProcessor $quantityProcessor,
57+
FormKeyValidator $formKeyValidator,
58+
CheckoutSession $checkoutSession,
59+
Json $json,
60+
LoggerInterface $logger
61+
) {
62+
$this->quantityProcessor = $quantityProcessor;
63+
$this->formKeyValidator = $formKeyValidator;
64+
$this->checkoutSession = $checkoutSession;
65+
$this->json = $json;
66+
$this->logger = $logger;
67+
parent::__construct($context);
68+
}
69+
70+
/**
71+
* @return void
72+
*/
73+
public function execute()
74+
{
75+
try {
76+
if (!$this->formKeyValidator->validate($this->getRequest())) {
77+
throw new LocalizedException(
78+
__('Something went wrong while saving the page. Please refresh the page and try again.')
79+
);
80+
}
81+
82+
$cartData = $this->getRequest()->getParam('cart');
83+
if (!is_array($cartData)) {
84+
throw new LocalizedException(
85+
__('Something went wrong while saving the page. Please refresh the page and try again.')
86+
);
87+
}
88+
89+
$cartData = $this->quantityProcessor->process($cartData);
90+
$quote = $this->checkoutSession->getQuote();
91+
92+
foreach ($cartData as $itemId => $itemInfo) {
93+
$item = $quote->getItemById($itemId);
94+
$qty = isset($itemInfo['qty']) ? (double)$itemInfo['qty'] : 0;
95+
if ($item) {
96+
$this->updateItemQuantity($item, $qty);
97+
}
98+
}
99+
100+
$this->jsonResponse();
101+
} catch (LocalizedException $e) {
102+
$this->jsonResponse($e->getMessage());
103+
} catch (\Exception $e) {
104+
$this->logger->critical($e->getMessage());
105+
$this->jsonResponse('Something went wrong while saving the page. Please refresh the page and try again.');
106+
}
107+
}
108+
109+
/**
110+
* Updates quote item quantity.
111+
*
112+
* @param Item $item
113+
* @param float $qty
114+
* @throws LocalizedException
115+
*/
116+
private function updateItemQuantity(Item $item, float $qty)
117+
{
118+
if ($qty > 0) {
119+
$item->setQty($qty);
120+
121+
if ($item->getHasError()) {
122+
throw new LocalizedException(__($item->getMessage()));
123+
}
124+
}
125+
}
126+
127+
/**
128+
* JSON response builder.
129+
*
130+
* @param string $error
131+
* @return void
132+
*/
133+
private function jsonResponse(string $error = '')
134+
{
135+
$this->getResponse()->representJson(
136+
$this->json->serialize($this->getResponseData($error))
137+
);
138+
}
139+
140+
/**
141+
* Returns response data.
142+
*
143+
* @param string $error
144+
* @return array
145+
*/
146+
private function getResponseData(string $error = ''): array
147+
{
148+
$response = [
149+
'success' => true,
150+
];
151+
152+
if (!empty($error)) {
153+
$response = [
154+
'success' => false,
155+
'error_message' => $error,
156+
];
157+
}
158+
159+
return $response;
160+
}
161+
}

app/code/Magento/Checkout/Controller/Cart/UpdatePost.php

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,45 @@
66
*/
77
namespace Magento\Checkout\Controller\Cart;
88

9+
use Magento\Checkout\Model\Cart\RequestQuantityProcessor;
10+
911
class UpdatePost extends \Magento\Checkout\Controller\Cart
1012
{
13+
/**
14+
* @var RequestQuantityProcessor
15+
*/
16+
private $quantityProcessor;
17+
18+
/**
19+
* @param \Magento\Framework\App\Action\Context $context
20+
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
21+
* @param \Magento\Checkout\Model\Session $checkoutSession
22+
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
23+
* @param \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator
24+
* @param \Magento\Checkout\Model\Cart $cart
25+
* @param RequestQuantityProcessor $quantityProcessor
26+
*/
27+
public function __construct(
28+
\Magento\Framework\App\Action\Context $context,
29+
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
30+
\Magento\Checkout\Model\Session $checkoutSession,
31+
\Magento\Store\Model\StoreManagerInterface $storeManager,
32+
\Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator,
33+
\Magento\Checkout\Model\Cart $cart,
34+
RequestQuantityProcessor $quantityProcessor = null
35+
) {
36+
parent::__construct(
37+
$context,
38+
$scopeConfig,
39+
$checkoutSession,
40+
$storeManager,
41+
$formKeyValidator,
42+
$cart
43+
);
44+
45+
$this->quantityProcessor = $quantityProcessor ?: $this->_objectManager->get(RequestQuantityProcessor::class);
46+
}
47+
1148
/**
1249
* Empty customer's shopping cart
1350
*
@@ -34,20 +71,10 @@ protected function _updateShoppingCart()
3471
try {
3572
$cartData = $this->getRequest()->getParam('cart');
3673
if (is_array($cartData)) {
37-
$filter = new \Zend_Filter_LocalizedToNormalized(
38-
['locale' => $this->_objectManager->get(
39-
\Magento\Framework\Locale\ResolverInterface::class
40-
)->getLocale()]
41-
);
42-
foreach ($cartData as $index => $data) {
43-
if (isset($data['qty'])) {
44-
$cartData[$index]['qty'] = $filter->filter(trim($data['qty']));
45-
}
46-
}
4774
if (!$this->cart->getCustomerSession()->getCustomerId() && $this->cart->getQuote()->getCustomerId()) {
4875
$this->cart->getQuote()->setCustomerId(null);
4976
}
50-
77+
$cartData = $this->quantityProcessor->process($cartData);
5178
$cartData = $this->cart->suggestItemsQty($cartData);
5279
$this->cart->updateItems($cartData)->save();
5380
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Checkout\Model\Cart;
9+
10+
use Magento\Framework\Locale\ResolverInterface;
11+
12+
class RequestQuantityProcessor
13+
{
14+
/**
15+
* @var ResolverInterface
16+
*/
17+
private $localeResolver;
18+
19+
/**
20+
* RequestQuantityProcessor constructor.
21+
* @param ResolverInterface $localeResolver
22+
*/
23+
public function __construct(
24+
ResolverInterface $localeResolver
25+
) {
26+
$this->localeResolver = $localeResolver;
27+
}
28+
29+
/**
30+
* Process cart request data
31+
*
32+
* @param array $cartData
33+
* @return array
34+
*/
35+
public function process(array $cartData): array
36+
{
37+
$filter = new \Zend\I18n\Filter\NumberParse($this->localeResolver->getLocale());
38+
39+
foreach ($cartData as $index => $data) {
40+
if (isset($data['qty'])) {
41+
$data['qty'] = is_string($data['qty']) ? trim($data['qty']) : $data['qty'];
42+
$cartData[$index]['qty'] = $filter->filter($data['qty']);
43+
}
44+
}
45+
46+
return $cartData;
47+
}
48+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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\Checkout\Test\Unit\Model\Cart;
9+
10+
use Magento\Checkout\Model\Cart\RequestQuantityProcessor;
11+
use Magento\Framework\Locale\ResolverInterface;
12+
use \PHPUnit_Framework_MockObject_MockObject as MockObject;
13+
14+
class RequestQuantityProcessorTest extends \PHPUnit\Framework\TestCase
15+
{
16+
/**
17+
* @var ResolverInterface | MockObject
18+
*/
19+
private $localeResolver;
20+
21+
/**
22+
* @var RequestQuantityProcessor
23+
*/
24+
private $requestProcessor;
25+
26+
protected function setUp()
27+
{
28+
$this->localeResolver = $this->getMockBuilder(ResolverInterface::class)
29+
->getMockForAbstractClass();
30+
31+
$this->localeResolver->method('getLocale')
32+
->willReturn('en_US');
33+
34+
$this->requestProcessor = new RequestQuantityProcessor(
35+
$this->localeResolver
36+
);
37+
}
38+
39+
/**
40+
* Test of cart data processing.
41+
*
42+
* @param array $cartData
43+
* @param array $expected
44+
* @dataProvider cartDataProvider
45+
*/
46+
public function testProcess($cartData, $expected)
47+
{
48+
$this->assertEquals($this->requestProcessor->process($cartData), $expected);
49+
}
50+
51+
public function cartDataProvider()
52+
{
53+
return [
54+
'empty_array' => [
55+
'cartData' => [],
56+
'expected' => [],
57+
],
58+
'strings_array' => [
59+
'cartData' => [
60+
['qty' => ' 10 '],
61+
['qty' => ' 0.5 ']
62+
],
63+
'expected' => [
64+
['qty' => 10],
65+
['qty' => 0.5]
66+
],
67+
],
68+
'integer_array' => [
69+
'cartData' => [
70+
['qty' => 1],
71+
['qty' => 0.002]
72+
],
73+
'expected' => [
74+
['qty' => 1],
75+
['qty' => 0.002]
76+
],
77+
],
78+
'array_of arrays' => [
79+
'cartData' => [
80+
['qty' => [1, 2 ,3]],
81+
],
82+
'expected' => [
83+
['qty' => [1, 2, 3]],
84+
],
85+
],
86+
];
87+
}
88+
}

app/code/Magento/Checkout/i18n/en_US.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,4 @@ Payment,Payment
177177
"We received your order!","We received your order!"
178178
"Thank you for your purchase!","Thank you for your purchase!"
179179
"optional", "optional"
180+
"Something went wrong while saving the page. Please refresh the page and try again.","Something went wrong while saving the page. Please refresh the page and try again."

app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
<form action="<?= /* @escapeNotVerified */ $block->getUrl('checkout/cart/updatePost') ?>"
1414
method="post"
1515
id="form-validate"
16-
data-mage-init='{"validation":{}}'
16+
data-mage-init='{"Magento_Checkout/js/action/update-shopping-cart":
17+
{"validationURL" : "/checkout/cart/updateItemQty"}
18+
}'
1719
class="form form-cart">
1820
<?= $block->getBlockHtml('formkey') ?>
1921
<div class="cart table-wrapper<?= $mergedCells == 2 ? ' detailed' : '' ?>">

0 commit comments

Comments
 (0)