Как я могу изменить строку, переданную событием?

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

Я только что узнал, что некоторые события также передают транспортный объект, в котором строка может быть изменена (спасибо Алекс ), но событие 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 (целые числа, строки, логические значения и т. Д.) Не являются объектами и подпадают под действие правил передачи значений аргументов в 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.

Alex
источник
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запись в наблюдателе (немного липко, как если бы вы использовали Reflection или дублируя логику от обоего _saveCache()и _getSidPlaceholder()методов , чтобы написать записи кэша. и , наконец, если вам нужно манипулировать ничего , относящееся к данным дерева узлов, вы должны генерировать копию данных дерева узлов. Это теоретически может быть сделано схватил Mage_Catalog_Model_Observerсинглтон и схватил с него дерево ... действительно очень липкое.

benmarks
источник
1
Я ненавижу реализацию TopMenu в Magento с самой сущностью моей души. Я постоянно сталкиваюсь с этим во время любой реализации, которая требует настройки навигации. Они сделали очень сложным незаметное изменение вывода HTML; Magento борется с вами на каждом этапе пути.
wlvrn
Ну, да, меню неуместно негибко, но вы получаете немало функциональности, которая работает.
отметки