Skip to content

Commit 6fd1a30

Browse files
committed
Merge remote-tracking branch 'mainline/2.4-develop' into HB-PR-delivery-Oct
2 parents 28e89b7 + 485c714 commit 6fd1a30

File tree

26 files changed

+753
-585
lines changed

26 files changed

+753
-585
lines changed

app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Rows.php

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,82 @@
55
*/
66
namespace Magento\Catalog\Model\Indexer\Product\Price\Action;
77

8+
use Magento\Directory\Model\CurrencyFactory;
9+
use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory;
10+
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
11+
use Magento\Catalog\Model\Product\Type;
12+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice;
13+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory;
14+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice;
15+
use Magento\Framework\App\Config\ScopeConfigInterface;
16+
use Magento\Framework\Stdlib\DateTime;
17+
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
18+
use Magento\Store\Model\StoreManagerInterface;
19+
820
/**
921
* Class Rows reindex action for mass actions
1022
*
23+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) to preserve compatibility with parent class
1124
*/
1225
class Rows extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
1326
{
27+
/**
28+
* Default batch size
29+
*/
30+
private const BATCH_SIZE = 100;
31+
32+
/**
33+
* @var int
34+
*/
35+
private $batchSize;
36+
37+
/**
38+
* @param ScopeConfigInterface $config
39+
* @param StoreManagerInterface $storeManager
40+
* @param CurrencyFactory $currencyFactory
41+
* @param TimezoneInterface $localeDate
42+
* @param DateTime $dateTime
43+
* @param Type $catalogProductType
44+
* @param Factory $indexerPriceFactory
45+
* @param DefaultPrice $defaultIndexerResource
46+
* @param TierPrice|null $tierPriceIndexResource
47+
* @param DimensionCollectionFactory|null $dimensionCollectionFactory
48+
* @param TableMaintainer|null $tableMaintainer
49+
* @param int|null $batchSize
50+
* @SuppressWarnings(PHPMD.NPathComplexity) Added to backward compatibility with abstract class
51+
* @SuppressWarnings(PHPMD.CyclomaticComplexity) Added to backward compatibility with abstract class
52+
* @SuppressWarnings(PHPMD.ExcessiveParameterList) Added to backward compatibility with abstract class
53+
*/
54+
public function __construct(
55+
ScopeConfigInterface $config,
56+
StoreManagerInterface $storeManager,
57+
CurrencyFactory $currencyFactory,
58+
TimezoneInterface $localeDate,
59+
DateTime $dateTime,
60+
Type $catalogProductType,
61+
Factory $indexerPriceFactory,
62+
DefaultPrice $defaultIndexerResource,
63+
TierPrice $tierPriceIndexResource = null,
64+
DimensionCollectionFactory $dimensionCollectionFactory = null,
65+
TableMaintainer $tableMaintainer = null,
66+
?int $batchSize = null
67+
) {
68+
parent::__construct(
69+
$config,
70+
$storeManager,
71+
$currencyFactory,
72+
$localeDate,
73+
$dateTime,
74+
$catalogProductType,
75+
$indexerPriceFactory,
76+
$defaultIndexerResource,
77+
$tierPriceIndexResource,
78+
$dimensionCollectionFactory,
79+
$tableMaintainer
80+
);
81+
$this->batchSize = $batchSize ?? self::BATCH_SIZE;
82+
}
83+
1484
/**
1585
* Execute Rows reindex
1686
*
@@ -24,10 +94,28 @@ public function execute($ids)
2494
if (empty($ids)) {
2595
throw new \Magento\Framework\Exception\InputException(__('Bad value was supplied.'));
2696
}
27-
try {
28-
$this->_reindexRows($ids);
29-
} catch (\Exception $e) {
30-
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
97+
$currentBatch = [];
98+
$i = 0;
99+
100+
foreach ($ids as $id) {
101+
$currentBatch[] = $id;
102+
if (++$i === $this->batchSize) {
103+
try {
104+
$this->_reindexRows($currentBatch);
105+
} catch (\Exception $e) {
106+
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
107+
}
108+
$i = 0;
109+
$currentBatch = [];
110+
}
111+
}
112+
113+
if (!empty($currentBatch)) {
114+
try {
115+
$this->_reindexRows($currentBatch);
116+
} catch (\Exception $e) {
117+
throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
118+
}
31119
}
32120
}
33121
}

app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Price/Action/RowsTest.php

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,189 @@
77

88
namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Price\Action;
99

10+
use Magento\Store\Model\StoreManagerInterface;
11+
use Magento\Directory\Model\CurrencyFactory;
12+
use Magento\Catalog\Model\Product\Type;
13+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory;
14+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice;
15+
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice;
16+
use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory;
17+
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
1018
use Magento\Catalog\Model\Indexer\Product\Price\Action\Rows;
11-
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
19+
use Magento\Framework\App\Config\ScopeConfigInterface;
20+
use Magento\Framework\Stdlib\DateTime;
21+
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
22+
use Magento\Framework\DB\Adapter\AdapterInterface;
23+
use Magento\Framework\DB\Select;
24+
use Magento\Framework\Indexer\MultiDimensionProvider;
1225
use PHPUnit\Framework\TestCase;
26+
use PHPUnit\Framework\MockObject\MockObject;
1327

28+
/**
29+
* Test coverage for the rows action
30+
*
31+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) to preserve compatibility with parent class
32+
*/
1433
class RowsTest extends TestCase
1534
{
1635
/**
1736
* @var Rows
1837
*/
19-
protected $_model;
38+
private $actionRows;
39+
40+
/**
41+
* @var ScopeConfigInterface|MockObject
42+
*/
43+
private $config;
44+
45+
/**
46+
* @var StoreManagerInterface|MockObject
47+
*/
48+
private $storeManager;
49+
50+
/**
51+
* @var CurrencyFactory|MockObject
52+
*/
53+
private $currencyFactory;
54+
55+
/**
56+
* @var TimezoneInterface|MockObject
57+
*/
58+
private $localeDate;
59+
60+
/**
61+
* @var DateTime|MockObject
62+
*/
63+
private $dateTime;
64+
65+
/**
66+
* @var Type|MockObject
67+
*/
68+
private $catalogProductType;
69+
70+
/**
71+
* @var Factory|MockObject
72+
*/
73+
private $indexerPriceFactory;
74+
75+
/**
76+
* @var DefaultPrice|MockObject
77+
*/
78+
private $defaultIndexerResource;
79+
80+
/**
81+
* @var TierPrice|MockObject
82+
*/
83+
private $tierPriceIndexResource;
84+
85+
/**
86+
* @var DimensionCollectionFactory|MockObject
87+
*/
88+
private $dimensionCollectionFactory;
89+
90+
/**
91+
* @var TableMaintainer|MockObject
92+
*/
93+
private $tableMaintainer;
2094

2195
protected function setUp(): void
2296
{
23-
$objectManager = new ObjectManager($this);
24-
$this->_model = $objectManager->getObject(Rows::class);
97+
$this->config = $this->getMockBuilder(ScopeConfigInterface::class)
98+
->getMockForAbstractClass();
99+
$this->storeManager = $this->getMockBuilder(StoreManagerInterface::class)
100+
->getMockForAbstractClass();
101+
$this->currencyFactory = $this->getMockBuilder(CurrencyFactory::class)
102+
->disableOriginalConstructor()
103+
->getMock();
104+
$this->localeDate = $this->getMockBuilder(TimezoneInterface::class)
105+
->getMockForAbstractClass();
106+
$this->dateTime = $this->getMockBuilder(DateTime::class)
107+
->disableOriginalConstructor()
108+
->getMock();
109+
$this->catalogProductType = $this->getMockBuilder(Type::class)
110+
->disableOriginalConstructor()
111+
->getMock();
112+
$this->indexerPriceFactory = $this->getMockBuilder(Factory::class)
113+
->disableOriginalConstructor()
114+
->getMock();
115+
$this->defaultIndexerResource = $this->getMockBuilder(DefaultPrice::class)
116+
->disableOriginalConstructor()
117+
->getMock();
118+
$this->tierPriceIndexResource = $this->getMockBuilder(TierPrice::class)
119+
->disableOriginalConstructor()
120+
->getMock();
121+
$this->dimensionCollectionFactory = $this->getMockBuilder(DimensionCollectionFactory::class)
122+
->disableOriginalConstructor()
123+
->getMock();
124+
$this->tableMaintainer = $this->getMockBuilder(TableMaintainer::class)
125+
->disableOriginalConstructor()
126+
->getMock();
127+
$batchSize = 2;
128+
129+
$this->actionRows = new Rows(
130+
$this->config,
131+
$this->storeManager,
132+
$this->currencyFactory,
133+
$this->localeDate,
134+
$this->dateTime,
135+
$this->catalogProductType,
136+
$this->indexerPriceFactory,
137+
$this->defaultIndexerResource,
138+
$this->tierPriceIndexResource,
139+
$this->dimensionCollectionFactory,
140+
$this->tableMaintainer,
141+
$batchSize
142+
);
25143
}
26144

27145
public function testEmptyIds()
28146
{
29147
$this->expectException('Magento\Framework\Exception\InputException');
30148
$this->expectExceptionMessage('Bad value was supplied.');
31-
$this->_model->execute(null);
149+
$this->actionRows->execute(null);
150+
}
151+
152+
public function testBatchProcessing()
153+
{
154+
$ids = [1, 2, 3, 4];
155+
$select = $this->getMockBuilder(Select::class)
156+
->disableOriginalConstructor()
157+
->getMock();
158+
$select->expects($this->any())->method('from')->willReturnSelf();
159+
$select->expects($this->any())->method('where')->willReturnSelf();
160+
$select->expects($this->any())->method('join')->willReturnSelf();
161+
$adapter = $this->getMockBuilder(AdapterInterface::class)->getMockForAbstractClass();
162+
$adapter->expects($this->any())->method('select')->willReturn($select);
163+
$this->defaultIndexerResource->expects($this->any())
164+
->method('getConnection')
165+
->willReturn($adapter);
166+
$adapter->expects($this->any())
167+
->method('fetchAll')
168+
->with($select)
169+
->willReturn([]);
170+
$adapter->expects($this->any())
171+
->method('fetchPairs')
172+
->with($select)
173+
->willReturn([]);
174+
$multiDimensionProvider = $this->getMockBuilder(MultiDimensionProvider::class)
175+
->disableOriginalConstructor()
176+
->getMock();
177+
$this->dimensionCollectionFactory->expects($this->exactly(2))
178+
->method('create')
179+
->willReturn($multiDimensionProvider);
180+
$iterator = new \ArrayIterator([]);
181+
$multiDimensionProvider->expects($this->exactly(2))
182+
->method('getIterator')
183+
->willReturn($iterator);
184+
$this->catalogProductType->expects($this->any())
185+
->method('getTypesByPriority')
186+
->willReturn([]);
187+
$adapter->expects($this->exactly(2))
188+
->method('getIndexList')
189+
->willReturn(['entity_id'=>['COLUMNS_LIST'=>['test']]]);
190+
$adapter->expects($this->exactly(2))
191+
->method('getPrimaryKeyName')
192+
->willReturn('entity_id');
193+
$this->actionRows->execute($ids);
32194
}
33195
}

app/code/Magento/Customer/Api/SessionCleanerInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
interface SessionCleanerInterface
1414
{
1515
/**
16-
* Destroy all active customer sessions related to given customer id, including current session.
16+
* Destroy all active customer sessions related to given customer except current session.
1717
*
1818
* @param int $customerId
1919
* @return void

app/code/Magento/Customer/Controller/Account/EditPost.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
use Magento\Framework\Phrase;
3434

3535
/**
36-
* Class EditPost
36+
* Customer edit account information controller
37+
*
3738
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
3839
*/
3940
class EditPost extends AbstractAccount implements CsrfAwareActionInterface, HttpPostActionInterface
@@ -185,6 +186,7 @@ public function validateForCsrf(RequestInterface $request): ?bool
185186
* Change customer email or password action
186187
*
187188
* @return \Magento\Framework\Controller\Result\Redirect
189+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
188190
*/
189191
public function execute()
190192
{
@@ -217,6 +219,12 @@ public function execute()
217219
);
218220
$this->dispatchSuccessEvent($customerCandidateDataObject);
219221
$this->messageManager->addSuccessMessage(__('You saved the account information.'));
222+
// logout from current session if password changed.
223+
if ($isPasswordChanged) {
224+
$this->session->logout();
225+
$this->session->start();
226+
return $resultRedirect->setPath('customer/account/login');
227+
}
220228
return $resultRedirect->setPath('customer/account');
221229
} catch (InvalidEmailOrPasswordException $e) {
222230
$this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage()));

