Que dois-je faire quand une extension écrase une classe globalement et que je veux utiliser l'original?

42

Nous utilisons une extension qui remplace globalement le bloc Mage_Catalog_Block_Product_List_Toolbar.

<global>
    <blocks>
        <catalog>
            <rewrite>
                <product_list_toolbar>Amasty_Shopby_Block_Catalog_Product_List_Toolbar</product_list_toolbar>
            </rewrite>
        </catalog>
    </blocks>
</global>

Bien que l'extension fonctionne dans le contexte d'une catégorie de navigation par couches, la classe réécrite ne fonctionne pas correctement lorsque nous insérons une liste de produits arbitraire dans une autre vue (personnalisée) de notre propre module interne. Si nous supprimons le remplacement d'extension uniquement à des fins de test, tout fonctionne correctement.

Comment annuler la réécriture d'une extension uniquement pour notre propre contrôleur, sans modifier le code de communauté du développeur de l'extension?

Aaron Pollock
la source
2
Si vous changez de classe, l'extension de Shopby sera probablement cassée mais ... Jamais essayé, mais vous voudrez peut-être simplement réécrire cette classe d'extensions dans votre propre extension Your_Extension_Block_Catalog_Product_List_Toolbar étend Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel
D'après ce que je peux dire, Magento n'autorise qu'un seul cours <rewrite>par classe. Par conséquent, bien que je puisse créer ma propre classe en étendant la classe principale, je ne suis pas sûr de la façon dont cela fonctionnerait via la getBlock('catalog/product_list_toolbar')méthode usine.
Aaron Pollock
S'il est une extension Payed vous devez contacter le support Amasty, ce regard comme bug
Fra
avez-vous réussi à cerner le problème? Quelles sont les causes du problème auquel vous êtes confronté (quelle fonction dans la classe étendue)?
FlorinelChis
1
@AaronPollock peut-être, mais ce problème pourrait toujours provenir d'une extension qui écrase les choses exactement aussi largement qu'il le faut. Nous ferions peut-être mieux de réexaminer le modèle d’héritage lui-même. Peut-être que mixins ou traits aidera.
Kojiro

Réponses:

25

Mises en garde: Il n'y a pas de moyen conçu de faire ce que vous demandez dans le système. Ce qui suit devrait fonctionner, mais je n’ai jamais fait d’essais sur un système de production et il peut arriver que cela cause plus de problèmes qu’il en vaut la peine. Continuez uniquement si vous êtes à l'aise avec les problèmes de débogage liés à la modification de la réécriture d'un système en fonctionnement.

L'étape 1 annule la réécriture. L'arborescence de configuration de Magento peut être modifiée lors de l'exécution. Donc, si vous exécutez le code suivant

$config = Mage::getConfig();        
$config->setNode(
    'global/blocks/catalog/rewrite/product_list_toolbar',
    'Mage_Catalog_Block_Product_List_Toolbar'
);

Ensuite, Magento instanciera le Mage_Catalog_Block_Product_List_Toolbarbloc d' origine pour le reste de la demande.

La deuxième étape consiste à décider où appeler ceci dans votre module. Comme ceci est juste pour votre contrôleur et qu'il réécrit un bloc qui ne sera pas instancié avant la fin de votre contrôleur, j'ajouterais une méthode à votre classe de contrôleur, quelque chose comme ceci

protected function _undoRewrites()
{
    $config = Mage::getConfig();        
    $config->setNode(
        'global/blocks/catalog/rewrite/product_list_toolbar',
        'Mage_Catalog_Block_Product_List_Toolbar'
    );    
}

puis appelez simplement cette méthode au début de chacune de vos actions

public function indexAction()
{
    $this->_undoRewrites();
    $test = Mage::getSingleton('core/layout')->createBlock('catalog/product_list_toolbar');        
    var_dump($test);
}

