Come posso modificare una stringa passata da un evento?


10

Nella mia funzione di osservatore, ottengo una variabile passata dall'evento in questo modo:

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

Se sthè un oggetto, posso modificarlo chiamando metodi su di esso. Ma come posso modificare sthse è una stringa semplice? Ho provato quanto segue senza successo:

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

Ho appena appreso che alcuni eventi passano anche un oggetto di trasporto in cui la stringa può essere modificata (grazie Alex ), ma l'evento page_block_html_topmenu_gethtml_afterno. Quindi cosa posso fare?

L'evento in questione viene inviato in questo modo e voglio modificare $ html:

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

Risposte:


12

Non puoi.

Il motivo per cui funziona l'approccio con oggetto di trasporto è che gli oggetti di PHP sono alias / riferimenti . Quando modifichi un oggetto, stai modificando One True Object.

I tipi primitivi di PHP (ints, stringhe, booleani, ecc.) Non sono oggetti e rientrano nelle regole pass by PHP per gli argomenti. Se uno sviluppatore del modulo Magento ti passa una stringa non elaborata in un osservatore di eventi

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

questo è il loro modo di dire

Puoi guardare questo valore, ma non voglio che tu lo modifichi.

Lasceremo se questa è una decisione di progettazione deliberata o uno sviluppatore che non pensa alle cose come un esercizio per il lettore.

Per quanto riguarda la tua domanda non posta, se vuoi modificare il menu principale, ci sono alcuni approcci che prenderei. Collegarsi page_block_html_topmenu_gethtml_beforeall'evento e modificare l' menuoggetto

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

dovrebbe funzionare, poiché _menuè un oggetto

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

In secondo luogo, è possibile riscrivere la classe generatrice di 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;
}

In terzo luogo, è possibile utilizzare gli aggiornamenti del layout per rimuovere il blocco di menu superiore esistente e inserire un nuovo blocco con una classe personalizzata creata. La classe personalizzata estenderebbe la classe di menu principale esistente e quindi ridefinirà getHtml. Questo è più complicato, ma evita i problemi associati alle riscritture.


5

Direi che è un bug di progettazione in quell'evento.

Gli oggetti vengono passati per riferimento, quindi possono essere manipolati. Le stringhe vengono sempre copiate. Quindi in questo caso la stringa non può essere manipolata all'interno dell'osservatore, anche l' page_block_html_topmenu_gethtml_afterevento mi sembra che il suo scopo sia quello di darti la possibilità di manipolare il $html.


3

Si è possibile modificare uscita del blocco con stringa trasportati osservando l' core_block_abstract_to_html_afterevento (link) . In questo caso, il contenuto renderizzato viene trasportato dall'istanza del blocco all'istanza dell'osservatore e, soprattutto, il contenuto trasportato è ciò che viene restituito dalla classe di blocco. Si noti che esiste un'importante considerazione per la memorizzazione nella cache che ho spiegato di seguito nell'esempio.

Esempio

Poiché questo evento viene generato per ogni rendering di blocco, è necessario configurare l'osservatore come singleton e verificare che il tipo di blocco sia un'istanza di 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);
     }
}

La tua logica di manipolazione potrebbe essere implementata nel metodo di osservazione o inserita in un altro metodo nell'osservatore.

Problemi

Poiché comporta la manipolazione dell'output e l'osservatore viene chiamato per tutti i rendering a blocchi, questo dovrebbe essere usato solo quando la preoccupazione principale è evitare una riscrittura dei blocchi. Inoltre, il contenuto generato in questo osservatore viene manipolato in block_htmlscrittura post- cache (tramite la chiamata dell'istanza di blocco a _saveCache()), quindi è necessario ricollegare nella cache la block_htmlvoce nell'osservatore (un po 'appiccicoso, poiché si utilizza Riflessione o duplicando la logica da entrambi i metodi _saveCache()e _getSidPlaceholder()per scrivere la voce della cache. E infine, se è necessario manipolare qualsiasi cosa relativa ai dati del nodo dell'albero, si dovrebbe generare una copia dei dati del nodo dell'albero. Ciò potrebbe teoricamente essere fatto da afferrare il Mage_Catalog_Model_Observersingleton e afferrare l'albero da esso ... davvero molto appiccicoso.


1
Odio l'implementazione di Magento di TopMenu con l'essenza stessa della mia anima. Di solito mi sbatto contro di esso durante qualsiasi implementazione che richiede la personalizzazione della navigazione. Hanno reso super difficile modificare l'output HTML in modo discreto; Magento ti combatte ad ogni passo.
wlvrn,

Bene, sì, il menu è inappropriatamente non flessibile, ma ottieni un bel po 'di funzionalità che funziona.
benmarks
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.