app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
use Magento\Customer\Model\Customer\CredentialsValidator;
1515

1616
/**
17-
* Class ResetPasswordPost
18-
*
19-
* @package Magento\Customer\Controller\Account
17+
* Customer reset password controller
2018
*/
2119
class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount implements HttpPostActionInterface
2220
{
@@ -91,6 +89,11 @@ public function execute()
9189
$resetPasswordToken,
9290
$password
9391
);
92+
// logout from current session if password changed.
93+
if ($this->session->isLoggedIn()) {
94+
$this->session->logout();
95+
$this->session->start();
96+
}
9497
$this->session->unsRpToken();
9598
$this->messageManager->addSuccessMessage(__('You updated your password.'));
9699
$resultRedirect->setPath('*/*/login');

app/code/Magento/Customer/Model/Session/SessionCleaner.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ public function __construct(
7171
*/
7272
public function clearFor(int $customerId): void
7373
{
74-
if ($this->sessionManager->isSessionExists()) {
75-
//delete old session and move data to the new session
76-
//use this instead of $this->sessionManager->regenerateId because last one doesn't delete old session
77-
// phpcs:ignore Magento2.Functions.DiscouragedFunction
78-
session_regenerate_id(true);
79-
}
80-
8174
$sessionLifetime = $this->scopeConfig->getValue(
8275
Config::XML_PATH_COOKIE_LIFETIME,
8376
ScopeInterface::SCOPE_STORE
@@ -89,6 +82,8 @@ public function clearFor(int $customerId): void
8982
$visitorCollection = $this->visitorCollectionFactory->create();
9083
$visitorCollection->addFieldToFilter('customer_id', $customerId);
9184
$visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]);
85+
$visitorCollection->addFieldToFilter('session_id', ['neq' => $this->sessionManager->getSessionId()]);
86+
9287
/** @var \Magento\Customer\Model\Visitor $visitor */
9388
foreach ($visitorCollection->getItems() as $visitor) {
9489
$sessionId = $visitor->getSessionId();

0 commit comments

Comments
 (0)