Suppression d'une catégorie : prenez garde...

  • De le 10 février 2010
  • Difficulté : 2/4

Suppression d'une catégorie : prenez garde... Suite à une petite mésaventure sur un e-commerce Magento en production (1.3.2.2), j'ai pu relever un bug assez important lors de la suppression d'une catégorie à laquelle des produits étaient encore associés... Un petit correctif permet de pallier au problème.

Mise à jour 13/02/2010 : le problème a été corrigé dans les versions 1.4.0.0 CE et 1.7.0.0 EE

Malgré tous les tests de fiabilité que l'on peut effectuer avant mise en production d'un e-commerce, il y a parfois certains problèmes que l'on ne pouvait envisager qui nous tombent dessus par surprise lors d'une action totalement anodine.

Ma dernière surprise eut lieu lorsque depuis le backoffice, j'ai souhaité supprimer une catégorie obsolète (et inactive). Sur cette catégorie était encore associé quelques produits, réaffectés depuis dans d'autres catégories.

Le problème relevé fut le suivant :

Imaginons que le produit Ipod Nano soit affecté dans 2 catégories distinctes : Baladeurs Mp3 et Apple. Dans la base de données, cette information est enregistrée dans 3 tables :

  • catalog_category_product_index
  • catalog_category_product
  • catalog_product_entity

Dans un bloc quelconque du site, j'applique le code suivant :

Bloc

$collection = Mage::getResourceModel('catalog/product_collection');
        
foreach($collection as $product) {
        $categories = $product->getCategoryIds();
        
        Zend_debug::dump($categories);
                
        foreach($categories as $id) {
                $category = Mage::getModel('catalog/category')->load($id);
                echo $id.' : '.$category->getName();
        }
}

Lorsque ce script est exécuté, il affiche à l'écran :

Résultat

array(2) {
  [0] => string(1) "7"
  [1] => string(1) "8"
}

7 : Apple
8 : Baladeurs Mp3

Jusque là rien d'anormal. Mais si je décide de supprimer la catégorie Apple, sans retirer au préalable les produits qu'elle contient, voici ce que ce même script affiche :

Résultat

array(2) {
  [0] => string(1) "7"
  [1] => string(1) "8"
}

7 : 
8 : Baladeurs Mp3

Le produit semble associé à une catégorie qui n'existe plus... En effet, dans ma base de données, bien que les entrées des tables catalog_category_product_index et catalog_category_product aient disparu, la valeur de l'attribut category_ids reste inchangée (7,8 dans notre exemple). Or c'est la valeur de cet attribut que Magento récupère lors de la requête sur le produit.

Imaginez les problèmes qui pourraient survenir sur l'un de vos modules... Pour que la valeur de l'attribut soit renouvelé, il est obligatoire d'éditer le produit, puis de retirer l'ensemble des catégories auxquelles il est associé.

Je n'ai pas testé sur la version 1.4-rc1 de Magento. Pour les versions 1.3.x.x, nous allons appliquer un petit correctif.

Le module correctif sera chargé de récupérer la catégorie avant sa suppression, puis de retirer la totalité des produits qui lui sont associés.

Architecture du module

  • app/code/local/Magentix/CategoryDelete/etc/
  • config.xml
  • app/code/local/Magentix/CategoryDelete/Model/
  • Observer.php
  • app/etc/modules/
  • Magentix_CategoryDelete.xml

Développement du module

Rien de très complexe, un simple observer sur l'événement catalog_controller_category_delete :

app/code/local/Magentix/CategoryDelete/Model/Observer.php

<?php

class Magentix_CategoryDelete_Model_Observer {

        public function unset_products($observer) {
                $event = $observer->getEvent();
                $category = $event->getCategory();
                $category->setPostedProducts(array());
                $category->save();
        }
        
}

Editez ensuite le fichier de configuration :

app/code/local/Magentix/CategoryDelete/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_CategoryDelete>
            <version>0.1.0</version>
        </Magentix_CategoryDelete>
    </modules>
    <global>
        <models>
            <categorydelete>
                <class>Magentix_CategoryDelete_Model</class>
            </categorydelete>
        </models>
        <events>
            <catalog_controller_category_delete>
                <observers>
                    <unset_products>
                        <type>singleton</type>
                        <class>categorydelete/observer</class>
                        <method>unset_products</method>
                    </unset_products>
                </observers>
            </catalog_controller_category_delete>
        </events>
    </global>
</config>

Enfin procédez à la déclaration du module :

app/etc/modules/Magentix_CategoryDelete.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_CategoryDelete>
            <active>true</active>
            <codePool>local</codePool>
        </Magentix_CategoryDelete>
    </modules>
</config>
commentaires

Commentez cet article : Suppression d'une catégorie : prenez garde...