이벤트가 전달한 문자열을 어떻게 변경합니까?


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의 객체 가 별칭 / 참조 이기 때문 입니다. 객체를 수정하면 하나의 진정한 객체가 수정됩니다.

PHP의 기본 유형 (int, strings, 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;
}

셋째, 레이아웃 업데이트를 사용하여 기존 최상위 메뉴 블록을 제거하고 생성 한 사용자 정의 클래스가있는 새 블록을 삽입 할 수 있습니다. 사용자 정의 클래스는 기존 최상위 메뉴 클래스를 확장 한 다음 재정의 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()and _getSidPlaceholder()메소드 에서 논리를 복제하고 마지막으로 트리 노드 데이터와 관련된 항목을 조작해야하는 경우 트리 노드 데이터의 사본을 생성해야합니다. 잡고 Mage_Catalog_Model_Observer싱글을 매우 끈적 참 ... 그것에서 나무를 잡아.


1
나는 내 영혼의 본질로 Magento의 TopMenu 구현을 싫어합니다. 내비게이션 사용자 지정이 필요한 모든 구현 중에 나는 정기적으로 내 머리를 부딪칩니다. 그들은 HTML 출력을 눈에 띄지 않게 조정하기가 매우 어려워졌습니다. 마 젠토는 모든 단계에서 당신과 싸 웁니다.
wlvrn

글쎄, 메뉴는 부적절하게 융통성이 없지만, 당신은 작동하는 약간의 기능을 얻습니다.
benmarks
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.