イベントによって渡される文字列を変更するにはどうすればよいですか?


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
));

回答:


12

できません。

トランスポートオブジェクトアプローチが機能する理由は、PHPのオブジェクトがエイリアス/参照であるためです。オブジェクトを変更すると、One True Objectが変更されます。

PHPのプリミティブ型(int、string、booleansなど)はオブジェクトではなく、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;
}

3番目に、レイアウトの更新を使用して既存のトップメニューブロックを削除し、作成したカスタムクラスで新しいブロックを挿入できます。カスタムクラスは、既存のトップメニュークラスを拡張し、を再定義し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 2013

ええ、はい、メニューは不適切に柔軟性がありませんが、機能するかなりの機能が得られます。
ベンマークス2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.