当扩展全局覆盖一个类并且我想使用原始类时该怎么办?


42

我们正在使用一个扩展程序,该扩展程序将覆盖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>

虽然扩展程序在分层导航类别的上下文中起作用,但是当我们在自己的内部模块中将任意产品列表插入另一个(自定义)视图时,重写的类无法正常工作。如果我们仅出于测试目的删除扩展覆盖,则一切正常。

我们如何只为自己的控制器撤消扩展的重写,而无需编辑扩展开发人员的社区代码?


2
如果您更改类,则可能会破坏Shopby扩展名,但是...从未尝试过,但是您可能只想在自己的扩展名中重写该扩展名类Your_Extension_Block_Catalog_Product_List_Toolbar扩展了Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel

据我所知,Magento <rewrite>每个类只允许一个类,因此尽管我可以创建自己的类来扩展核心类,但是我不确定如何通过getBlock('catalog/product_list_toolbar')工厂方法来使其工作。
亚伦·波洛克

如果它是一个祈祷,扩展你应该联系Amasty支持,这看起来像是错误
法兰克福机场

您设法找出问题了吗?是什么导致您遇到的问题(扩展类中的哪个函数)?
FlorinelChis

1
@AaronPollock也许可以,但是这个问题仍然可能源于扩展,它可以完全覆盖所需的内容。也许最好重新检查继承模型本身。混合或特性可能会有所帮助。
kojiro

Answers:


25

注意事项:在系统中没有设计好的方法来完成您要问的事情。以下应该可行,但是我从未在生产系统上进行过广泛尝试,并且在某些情况下可能会造成更多值得的麻烦。仅当您愿意调试与更改工作系统重写有关的问题时,才继续进行。

步骤1是撤消重写。Magento配置树可以在运行时更改。因此,如果您运行以下代码

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

然后,Magento将为Mage_Catalog_Block_Product_List_Toolbar其余请求实例化原始块。

步骤2是确定在模块中的何处调用此函数。由于这仅适用于您的控制器,并且正在重写一个块,直到您的控制器结束时才实例化该块,因此我将向您的控制器类中添加一个类似以下方法的方法

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

然后在每个动作开始时调用此方法

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

这似乎有点笨拙,但是当您对Magento的系统对象很聪明时,笨拙(即显而易见)是个好主意。这里的另一个地方可能是controller_action_predispatchcontroller_action_predispatch_front_controller_action事件和/或有条件地应用。

请记住,在调用此方法之前,不会撤消重写。这意味着,如果您尝试在调用之前实例化一个块_undoRewrites,则重写的类将用于实例化该对象。


19

解决方案1:
您可以尝试在控制器中直接实例化该类(用PHP方式)

代替

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

就像是:

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

解决方案2:
另一种方法是在您的模块中创建一个新类,以扩展原始类并使用该类。

解决方案3:
否则,如果扩展名未加密(我们都喜欢开放源代码:),则可以尝试找出扩展名破坏您的原因


解决方案2确实可​​以工作(实用的解决方案),但是它并不是很棒,因为我不能rewrite在同一基类上再做一遍。因此,工厂方法将不起作用(我已经意识到了这一点)。也许没有Magento的方法可以做到这一点,但让我们稍作停留,看看是否有更好的方法。
亚伦·波洛克

解决方案2是我将要使用的解决方案...我准备提出建议,直到我看到Francesco的回答。;)
davidalger 2013年

1
尽管我最喜欢解决方案2,但对解决方案1的注释:您也可以为createBlock提供完整的类名(例如在$this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")块类上下文中)。如果/参数中没有,Magento将按原样使用字符串搜索类。
Matthias Zeis

1
@Aaron Pollock,您可以在同一基类上进行第二次重写。只需将模块名称空间命名为Z(A后面的任何字母),magento就会使用它而不是Amasty。
2014年

5

如果同一类别名存在多个重写,则Magento配置加载器最后一次从config.xml中解析“ wins”。我可以通过以下方法解决此问题:

  1. 创建自己的新扩展名。
  2. catalog/product_list_toolbar在您的扩展程序中重写
  3. 让您的块Mage_Catalog_Block_Product_List_Toolbar而不是Amasty类扩展。
  4. 自由地评论您的班级,解释这种重写冲突是故意的。您不希望其他运行MageRun的开发人员尝试“修复”您刚创建的重写冲突。
  5. 在扩展程序的app / etc / modules / blah.xml文件中添加一个依赖项,以确保扩展程序在Amasty加载后被加载。

1

与上面的Francesco建议类似,但我相信您实际上可以将完整的类名传递给getModel。这样,您仍然在做相同的事情,但是使用核心方法来做。我不确定这种方法的优点/缺点,但是我想把它当作一个想法。

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

附带一提,我相信这将是在Magento2中加载类的标准方法。


1

恐怕您确实需要对扩展代码稍作更改。不要再重写自己的类config.xml,只需进行更改Amasty_Shopby_Block_Catalog_Product_List_Toolbar以扩展您的类,然后再扩展即可Mage_Catalog_Block_Product_List_Toolbar


我看到扩展代码像核心代码一样-是别人的事(以保持干净升级的能力)。必须有一种避免碰触它的方法。同样,问题在于Amasty类在任意产品列表的上下文中破坏了核心功能。我不注入自己的功能;我需要恢复核心功能。如果要遵循您的解决方案,我自己的课程将是空的,而我在其中输入的任何尝试的修复方法都将被更高先例的Amasty课程覆盖。
亚伦·波洛克

这是个坏习惯。外部模块应始终保持原样。如果需要更新模块,则需要在新版本中重做所有更改。就可维护性而言,这可能成为噩梦。
MichaelTürk2013年

您最好创建一个新块,然后从Amasty工具栏对其进行扩展,而不是相反。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.