Correction d'une régression introduite par la version 1.7.8.4 de Prestashop sur la gestion des Hooks

Suite à la remontée successive de plusieurs utilisateurs de la dernière version 1.7.8.4 de Prestashop sur des modules ne fonctionnant plus ou ne s'affichant plus convenablement sur leur boutique, il fut découvert une évolution problématique dans le code de la gestion des Hooks de PrestaShop.

Qu'est ce qu'un Hook sur PrestaShop

PrestaShop intègre une gestion des emplacements d'affichage des éléments sur les boutiques sous forme de Hook soit des points d'accroche ou tout module ou tout code peut-être rattachées donc être exécutée chaque fois que le Hook est appelé.

Il existe plusieurs types de Hook.

  • Les Hooks d'affichage qui servent à simplement afficher des éléments en des emplacements précis.
  • Les Hooks d'action qui sont appelés lorsqu'une action est effectuée dans Prestashop, par exemple, lorsqu'un produit est mis à jour, ou encore lorsqu'une commande est validée.

On rencontre souvent des modules qui sont développés sans connaître l'existence et les usages de ces Hooks, ce qui peut provoquer de gros soucis. On rencontre beaucoup de développeurs qui préfèrent passer par leurs scripts personnalisés sans jamais utiliser ces systèmes et donc empêchent les autres modules rattachés convenablement d'être informé des modifications effectuées et donc risquent de provoquer des erreurs en base de données, des incohérences de données ou autre.

L'usage des Hooks est primordial pour tout développement de modules respectant le fonctionnement de PrestaShop.

Le Bug (régression) de la version 1.7.8.4 de PrestaShop.

La version 1.7.8.4 a changé le code de récupération des Hook dans la base de données.

Ce changement est cohérent mais il a oublié un élément-clé : La casse.

Ainsi, si l'on code mal le nom du Hook appelé, cela ne fonctionne plus.

Avant que vous appeliez le hook ainsi hookDisplayHeader ou hookdisplayheader, cela fonctionnait, ce qui n'est plus le cas sur cette version.

Le code

Le code avant la modification :

    public static function getHookStatusByName($hook_name): bool
    {
        $sql = new DbQuery();
        $sql->select('active');
        $sql->from('hook', 'h');
        $sql->where('h.name = "' . pSQL($hook_name) . '"');

        return (bool) Db::getInstance()->getValue($sql);
    }

Le code qui provoque l'erreur :

    public static function getHookStatusByName($hook_name): bool
    {
        $hook_names = [];
        if (Cache::isStored('active_hooks')) {
            $hook_names = Cache::retrieve('active_hooks');
        } else {
            $sql = new DbQuery();
            $sql->select('name');
            $sql->from('hook', 'h');
            $sql->where('h.active = 1');
            $active_hooks = Db::getInstance()->executeS($sql);
            if (!empty($active_hooks)) {
                $hook_names = array_column($active_hooks, 'name');
                if (is_array($hook_names)) {
                    Cache::store('active_hooks', $hook_names);
                }
            }
        }

        return in_array($hook_name, $hook_names);
    }

L'explication du problème

Dans l'ancien code nous constatons que l'on ne fait appel qu'à une simple requête SQL qui elle n'est pas sensible à la casse.

Alors que dans le second code, on retrouve un texte in_array() qui lui est sensible à la casse, d'où l'erreur de traitement qui est engendrée du fait de différentes dénominations avec des majuscules ou non des Hooks.

La correction

Pour apporter une solution à ce problème c'est assez simple il faut toujours traiter les données en minuscule pour éliminer la problématique des majuscules.

Cela semble être une évidence et beaucoup de développeurs utilisent ce système pour justement ne pas devoir gérer les erreurs de nommage.

Il faut donc, pour corriger le problème, ouvrir le fichier :

classes/Hook.php

remplacer la ligne 1280

$sql->select('name');

par

$sql->select('lower(name) as name');

puis remplacer la ligne 1292

return in_array($hook_name, $hook_names);

par

return in_array(strtolower($hook_name), $hook_names);

Glossaire

Conclusion

Quel que soit votre niveau de développement, vous devez apprendre à anticiper les potentielles erreurs de ce type, car elles sont insidieuses et peuvent vous faire perdre beaucoup de temps en recherche de solutions car elles sont difficiles à identifier, alors pensez-y lors de vos prochains développements.

Sources : https://github.com/PrestaShop/PrestaShop/pull/27874