Cela peut sembler un peu maladroit, mais je pense que c'est une bonne idée d'être maladroit (c'est-à-dire évident) lorsque vous êtes malin avec les objets système de Magento. Un autre endroit pour cela pourrait être le controller_action_predispatchou les controller_action_predispatch_front_controller_actionévénements et / ou appliqué de manière conditionnelle.

Rappelez-vous simplement que la réécriture ne sera pas annulée jusqu'à ce que cette méthode soit appelée. Cela signifie que si vous essayez d'instancier un bloc avant d'appeler _undoRewrites, la classe réécrite sera utilisée pour instancier l'objet.

Alan Storm
la source
19

Solution 1:
Vous pouvez essayer d’instancier la classe directement (façon php) dans votre contrôleur

au lieu de

$this->getLayout()->createBlock('catalog/product_list_toolbar');

quelque chose comme:

$block = New Magento_Catalog_Product_List_Toolbar;
$this->getLayout()->addBlock(....);

Solution 2:
Une autre approche serait de créer une nouvelle classe, dans votre module, qui étend la classe d'origine et de l'utiliser.

Solution 3:
sinon, si l'extension n'est pas cryptée (nous aimons tous l'open source :), vous pouvez essayer de savoir pourquoi cela casse vos données

Fra
la source
La solution 2 fonctionne (solution pragmatique) mais ce n’est pas génial car je ne peux pas faire une seconde rewritesur la même classe de base. Par conséquent, la méthode d'usine ne fonctionnera pas (vous l'avez déjà compris, je pense). Peut-être qu’il n’ya pas de moyen Magento de faire cela, mais attendons un peu pour voir s’il existe un meilleur moyen.
Aaron Pollock
J'allais avec la solution 2 ... Je m'apprêtais à suggérer cela jusqu'à ce que je voie la réponse de Francesco. ;)
davidalger
1
Même si la solution 2 me convient le mieux, remarque à la solution 1: vous pouvez également fournir un nom de classe complet à createBlock (comme dans le $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")contexte de classe de bloc). S'il n'y a pas /de paramètre dans les paramètres, Magento utilisera simplement la chaîne telle quelle pour rechercher la classe.
Matthias Zeis
1
@ Aaron Pollock, vous POUVEZ faire une deuxième réécriture sur la même classe de base. Il suffit de nommer l’espace de nom du module comme Z (toute lettre après A) et magento l’utilisera à la place de Amasty.
Amasty
5

S'il existe plusieurs réécritures pour le même alias de classe, le dernier chargeur analysé par le chargeur de configuration Magento à partir de config.xml "gagne". J'attaquerais ce problème par:

  1. Créez votre propre extension.
  2. Réécris le catalog/product_list_toolbardans ton extension
  3. Demandez à votre bloc d'étendre Mage_Catalog_Block_Product_List_Toolbarau lieu de la classe Amasty.
  4. Commentez généreusement votre classe en expliquant que ce conflit de réécriture est intentionnel. Vous ne voulez pas qu'un autre développeur qui exécute MageRun tente de "réparer" le conflit de réécriture que vous venez de créer.
  5. Ajoutez une dépendance dans le fichier app / etc / modules / blah.xml de votre extension pour vous assurer que votre extension est chargée après celle d'Amasty.
Jim OHalloran
la source
1

Semblable à ce que Francesco a suggéré ci-dessus, mais je pense que vous pouvez en fait donner le nom complet de la classe à getModel. De cette façon, vous faites un peu la même chose, mais vous utilisez des méthodes de base pour le faire. Je ne suis pas tout à fait sûr des avantages / inconvénients de cette méthode, mais je pensais que ce serait une idée.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

En passant, je pense que ce sera le moyen standard de charger des classes dans Magento2.

jmspldnl
la source
1

Vous devez faire un léger changement dans le code d'extension, j'ai peur. Ne réécrivez plus la classe dans la vôtre config.xml, changez simplement Amasty_Shopby_Block_Catalog_Product_List_Toolbarpour étendre votre classe qui à son tour s'étend Mage_Catalog_Block_Product_List_Toolbar.

Paul Grigoruta
la source
Je vois le code d'extension comme un code de base - l'activité de quelqu'un d'autre (pour maintenir la capacité de mise à niveau proprement). Il doit y avoir un moyen d'éviter de le toucher. En outre, le problème est que la classe Amasty rompt la fonctionnalité principale dans le contexte d’une liste de produits arbitraire. Je n'injecte pas ma propre fonctionnalité; J'ai besoin de réactiver les fonctionnalités de base. Ma propre classe, si je suivais votre solution, serait vide et toute tentative de correction que je mettrais dedans serait écrasée par la classe supérieure précédente, Amasty.
Aaron Pollock
C'est une mauvaise habitude. Les modules externes doivent toujours être intacts. Si vous devez mettre à jour votre module, vous devrez refaire toutes vos modifications dans la nouvelle version. Cela pourrait devenir un cauchemar en termes de maintenabilité.
Michael Türk
Vous feriez mieux de créer un nouveau bloc et de l'étendre à partir de la barre d'outils Amasty, et non l'inverse.
Amasty