diff --git a/vendor/magento/module-persistent/Model/CleanExpiredPersistentQuotes.php b/vendor/magento/module-persistent/Model/CleanExpiredPersistentQuotes.php new file mode 100644 index 0000000000000..06b3ea9d7b714 --- /dev/null +++ b/vendor/magento/module-persistent/Model/CleanExpiredPersistentQuotes.php @@ -0,0 +1,98 @@ +storeManager->getWebsite($websiteId)->getStores(); + foreach ($stores as $store) { + $this->processStoreQuotes($store); + } + } + + /** + * Process store quotes in batches + * + * @param StoreInterface $store + * @return void + */ + private function processStoreQuotes(StoreInterface $store): void + { + $lastProcessedId = $count = 0; + + while (true) { + $quotesToProcess = $this->expiredPersistentQuotesCollection + ->getExpiredPersistentQuotes($store, $lastProcessedId, $this->batchSize); + + if (!$quotesToProcess->count()) { + break; + } + + foreach ($quotesToProcess as $quote) { + $count++; + try { + $this->quoteRepository->delete($quote); + $lastProcessedId = (int)$quote->getId(); + } catch (Exception $e) { + $this->logger->error(sprintf( + 'Unable to delete expired quote (ID: %s): %s', + $quote->getId(), + (string)$e + )); + } + if ($count % $this->batchSize === 0) { + $this->snapshot->clear($quote); + } + $quote->clearInstance(); + unset($quote); + } + + $quotesToProcess->clear(); + unset($quotesToProcess); + } + } +} diff --git a/vendor/magento/module-persistent/Model/ResourceModel/ExpiredPersistentQuotesCollection.php b/vendor/magento/module-persistent/Model/ResourceModel/ExpiredPersistentQuotesCollection.php new file mode 100644 index 0000000000000..291bf855af937 --- /dev/null +++ b/vendor/magento/module-persistent/Model/ResourceModel/ExpiredPersistentQuotesCollection.php @@ -0,0 +1,104 @@ +scopeConfig->getValue( + Data::XML_PATH_LIFE_TIME, + ScopeInterface::SCOPE_WEBSITE, + $store->getWebsiteId() + ); + + $lastLoginCondition = gmdate("Y-m-d H:i:s", time() - $lifetime); + + /** @var $quotes Collection */ + $quotes = $this->quoteCollectionFactory->create(); + + $additionalQuotes = clone $quotes; + $additionalQuotes->addFieldToFilter('main_table.store_id', (int)$store->getId()); + $additionalQuotes->addFieldToFilter('main_table.updated_at', ['lt' => $lastLoginCondition]); + $additionalQuotes->addFieldToFilter('main_table.is_persistent', 1); + $additionalQuotes->addFieldToFilter('main_table.entity_id', ['gt' => $lastId]); + $additionalQuotes->setOrder('entity_id', Collection::SORT_ORDER_ASC); + $additionalQuotes->setPageSize($batchSize); + + $select1 = clone $additionalQuotes->getSelect(); + $select2 = clone $additionalQuotes->getSelect(); + + //case 1 - customer logged in and logged out + $select1->reset(Select::COLUMNS) + ->columns('main_table.entity_id') + ->joinLeft( + ['cl1' => $additionalQuotes->getTable('customer_log')], + 'cl1.customer_id = main_table.customer_id', + [] + )->where('cl1.last_login_at < cl1.last_logout_at + AND cl1.last_logout_at IS NOT NULL'); + + //case 2 - customer logged in and not logged out but session expired + //case 3 - customer logged in, logged out, logged in and then session expired + $select2->reset(Select::COLUMNS) + ->columns('main_table.entity_id') + ->joinLeft( + ['cl2' => $additionalQuotes->getTable('customer_log')], + 'cl2.customer_id = main_table.customer_id', + [] + )->where('cl2.last_login_at < "' . $lastLoginCondition . '" + AND (cl2.last_logout_at IS NULL OR cl2.last_login_at > cl2.last_logout_at)'); + + $selectQuoteIds = $additionalQuotes + ->getConnection() + ->select() + ->union( + [ + $select1, + $select2 + ], + Select::SQL_UNION_ALL + ); + + $quotes->getSelect()->where('main_table.entity_id IN (' . $selectQuoteIds . ')'); + + return $quotes; + } +} diff --git a/vendor/magento/module-persistent/Observer/ClearExpiredCronJobObserver.php b/vendor/magento/module-persistent/Observer/ClearExpiredCronJobObserver.php index e155442c3e1e4..387543795fd44 100644 --- a/vendor/magento/module-persistent/Observer/ClearExpiredCronJobObserver.php +++ b/vendor/magento/module-persistent/Observer/ClearExpiredCronJobObserver.php @@ -1,49 +1,63 @@ _websiteCollectionFactory = $websiteCollectionFactory; $this->_sessionFactory = $sessionFactory; + $this->cleanExpiredPersistentQuotes = $cleanExpiredPersistentQuotes; } /** * Clear expired persistent sessions * - * @param \Magento\Cron\Model\Schedule $schedule + * @param Schedule $schedule * @return $this * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function execute(\Magento\Cron\Model\Schedule $schedule) + public function execute(Schedule $schedule) { $websiteIds = $this->_websiteCollectionFactory->create()->getAllIds(); if (!is_array($websiteIds)) { @@ -52,6 +66,7 @@ public function execute(\Magento\Cron\Model\Schedule $schedule) foreach ($websiteIds as $websiteId) { $this->_sessionFactory->create()->deleteExpired($websiteId); + $this->cleanExpiredPersistentQuotes->execute((int) $websiteId); } return $this; diff --git a/vendor/magento/module-persistent/etc/di.xml b/vendor/magento/module-persistent/etc/di.xml index bec28c0bbbcfd..c2a6be533e8ea 100644 --- a/vendor/magento/module-persistent/etc/di.xml +++ b/vendor/magento/module-persistent/etc/di.xml @@ -1,8 +1,8 @@ @@ -25,4 +25,9 @@ + + + 500 + +