Magento : Mettre en cache le load d’un produit

Vous connaissez certainement le fameux $product->load($product->getId()) qui va peupler votre objet en allant chercher les valeurs en base de données. Cette méthode n’utilise pas le cache Magento alors qu’elle est assez gourmande en requêtes SQL. Voici donc un petit exemple de mise en cache du load produit qui vous permettra de soulager un peu votre serveur MySQL.

Configuration du module

Rendez-vous dans app/code/local/Namespace/Catalog/etc/config.xml :

<?xml version="1.0"?>
<config>
    <modules>
        <Namespace_Catalog>
            <version>0.1.0</version>
        </Namespace_Catalog>
    </modules>
    <global>
        <models>
            <catalog>
                <rewrite>
                    <product>Namespace_Catalog_Model_Product</product>
                </rewrite>
            </catalog>
        </models>
        <cache>
            <types>
                <product_loading>
                    <label>Product Loading</label>
                    <description>Cache of product attributes loading.</description>
                    <tags>catalog_product</tags>
                </product_loading>
            </types>
        </cache>
    </global>
</config>

On a donc créé un nouveau type de cache qui nous permettra d’activer et de désactiver le cache sur le load produit. Voici ce qu’on obtient dans la liste des types de cache dans l’admin :

Surcharge de la méthode load()

Ouvrir le fichier app/code/local/Namespace/Catalog/Model/Product.php :

<?php
 
class Namespace_Catalog_Model_Product extends Mage_Catalog_Model_Product
{
    public function load($id, $field = null)
    {
        if (null !== $field || !Mage::app()->useCache('product_loading')) {
            return parent::load($id, $field);
        }
 
        // Caching product data
        Varien_Profiler::start(__METHOD__);
        $storeId = (int) $this->getStoreId();
        $cacheId = "product-$id-$storeId";
        if ($cacheContent = Mage::app()->loadCache($cacheId)) {
            $data = unserialize($cacheContent);
            if (!empty($data)) {
                foreach ($data as $key => &$value){
                    $this->$key = $value;
                }
                unset($value);
            }
        } else {
            parent::load($id);
 
            // You can call some heavy methods here
 
            try {
                $cacheContent = serialize(get_object_vars($this));
                $tags = array(
                    Mage_Catalog_Model_Product::CACHE_TAG,
                    Mage_Catalog_Model_Product::CACHE_TAG . '_' . $id
                );
                $lifetime = Mage::getStoreConfig('core/cache/lifetime');
                Mage::app()->saveCache($cacheContent, $cacheId, $tags, $lifetime);
            } catch (Exception $e) {
                // Exception = no caching
                Mage::logException($e);
            }
        }
        Varien_Profiler::stop(__METHOD__);
 
        return $this;
    }
}

Je vous laisse vérifier vous-même si le nombre de requête SQL diminue bien une fois le cache activé mais sachez qu’il existe des barres de debug qui peuvent vous faciliter la vie, en voici une : https://github.com/madalinoprea/magneto-debug.

12 réponses à “Magento : Mettre en cache le load d’un produit”

  1. Anh Quy dit :

    Hi Reinke.
    great article, but there is a problem, when you turn on the cache. product information in the admin is having problems about display, the default value and default store view use the same cache and product information shown is incorrect.
    can you help me to handle the case this!
    thanks

  2. Marc dit :

    This looks extremely useful. Thanks for sharing this Johann.

    Quick question though (since there’ve been no updates to the comment thread):
    Has the problem reported by Anh Quy been fixed?

  3. Ryan dit :

    Hello, great work. Just wondering if you fixed the admin issues?

    Thanks!

  4. Mathis dit :

    For Fixing Issues with the Admin Panel u have to set « Mage::app()->getStore()->isAdmin() » at the top:
    also added to [email protected]: https://gist.github.com/4517079
    Code:

    public function load($id, $field = null)
    {
    if(Mage::app()->getStore()->isAdmin())
    {
    return parent::load($id, $field = null);
    }

  5. Mido dit :

    Maybe a stupid question: but i was trying to add this method of caching products.

    So i created the directories like you ment, but i cant get extra cache type. What i am doing wrong?

    Using Magento 1.7

    looking forward to your reply!

  6. Joshua dit :

    I am also working on getting this working, I have a custom extension that I placed this in and it’s not fireing, so I instead put it into it’s own name space and folder as suggested in this article and still can’t get it to fire.

    I have added debugging points in ths script to log data using Mage::log but nothing get’s written to the log, so there is something funny going on not allowing the Load to trigger.

  7. Eric dit :

    I would recommend updating the cache tags. With the current setup whenever any product is updated all product cache records are removed. A better solution would seem to be updating the tags entry in the config to:
    namespace_product
    And in the load method:
    Namespace_Catalog_Model_Product::CUSTOM_CACHE_TAG,

  8. Toni dit :

    I am having the same issue as some people here. The folder structure was recreated and the files have been created and uploaded to corresponding folders. However the option does not show in the back and as suggested by the original post.

    What am I doing wrong here?

  9. Dimitry dit :

    Thanks for the code! I keep coming up on a problem: I get a « Node no longer exists » error when unserializing. Have you seen this problem?

    • Dimitry dit :

      Found a solution. After parent::load($id), add $this->_urlModel = null; It prevents the _urlModel attribute from being cached. That’s okay since it’s always repopulated by Mage_Catalog_Model_Product::getUrlModel().

  10. Daniel dit :

    Hi! I’d like to know what happens if I have a configurable product composed by multiple simple products (let’s say a shoe with different sized), and one simple product becomes out-of-stock. How is the caché refreshed to don’t allow to select the exhausted size?

Laisser un commentaire

* Champs requis

Categories