Bagaimana saya bisa mengubah string yang dilewati oleh suatu peristiwa?

10

Dalam fungsi pengamat saya, saya mendapatkan variabel yang dilewati oleh acara seperti itu:

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

Jika sthmerupakan objek, saya dapat mengubahnya dengan memanggil metode di atasnya. Tetapi bagaimana saya bisa mengubah sthjika ini adalah string sederhana? Saya mencoba yang berikut ini tanpa hasil:

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

Saya baru tahu bahwa beberapa peristiwa juga melewati objek transportasi di mana string dapat diubah (terima kasih Alex ), tetapi acara page_block_html_topmenu_gethtml_aftertidak. Jadi apa yang bisa saya lakukan?

Acara tersebut akan dikirim seperti ini dan saya ingin mengubah $ html:

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

Jawaban:

12

Kamu tidak bisa

Alasan pendekatan objek transport bekerja adalah objek PHP adalah alias / referensi . Saat Anda memodifikasi suatu objek, Anda memodifikasi One True Object.

Tipe primitif PHP (int, string, boolean, dll.) Bukan objek, dan berada di bawah aturan nilai pass PHP untuk argumen. Jika pengembang modul Magento memberikan Anda string mentah kepada pengamat acara

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

itu cara mereka mengatakan

Anda dapat melihat nilai ini, tetapi saya tidak ingin Anda memodifikasinya.

Kami akan meninggalkan apakah ini keputusan desain yang disengaja atau pengembang tidak memikirkan semuanya sebagai latihan untuk pembaca.

Mengenai pertanyaan Anda yang tidak diminta, jika Anda ingin mengubah menu paling atas, ada beberapa pendekatan yang akan saya ambil. Mengaitkan ke dalam page_block_html_topmenu_gethtml_beforeacara dan memodifikasi menuobjek

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

harus bekerja, karena _menumerupakan objek

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

Kedua, Anda dapat menulis ulang kelas penghasil 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;
}

Ketiga, Anda bisa menggunakan pembaruan tata letak untuk menghapus blok menu teratas yang ada, dan menyisipkan blok baru dengan kelas khusus yang Anda buat. Kelas khusus Anda akan memperluas kelas menu top yang ada, dan kemudian mendefinisikan kembali getHtml. Ini lebih rumit, tetapi menghindari masalah yang terkait dengan penulisan ulang.

Alan Storm
sumber
5

Saya akan mengatakan itu adalah bug desain dalam acara itu.

Objek diteruskan dengan referensi, sehingga mereka dapat dimanipulasi. String selalu disalin. Jadi dalam hal ini senar tidak dapat dimanipulasi di dalam pengamat, bahkan page_block_html_topmenu_gethtml_afteracara hanya tampak bagi saya seperti tujuannya adalah untuk memberi Anda kesempatan untuk memanipulasi $html.

Alex
sumber
3

Hal ini dimungkinkan untuk memodifikasi blok output melalui serangkaian diangkut dengan mengamati core_block_abstract_to_html_afteracara (link) . Dalam hal ini, konten yang diberikan diangkut dari instance blok ke instance observer, dan - yang paling penting - konten yang diangkut adalah apa yang dikembalikan oleh kelas blok. Perhatikan bahwa ada pertimbangan caching yang penting yang saya jelaskan di bawah contoh ini.

Contoh

Karena acara ini dipecat untuk setiap blok render, Anda harus mengonfigurasi pengamat sebagai singleton dan menguji bahwa tipe blok adalah turunan dari 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);
     }
}

Logika manipulasi Anda dapat diterapkan dalam metode mengamati atau ditempatkan di metode lain di pengamat.

Masalah

Karena melibatkan manipulasi keluaran dan pengamat dipanggil untuk semua render blok, ini hanya boleh digunakan ketika masalah utama adalah menghindari blok tulis ulang. Juga, konten yang dihasilkan dalam pengamat ini adalah manipulasi post- block_htmlcache write (melalui panggilan instance blok ke _saveCache()), jadi Anda harus melakukan cache ulang block_htmlentri di pengamat (agak lengket, karena Anda akan menggunakan Refleksi atau menggandakan logika dari kedua metode _saveCache()dan _getSidPlaceholder()metode untuk menulis entri cache. Dan akhirnya, jika Anda perlu memanipulasi apa pun yang berkaitan dengan data simpul pohon, Anda harus menghasilkan salinan data simpul pohon. Ini secara teoritis dapat dilakukan oleh meraih Mage_Catalog_Model_Observersingleton dan meraih pohon itu ... memang sangat lengket.

tanda batas
sumber
1
Saya benci penerapan Magento tentang Topen dengan esensi jiwa saya. Saya secara rutin membenturkan kepala saya ke sana selama implementasi yang membutuhkan penyesuaian navigasi. Mereka membuatnya super-sulit untuk men-tweak output HTML itu dengan cara yang tidak mencolok; Magento berkelahi dengan Anda setiap langkah.
wlvrn
Ya, menu itu tidak fleksibel, tetapi Anda mendapatkan cukup banyak fungsionalitas yang berfungsi.
patokan