如何更改事件传递的字符串?


10

在观察者函数中,我得到了事件传递的变量,如下所示:

public function observerFunc(Varien_Event_Observer $observer)
{
    $sth = $observer->getEvent()->getSth();
}

如果sth是一个对象,我可以通过在其上调用方法来对其进行更改。但是,sth如果它是一个简单的字符串,该如何更改?我尝试了以下操作但未成功:

public function observerFunc(Varien_Event_Observer $observer)
{
    $sth = $observer->getEvent()->getSth();
    $observer->getEvent()->setSth('test');
    $observer->setSth('test');
}

我刚刚了解到,某些事件还传递了一个传输对象,在该对象中可以更改字符串(感谢Alex),但是该事件page_block_html_topmenu_gethtml_after不能。那我该怎么办?

有问题的事件是这样发送的,我想更改$ html:

$html = $this->_getHtml($this->_menu, $childrenWrapClass);
Mage::dispatchEvent('page_block_html_topmenu_gethtml_after', array(
    'menu' => $this->_menu,
    'html' => $html
));

Answers:


12

你不能

传输对象方法起作用的原因是PHP的对象是aliases / references。修改对象时,您正在修改一个真实对象。

PHP的原始类型(int,字符串,布尔值等)不是对象,并且属于PHP的参数传递值规则。如果Magento模块开发人员在事件观察器中向您传递了原始字符串

    Mage::dispatchEvent('page_block_html_topmenu_gethtml_after', array(
        'menu' => $this->_menu,
        'html' => $html
    ));

那是他们说的方式

您可以查看此值,但我不希望您修改它。

我们将离开这是一个故意的设计决定,还是一个开发人员不考虑任何事情作为练习供读者阅读。

关于您尚未提出的问题,如果您想修改顶部菜单,则可以采用以下几种方法。钩住page_block_html_topmenu_gethtml_before事件并修改menu对象

    Mage::dispatchEvent('page_block_html_topmenu_gethtml_before', array(
        'menu' => $this->_menu
    ));

应该工作,因为_menu是一个对象

/**
 * Top menu data tree
 *
 * @var Varien_Data_Tree_Node
 */
protected $_menu;

其次,您可以重写菜单生成类

public function getHtml($outermostClass = '', $childrenWrapClass = '')
{
    $html = parent::getHtml($outermostClass, $childrenWrapClass);
    //monkey with $html here to add your menu items or custom markup
    return $html;
}

第三,您可以使用布局更新来删除现有的顶部菜单块,并使用您创建的自定义类插入新的块。您的自定义类将扩展现有的顶级菜单类,然后重新定义getHtml。这更加复杂,但是避免了与重写相关的问题。


5

我会说那是该事件中的设计错误。

对象通过引用传递,因此可以对其进行操作。字符串总是被复制。因此,在这种情况下,无法在观察者内部操纵字符串,即使该page_block_html_topmenu_gethtml_after事件在我看来也是如此,其目的是为您提供操纵的机会$html


3

可以经由输送串通过观察来修改块输出core_block_abstract_to_html_after事件(链接)。在这种情况下,渲染的内容从块实例传输到观察者实例,并且-最重要的是-传输的内容是块类返回的内容。请注意,有一个重要的缓存注意事项,我在示例下面进行了解释。

由于会为每个块渲染触发此事件,因此您应将观察者配置为单例并测试块类型是的实例Mage_Page_Block_Html_Topmenu

public function manipulateTopmenuOutput(Varien_Event_Observer $obs)
{
     if ($obs->getBlock() instanceof Mage_Page_Block_Html_Topmenu){
         $initialOutput = $obs->getTransport()->getHtml();
         //e.g. $modified output = $this->yourManipulationMethod($initialOutput);
         $obs->getTransport()->setHtml($modifiedOutput);
     }
}

您的操作逻辑可以在观察方法中实现,也可以在观察者中的另一个方法中放置。

问题

因为它涉及输出操作,并且所有块渲染都调用了观察者,所以只有在主要考虑避免块重写时才应使用此方法。另外,在此观察器中生成的内容是在block_html高速缓存后写入(通过块实例对的调用_saveCache())中进行操作的,因此您要么需要block_html在观察器中重新缓存条目(有点黏,因为您将使用反射或从_saveCache()_getSidPlaceholder()方法复制逻辑来写入缓存条目,最后,如果您需要处理与树节点数据有关的任何事情,则必须生成树节点数据的副本,理论上,这可以通过以下方式完成:抓住Mage_Catalog_Model_Observer单例并从中抓住树...确实很粘。


1
我非常真心地讨厌Magento对TopMenu的实现。在需要导航自定义的任何实现过程中,我都会经常碰到它。他们使得以不显眼的方式调整HTML输出变得非常困难。Magento与您战斗的每一步。
wlvrn

好吧,是的,菜单是不恰当的,但是您确实获得了很多起作用的功能。
benmarks 2013年
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.