Skip to content

Commit 482b6c7

Browse files
Merge branch 'AC-10890' into cia-2.4.8-beta2-develop-bugfix-10072024
2 parents 1b9c883 + 0d8ea54 commit 482b6c7

File tree

6 files changed

+332
-29
lines changed

6 files changed

+332
-29
lines changed

app/code/Magento/Quote/Model/BillingAddressManagement.php

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,27 @@
77

88
namespace Magento\Quote\Model;
99

10+
use Magento\Customer\Api\AddressRepositoryInterface;
1011
use Magento\Framework\App\ObjectManager;
1112
use Magento\Framework\Exception\InputException;
1213
use Magento\Quote\Api\BillingAddressManagementInterface;
14+
use Magento\Quote\Api\CartRepositoryInterface;
1315
use Magento\Quote\Api\Data\AddressInterface;
1416
use Psr\Log\LoggerInterface as Logger;
1517

1618
/**
1719
* Quote billing address write service object.
20+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1821
*/
1922
class BillingAddressManagement implements BillingAddressManagementInterface
2023
{
24+
/**
25+
* Billing address lock const
26+
*
27+
* @var string
28+
*/
29+
private const CART_BILLING_ADDRESS_LOCK = 'cart_billing_address_lock_';
30+
2131
/**
2232
* Validator.
2333
*
@@ -35,12 +45,12 @@ class BillingAddressManagement implements BillingAddressManagementInterface
3545
/**
3646
* Quote repository object.
3747
*
38-
* @var \Magento\Quote\Api\CartRepositoryInterface
48+
* @var CartRepositoryInterface
3949
*/
4050
protected $quoteRepository;
4151

4252
/**
43-
* @var \Magento\Customer\Api\AddressRepositoryInterface
53+
* @var AddressRepositoryInterface
4454
*/
4555
protected $addressRepository;
4656

@@ -49,24 +59,33 @@ class BillingAddressManagement implements BillingAddressManagementInterface
4959
*/
5060
private $shippingAddressAssignment;
5161

62+
/**
63+
* @var CartAddressMutexInterface
64+
*/
65+
private $cartAddressMutex;
66+
5267
/**
5368
* Constructs a quote billing address service object.
5469
*
55-
* @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository Quote repository.
70+
* @param CartRepositoryInterface $quoteRepository Quote repository.
5671
* @param QuoteAddressValidator $addressValidator Address validator.
5772
* @param Logger $logger Logger.
58-
* @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository
73+
* @param AddressRepositoryInterface $addressRepository
74+
* @param CartAddressMutexInterface|null $cartAddressMutex
5975
*/
6076
public function __construct(
61-
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
77+
CartRepositoryInterface $quoteRepository,
6278
QuoteAddressValidator $addressValidator,
6379
Logger $logger,
64-
\Magento\Customer\Api\AddressRepositoryInterface $addressRepository
80+
AddressRepositoryInterface $addressRepository,
81+
?CartAddressMutexInterface $cartAddressMutex = null
6582
) {
6683
$this->addressValidator = $addressValidator;
6784
$this->logger = $logger;
6885
$this->quoteRepository = $quoteRepository;
6986
$this->addressRepository = $addressRepository;
87+
$this->cartAddressMutex = $cartAddressMutex ??
88+
ObjectManager::getInstance()->get(CartAddressMutex::class);
7089
}
7190

7291
/**
@@ -75,8 +94,29 @@ public function __construct(
7594
*/
7695
public function assign($cartId, AddressInterface $address, $useForShipping = false)
7796
{
78-
/** @var \Magento\Quote\Model\Quote $quote */
97+
/** @var Quote $quote */
7998
$quote = $this->quoteRepository->getActive($cartId);
99+
$billingAddressId = (int) $quote->getBillingAddress()->getId();
100+
101+
return $this->cartAddressMutex->execute(
102+
self::CART_BILLING_ADDRESS_LOCK.$billingAddressId,
103+
$this->assignBillingAddress(...),
104+
$billingAddressId,
105+
[$address, $quote, $useForShipping]
106+
);
107+
}
108+
109+
/**
110+
* Assign billing address to cart
111+
*
112+
* @param AddressInterface $address
113+
* @param Quote $quote
114+
* @param bool $useForShipping
115+
* @return mixed
116+
* @throws InputException
117+
*/
118+
private function assignBillingAddress(AddressInterface $address, Quote $quote, bool $useForShipping = false)
119+
{
80120
$address->setCustomerId($quote->getCustomerId());
81121
$quote->removeAddress($quote->getBillingAddress()->getId());
82122
$quote->setBillingAddress($address);
@@ -85,9 +125,10 @@ public function assign($cartId, AddressInterface $address, $useForShipping = fal
85125
$quote->setDataChanges(true);
86126
$this->quoteRepository->save($quote);
87127
} catch (\Exception $e) {
88-
$this->logger->critical($e);
128+
$this->logger->critical($e->getMessage());
89129
throw new InputException(__('The address failed to save. Verify the address and try again.'));
90130
}
131+
91132
return $quote->getBillingAddress()->getId();
92133
}
93134

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Quote\Model;
20+
21+
use Magento\Framework\Lock\LockManagerInterface;
22+
23+
/**
24+
* @inheritDoc
25+
*/
26+
class CartAddressMutex implements CartAddressMutexInterface
27+
{
28+
/**
29+
* @var LockManagerInterface
30+
*/
31+
private $lockManager;
32+
33+
/**
34+
* @param LockManagerInterface $lockManager
35+
*/
36+
public function __construct(
37+
LockManagerInterface $lockManager,
38+
) {
39+
$this->lockManager = $lockManager;
40+
}
41+
42+
/**
43+
* @inheritDoc
44+
*/
45+
public function execute(string $lockName, callable $callable, int $result, array $args = [])
46+
{
47+
if (!$this->lockManager->lock($lockName, 0)) {
48+
return $result;
49+
}
50+
try {
51+
$result = $callable(...$args);
52+
} finally {
53+
$this->lockManager->unlock($lockName);
54+
}
55+
56+
return $result;
57+
}
58+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Quote\Model;
20+
21+
/**
22+
* Intended to prevent race conditions during quote address processing by concurrent requests.
23+
*/
24+
interface CartAddressMutexInterface
25+
{
26+
/**
27+
* Acquires a lock for quote address, executes callable and releases the lock after.
28+
*
29+
* @param string $lockName
30+
* @param callable $callable
31+
* @param int $result
32+
* @param array $args
33+
* @return mixed
34+
*/
35+
public function execute(string $lockName, callable $callable, int $result, array $args = []);
36+
}

0 commit comments

Comments
 (0)