Cosa devo fare quando un'estensione sovrascrive una classe a livello globale e voglio usare l'originale?


42

Stiamo usando un'estensione che sovrascrive globalmente il blocco 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>

Mentre l'estensione funziona nel contesto di una categoria di navigazione a più livelli, la classe riscritta non funziona correttamente quando inseriamo un elenco di prodotti arbitrario in un'altra vista (personalizzata) nel nostro modulo interno. Se eliminiamo la sovrascrittura dell'estensione solo a scopo di test, tutto funziona bene.

Come possiamo annullare la riscrittura di un'estensione solo per il nostro controller, senza modificare il codice comunità dello sviluppatore dell'estensione?


2
Se cambi la classe probabilmente interromperai l'estensione Shopby ma ... Non l'hai mai provato, tuttavia potresti voler riscrivere quella classe di estensioni nella tua estensione Your_Extension_Block_Catalog_Product_List_Toolbar estende Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel

Da quello che posso dire, Magento ne consente solo uno <rewrite>per classe, quindi anche se potrei creare la mia classe estendendo la classe principale, non sono sicuro di come riuscirò a farlo funzionare con il getBlock('catalog/product_list_toolbar')metodo factory.
Aaron Pollock il

Se si tratta di un'estensione a pagamento, è necessario contattare il supporto Amasty, questo aspetto da bug
Fra

sei riuscito a individuare il problema? che cosa causa il problema che stai affrontando (quale funzione nella classe estesa)?
FlorinelChis

1
@AaronPollock forse, ma questo problema potrebbe ancora derivare da un'estensione che sovrascrive le cose esattamente nel modo più ampio necessario. Forse staremmo meglio riesaminando il modello di eredità stesso. Forse mixins o tratti aiuteranno.
Kojiro,

Risposte:


25

Avvertenze: non esiste un modo progettato per fare ciò che stai chiedendo nel sistema. Quanto segue dovrebbe funzionare, ma non l'ho mai provato ampiamente su un sistema di produzione e potrebbero esserci situazioni in cui causerà più problemi che valga la pena. Procedere solo se si ha dimestichezza con i problemi di debug relativi alla modifica delle riscritture di un sistema funzionante.

Il passaggio 1 sta annullando la riscrittura. L'albero di configurazione di Magento può essere modificato in fase di esecuzione. Quindi, se si esegue il seguente codice

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

Quindi Magento creerà un'istanza del Mage_Catalog_Block_Product_List_Toolbarblocco originale per il resto della richiesta.

Il passaggio 2 sta decidendo dove chiamarlo nel tuo modulo. Poiché questo è solo per il tuo controller e sta riscrivendo un blocco che non verrà istanziato fino alla fine del controller, aggiungerei un metodo alla tua classe controller qualcosa del genere

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

e quindi chiama questo metodo all'inizio di ciascuna delle tue azioni

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

Questo può sembrare un po 'goffo, ma penso che sia una buona idea essere goffo (cioè ovvio) quando sei intelligente con gli oggetti di sistema di Magento. Un altro posto per questo potrebbe essere il controller_action_predispatcho controller_action_predispatch_front_controller_actioneventi e / o applicato in modo condizionale.

Ricorda solo che la riscrittura non verrà annullata fino a quando non verrà chiamato questo metodo. Ciò significa che se si tenta di creare un'istanza di un blocco prima di chiamare _undoRewrites, la classe riscritta verrà utilizzata per creare un'istanza dell'oggetto.


19

Soluzione 1:
è possibile provare a creare un'istanza della classe direttamente (modo php) nel controller

invece di

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

qualcosa di simile a:

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

Soluzione 2: un
altro approccio sarebbe quello di creare una nuova classe, nel tuo modulo, che estenda la classe originale e la usi.

Soluzione 3:
Altrimenti se l'estensione non è crittografata (tutti amiamo l'open source :) puoi provare a scoprire perché ti rompe le cose


La soluzione 2 funziona (soluzione pragmatica) ma non è eccezionale in quanto non posso fare un secondo rewritesulla stessa classe base. Pertanto il metodo di fabbrica non funzionerà (te ne sei reso conto credo già). Forse non c'è un modo Magento per farlo, ma teniamoci un po 'per vedere se c'è un modo migliore.
Aaron Pollock,

La soluzione 2 è quella con cui vorrei andare ... Mi stavo preparando a suggerire fino a quando non ho visto la risposta di Francesco. ;)
davidalger,

1
Anche se mi piace la soluzione 2 il migliore, una nota per la soluzione 1: si può anche fornire un nome completo della classe a createBlock (come in $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")quando il vostro sono in un contesto di classe blocco). Se non è presente alcun /parametro nel parametro Magento utilizzerà semplicemente la stringa così com'è per cercare la classe.
Matthias Zeis,

1
@Aaron Pollock, PUOI fare una seconda riscrittura sulla stessa classe base. Basta nominare lo spazio dei nomi del modulo come Z (qualsiasi lettera dopo A) e Magento lo userà invece di uno Amasty.
Amasty,

5

Se esistono più riscritture per lo stesso alias di classe, l'ultimo che il caricatore di configurazione Magento analizza da config.xml "vince". Attaccherei questo problema con:

  1. Crea una tua nuova estensione.
  2. Riscrivi il catalog/product_list_toolbarnella tua estensione
  3. Fai estendere il tuo blocco Mage_Catalog_Block_Product_List_Toolbarinvece della classe Amasty.
  4. Commenta liberamente la tua classe spiegando che questo conflitto di riscrittura è intenzionale. Non vuoi che un altro sviluppatore che esegue MageRun tenti di "risolvere" il conflitto di riscrittura che hai appena creato.
  5. Aggiungi una dipendenza nel file app / etc / modules / blah.xml della tua estensione per assicurarti che l'estensione sia caricata dopo quella di Amasty.

1

Simile a quello che Francesco ha suggerito sopra, ma credo che tu possa effettivamente passare il nome completo della classe a getModel. In questo modo, stai ancora facendo la stessa cosa, ma usando metodi di base per farlo. Non sono del tutto sicuro dei pro / contro di questo metodo, ma ho pensato di buttarlo lì come idea.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

A proposito, credo che questo sarà il modo standard per caricare le classi in Magento2.


1

Ho bisogno di fare una leggera modifica nel codice di estensione, temo. Non riscrivere più la classe nella tua config.xml, cambia solo Amasty_Shopby_Block_Catalog_Product_List_Toolbarper estendere la tua classe che a sua volta si estende Mage_Catalog_Block_Product_List_Toolbar.


Vedo il codice di estensione come il codice di base - attività di qualcun altro (per mantenere la capacità di aggiornare in modo pulito). Ci deve essere un modo per evitare di toccarlo. Inoltre, il problema è che la classe Amasty rompe la funzionalità principale nel contesto di un elenco di prodotti arbitrario. Non iniettare la mia funzionalità; Devo ripristinare la funzionalità di base. La mia classe, se dovessi seguire la tua soluzione, sarebbe vuota e qualsiasi tentativo di correzione che inserissi sarebbe sovrascritto dalla precedente classe Amasty precedente.
Aaron Pollock il

Questa è una cattiva abitudine. I moduli esterni devono essere sempre intatti. Se è necessario aggiornare il modulo, è necessario ripetere tutte le modifiche nella nuova versione. Questo potrebbe diventare un incubo in termini di manutenibilità.
Michael Türk,

Faresti meglio a creare un nuovo blocco ed estenderlo DA barra degli strumenti di Amasty, non viceversa.
Amasty,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.