O que faço quando uma extensão substitui uma classe globalmente e quero usar o original?


42

Estamos usando uma extensão que substitui globalmente o bloco 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>

Embora a extensão funcione no contexto de uma categoria de navegação em camadas, a classe reescrita não funciona corretamente quando inserimos uma lista arbitrária de produtos em outra exibição (personalizada) em nosso próprio módulo interno. Se removermos a substituição da extensão apenas para fins de teste, tudo funcionará bem.

Como podemos desfazer a reescrita de uma extensão apenas para nosso próprio controlador, sem editar o código da comunidade do desenvolvedor da extensão?


2
Se você alterar a classe você provavelmente vai quebrar a extensão Shopby mas ... Nunca tentei isso, contudo, você pode apenas querer reescrever essa classe extensões em seu próprio ramal Your_Extension_Block_Catalog_Product_List_Toolbar estende Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel

Pelo que sei, o Magento permite apenas um <rewrite>por classe, portanto, embora eu possa criar minha própria classe estendendo a classe principal, não tenho certeza de como faria isso funcionar através do getBlock('catalog/product_list_toolbar')método de fábrica.
Aaron Pollock

Se for uma extensão paga, você deve entrar em contato com o suporte do Amasty, isso parece um bug
Fra

você conseguiu identificar o problema? o que causa o problema que você está enfrentando (que função na classe estendida)?
usar o seguinte código

1
@AaronPollock talvez, mas esse problema ainda pode surgir de uma extensão que sobrescreve as coisas da maneira mais ampla possível. Talvez seja melhor reexaminar o próprio modelo de herança. Talvez mixins ou características ajudem.
Kojiro

Respostas:


25

Advertências: Não existe uma maneira projetada de fazer o que você está pedindo no sistema. O seguinte deve funcionar, mas eu nunca o testei extensivamente em um sistema de produção e pode haver situações em que isso causará mais problemas do que vale a pena. Prossiga apenas se estiver confortável em depurar problemas relacionados à alteração das regravações de um sistema em funcionamento.

A etapa 1 está desfazendo a reescrita. A árvore de configuração do Magento pode ser alterada em tempo de execução. Então, se você executar o seguinte código

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

Então o Magento instancia o Mage_Catalog_Block_Product_List_Toolbarbloco original pelo restante da solicitação.

A etapa 2 é decidir onde chamar isso em seu módulo. Como isso é apenas para o seu controlador e está reescrevendo um bloco que não será instanciado até o final do seu controlador, eu adicionaria um método à sua classe de controlador, algo como isto

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

e depois chame esse método no início de cada uma de suas ações

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

Isso pode parecer um pouco desajeitado, mas acho uma boa idéia ser desajeitado (ou seja, óbvio) quando você está sendo inteligente com os objetos de sistema do Magento. Outro lugar para isso pode ser os eventos controller_action_predispatchou controller_action_predispatch_front_controller_actione / ou aplicados condicionalmente.

Lembre-se de que a reescrita não será desfeita até que esse método seja chamado. Isso significa que, se você tentar instanciar um bloco antes de chamar _undoRewrites, a classe reescrita será usada para instanciar o objeto.


19

Solução 1:
você pode tentar instanciar a classe diretamente (maneira php) no seu controlador

ao invés de

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

algo como:

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

Solução 2:
Outra abordagem seria criar uma nova classe, no seu módulo, que estenda a classe original e use essa.

Solução 3:
Caso contrário, se a extensão não estiver criptografada (todos gostamos de código aberto :), você pode tentar descobrir por que ela quebra as suas coisas


A solução 2 funciona (solução pragmática), mas não é ótima, pois não posso fazer um segundo rewritena mesma classe base. Portanto, o método de fábrica não funcionará (você já percebeu isso, eu acho). Talvez não exista uma maneira do Magento de fazer isso, mas vamos aguardar um pouco para ver se há uma maneira melhor.
Aaron Pollock

A solução 2 é o que eu iria usar ... Eu estava me preparando para sugerir isso até ver a resposta de Francesco. ;)
davidalger 23/01

1
Embora eu goste da melhor solução 2, uma observação para a solução 1: você também pode fornecer um nome completo da classe para createBlock (como $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")quando você está em um contexto de classe de bloco). Se não houver nenhum /parâmetro, o Magento usará a string como está para procurar a classe.
Matthias Zeis 23/01

1
@ Aaron Pollock, você PODE reescrever em segundo lugar na mesma classe base. Apenas nomeie o namespace do módulo como Z (qualquer letra após A) e o magento o usará em vez do Amasty.
Amasty 30/07/2014

5

Se existirem várias reescritas para o mesmo alias de classe, a última que o carregador de configuração do Magento analisa do config.xml "ganha". Eu atacaria esse problema:

  1. Crie uma nova extensão própria.
  2. Reescreva o catalog/product_list_toolbarna sua extensão
  3. Mage_Catalog_Block_Product_List_ToolbarEstenda seu bloco em vez da classe Amasty.
  4. Comente liberalmente sua classe explicando que esse conflito de reescrita é intencional. Você não quer que outro desenvolvedor que execute o MageRun tente "consertar" o conflito de reescrita que você acabou de criar.
  5. Adicione uma dependência no arquivo app / etc / modules / blah.xml da sua extensão para garantir que sua extensão seja carregada após a do Amasty.

1

Semelhante ao que Francesco sugeriu acima, mas acredito que você pode realmente passar o nome completo da classe para getModel. Dessa forma, você ainda está fazendo a mesma coisa, mas usando métodos principais para fazê-lo. Não tenho muita certeza dos prós / contras desse método, mas pensei em lançar isso como uma idéia.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

Em uma nota lateral, acredito que esta será a maneira padrão de carregar classes no Magento2.


1

Você precisa fazer uma pequena alteração no código de extensão, receio. Não reescreva a classe por conta própria config.xml, apenas mude Amasty_Shopby_Block_Catalog_Product_List_Toolbarpara estender sua classe que, por sua vez, se estende Mage_Catalog_Block_Product_List_Toolbar.


Vejo código de extensão como código principal - o negócio de outra pessoa (para manter a capacidade de atualizar de forma limpa). Deve haver uma maneira de evitar tocá-lo. Além disso, o problema é que a classe Amasty quebra a funcionalidade principal no contexto de uma lista de produtos arbitrária. Não injeto minha própria funcionalidade; Eu preciso reviver a funcionalidade principal. Minha própria classe, se eu seguisse sua solução, estaria vazia e qualquer tentativa de correção que eu introduzisse ali seria substituída pela classe Amasty, precedente mais alta.
Aaron Pollock

Este é um mau hábito. Os módulos externos devem sempre estar intocados. Se você precisar atualizar seu módulo, precisará refazer todas as suas alterações na nova versão. Isso pode se tornar um pesadelo em termos de manutenção.
Michael Türk

É melhor criar um novo bloco e estendê-lo da barra de ferramentas do Amasty, não vice-versa.
Amasty 30/07/2014
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.