Description
Description
Hello,
I faced a memory limit issue on the backoffice customer view because the customer has an high number of orders (more than 1000) with an high number of product.
As the CustomerChecker to allow customer erase loads them all, the requirement memory is higher than the 4G allowed.
Class :
https://github.com/opengento/magento2-gdpr/blob/master/Model/Customer/CustomerChecker.php
Prerequisites
PHP Version:
- 8.3
Magento Version:
- 2.4.7-p4
Module Version:
- 4.4.2
Desktop (if applicable):
NA
Smartphone (if applicable):
NA
Issue Details
As OrderRepositoryInterface is used to load the full collection of orders (and their content) an high amount of order consumes an high amount of memory (to count them)
Steps to reproduce the behavior
- Create a customer with an high number of complex orders
- Click on the customer view access on the backoffice customer grid
- See error
Expected behavior
A count check should not impact to heavily the loading of the customer view
Screenshots
Additional context
I do understand that using OrderRepositoryInterface is a good practice in the magento ecosystem.
I only think that it's not adapted when you only want to count the number of orders.
There is a pretty strong performance enhancement by just using an OrderCollectionFactory and calling getSize() instead of loading the entire collection with all the child data.
In addition to that, as the class is final, plugins cannot be declared to add the wanted behavior properly.
Here is the preference I've implemented which works with my current volume.
<?php
/*
* Copyright Blablabla
*/
namespace CustomerDomain\Customer\Preference\Gdpr\Model\Customer;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Model\ResourceModel\Order\CollectionFactory as CollectionFactory;
use Opengento\Gdpr\Model\Config;
use Opengento\Gdpr\Model\Entity\EntityCheckerInterface;
/**
* We need to reimplement the checker because it loads all orders data
* and this is causing memory limit issue for customer with more than 1000 orders
*/
class CustomerChecker implements EntityCheckerInterface
{
/**
* @var bool[] Local cache for the values
*/
private array $cache;
/**
* Constructor
*
* @param CollectionFactory $orderCollectionFactory
* @param Config $config
*/
public function __construct(
private readonly CollectionFactory $orderCollectionFactory,
private readonly Config $config
) {
// Nothing to do here
}
/**
* @inheritDoc
*/
public function canErase(int $entityId): bool
{
if (!isset($this->cache[$entityId])) {
$this->cache[$entityId] = (0 === $this->orderCollectionFactory->create()
->addFieldToFilter(OrderInterface::STATE, ['nin' => $this->config->getAllowedStatesToErase()])
->addFieldToFilter(OrderInterface::CUSTOMER_ID, ['eq' => $entityId])
->getSize());
}
return $this->cache[$entityId];
}
}