Comment puis-je modifier une chaîne passée par un événement?


10

Dans ma fonction d'observateur, j'obtiens une variable passée par l'événement comme ça:

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

Si sthest un objet, je peux le modifier en appelant des méthodes dessus. Mais comment puis-je modifier sths'il s'agit d'une simple chaîne? J'ai essayé ce qui suit sans succès:

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

Je viens d'apprendre que certains événements passent également par un objet de transport dans lequel la chaîne peut être modifiée (merci Alex ), mais l'événement page_block_html_topmenu_gethtml_afterne le fait pas. Alors qu'est-ce que je peux faire?

L'événement en question est distribué comme ceci et je veux modifier $ html:

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

Réponses:


12

Tu ne peux pas.

La raison pour laquelle l'approche des objets de transport fonctionne est que les objets PHP sont des alias / références . Lorsque vous modifiez un objet, vous modifiez le One True Object.

Les types primitifs de PHP (entiers, chaînes, booléens, etc.) ne sont pas des objets et relèvent des règles de passage par valeur de PHP pour les arguments. Si un développeur de module Magento vous passe une chaîne brute dans un observateur d'événements

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

c'est leur façon de dire

Vous pouvez regarder cette valeur, mais je ne veux pas que vous la modifiiez.

Nous laisserons s'il s'agit d'une décision de conception délibérée ou d'un développeur ne réfléchissant pas aux choses comme un exercice pour le lecteur.

Quant à votre question non posée, si vous souhaitez modifier le menu du haut, il y a quelques approches que je prendrais. Accrocher à l' page_block_html_topmenu_gethtml_beforeévénement et modifier l' menuobjet

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

devrait fonctionner, car _menuest un objet

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

Deuxièmement, vous pouvez réécrire la classe génératrice de menus

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

Troisièmement, vous pouvez utiliser des mises à jour de mise en page pour supprimer le bloc de menu supérieur existant et insérer un nouveau bloc avec une classe personnalisée que vous avez créée. Votre classe personnalisée étendrait la classe de menu supérieure existante, puis redéfinir getHtml. Ceci est plus compliqué, mais évite les problèmes associés aux réécritures.


5

Je dirais que c'est un bug de conception dans cet événement.

Les objets sont transmis par référence, ils peuvent donc être manipulés. Les chaînes sont toujours copiées. Donc, dans ce cas, la chaîne ne peut pas être manipulée à l'intérieur de l'observateur, même l' page_block_html_topmenu_gethtml_afterévénement me semble juste que son but est de vous donner une chance de manipuler le $html.


3

Il est possible de modifier la sortie du bloc via une chaîne transportée en observant l' core_block_abstract_to_html_afterévénement (lien) . Dans ce cas, le contenu rendu est transporté de l'instance de bloc vers l'instance d'observateur et, plus important encore, le contenu transporté est ce qui est renvoyé par la classe de bloc. Notez qu'il y a une considération importante de mise en cache que j'ai expliquée ci-dessous l'exemple.

Exemple

Étant donné que cet événement est déclenché pour chaque rendu de bloc, vous devez configurer l'observateur en tant que singleton et tester que le type de bloc est une instance de 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);
     }
}

Votre logique de manipulation pourrait être implémentée dans la méthode d'observation ou placée dans une autre méthode dans l'observateur.

Problèmes

Parce qu'il implique une manipulation de sortie et que l'observateur est appelé pour tous les rendus de bloc, cela ne doit être utilisé que lorsque la principale préoccupation est d'éviter une réécriture de bloc. En outre, le contenu généré dans cet observateur est manipulé en block_htmlécriture post- cache (via l'appel de l'instance de bloc à _saveCache()), vous devez donc soit mettre en cache l' block_htmlentrée dans l'observateur (un peu collant, car vous utiliseriez soit Reflection ou dupliquer la logique des méthodes _saveCache()et _getSidPlaceholder()pour écrire l'entrée de cache. Et enfin, si vous avez besoin de manipuler quoi que ce soit concernant les données du nœud d'arbre, vous devrez générer une copie des données du nœud d'arbre. Cela pourrait théoriquement être fait par attraper le Mage_Catalog_Model_Observersingleton et en saisir l'arbre ... très collant en effet.


1
Je déteste la mise en œuvre de Magento du TopMenu avec l'essence même de mon âme. Je me cogne régulièrement la tête contre toute implémentation qui nécessite une personnalisation de la navigation. Ils ont rendu très difficile de modifier cette sortie HTML de manière discrète; Magento vous combat à chaque étape.
wlvrn le

Eh bien, oui, le menu est trop rigide, mais vous obtenez un peu de fonctionnalités qui fonctionnent.
benmarks
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.