Nghi Nguyen
Nghi Nguyen

Reputation: 121

Display quantity on category page Magento 2

I would like to display the quantity of product on category pages. I have tried the stockRegistry and it works just fine. However, when it runs on the production environment, for a category with a large number of products, it makes error 500 or other errors which describe does not have the response from the server. I believe the reason is the stockRegistry created too many requests that cause the problem.

My code is below:

class ListProduct extends \Magento\Catalog\Block\Product\ListProduct {
    private $_stockRegistry;

    private $stockHelper;

    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
        \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
        \Magento\Catalog\Model\Layer\Resolver $layerResolver,
        CategoryRepositoryInterface $categoryRepository,
        \Magento\Framework\Url\Helper\Data $urlHelper,
        \Magento\CatalogInventory\Api\StockRegistryInterface 
        $stockRegistry,
        Stock $stockHelper,
        array $data = []
    )
    {
        $this->_stockRegistry = $stockRegistry;
        $this->stockHelper = $stockHelper;

        parent::__construct(
            $context,
            $postDataHelper,
            $layerResolver,
            $categoryRepository,
            $urlHelper,
            $data
        );
    }


    public function getProductStock($id) {
        return $this->_stockRegistry->getStockItem($id)->getQty();
    }
}

And of course, I have updated my XML file to use this class instead.

What would be the way to get the quantity to display on category pages with a better performance?

Upvotes: 1

Views: 1737

Answers (1)

Sorbo
Sorbo

Reputation: 339

The correct way to do this is to get quantities for all products on the page

namespace Example\CatalogInventory\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Stock extends AbstractDb
{
    /**
     * {@inheritdoc}
     */
    protected function _construct()
    {
        $this->_init('cataloginventory_stock_item', 'item_id');
    }

    /**
     * Retrieve products quantities
     * Return array as key product id, value - qty
     */
    public function getProductsStockQty($productIds, $websiteId, $stockId = \Magento\CatalogInventory\Model\Stock::DEFAULT_STOCK_ID)
    {
        $select = $this->getConnection()->select()
            ->from($this->getMainTable(), ['product_id', 'qty'])
            ->where('product_id IN(?)', $productIds)
            ->where('stock_id=?', (int)$stockId)
            ->where('website_id=?', (int)$websiteId);

        return $this->getConnection()->fetchPairs($select);
    }
}

And use it in your custom block:

class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
{
    /**
     * @var \Example\CatalogInventory\Model\ResourceModel\Stock
     */
    private $stock;

    /**
     * @var array
     */
    private $quantities;

    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
        \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
        \Magento\Catalog\Model\Layer\Resolver $layerResolver,
        \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository,
        \Magento\Framework\Url\Helper\Data $urlHelper,
        \Example\CatalogInventory\Model\ResourceModel\Stock $stock,
        array $data = []
    ) {
        parent::__construct($context, $postDataHelper, $layerResolver, $categoryRepository, $urlHelper, $data);
        $this->stock = $stock;
    }

    public function getProductStock($productId)
    {
        if (!$this->quantities) {
            $this->quantities = $this->stock->getProductsStockQty(
                $this->getLoadedProductCollection()->getLoadedIds(),
                $this->_storeManager->getStore()->getWebsiteId()
            );
        }

        return $this->quantities[$productId] ?? 0;
    }
}

Upvotes: 1

Related Questions