확장이 클래스를 전역 적으로 덮어 쓰고 원본을 사용하려고 할 때 어떻게해야합니까?


42

우리는 Mage_Catalog_Block_Product_List_Toolbar 블록을 전체적으로 덮어 쓰는 확장을 사용하고 있습니다.

<global>
    <blocks>
        <catalog>
            <rewrite>
                <product_list_toolbar>Amasty_Shopby_Block_Catalog_Product_List_Toolbar</product_list_toolbar>
            </rewrite>
        </catalog>
    </blocks>
</global>

확장 기능은 계층화 된 탐색 범주의 컨텍스트에서 작동하지만 자체 제품 모듈의 다른 (사용자 지정)보기에 임의의 제품 목록을 삽입 할 때 다시 작성된 클래스가 제대로 작동하지 않습니다. 테스트 목적으로 만 확장을 덮어 쓰면 모든 것이 제대로 작동합니다.

확장 개발자의 커뮤니티 코드를 편집하지 않고 자체 컨트롤러에 대해서만 확장의 재 작성을 어떻게 취소 할 수 있습니까?


2
당신이 클래스를 변경하는 경우 당신은 아마 절대로이 그러나 당신이 당신 자신의 내선 Your_Extension_Block_Catalog_Product_List_Toolbar에 그 확장 클래스를 재 작성 할 수 있습니다 시도 ... Shopby 확장을 깰하지만 것이다 것은 Amasty_Shopby_Block_Catalog_Product_List_Toolbar 확장
샌더 사료 사탕

내가 알 수 있듯이 Magento <rewrite>는 클래스 당 하나만 허용 하므로 핵심 클래스를 확장하는 자체 클래스를 만들 수는 있지만 getBlock('catalog/product_list_toolbar')팩토리 메서드 를 통해 어떻게 작동하는지 잘 모르겠습니다 .
Aaron Pollock

유료 확장 프로그램 인 경우 Amasty 지원팀에 문의해야합니다. 버그로 보임
Fra

문제를 정확히 지적 했습니까? 직면 한 문제의 원인은 무엇입니까 (확장 클래스에서 어떤 기능을 수행합니까)?
FlorinelChis

1
@AaronPollock 일 수도 있지만이 문제는 여전히 필요한만큼 정확하게 물건을 덮어 쓰는 확장 프로그램에서 발생할 수 있습니다. 아마도 우리는 상속 모델 자체를 재검토하는 것이 더 나을 것입니다. 아마 믹스 인이나 특성이 도움이 될 것입니다.
kojiro

답변:


25

주의 사항 : 시스템에서 요구하는 작업을 수행하도록 설계된 방법은 없습니다. 다음은 작동하지만 프로덕션 시스템에서 광범위하게 시도한 적이 없으며 가치가 더 많은 문제가 발생할 수 있습니다. 작업 시스템의 재 작성 변경과 관련된 문제를 편안하게 디버깅 할 수있는 경우에만 진행하십시오.

1 단계는 재 작성을 취소합니다. Magento 구성 트리는 런타임에 변경할 수 있습니다. 따라서 다음 코드를 실행하면

$config = Mage::getConfig();        
$config->setNode(
    'global/blocks/catalog/rewrite/product_list_toolbar',
    'Mage_Catalog_Block_Product_List_Toolbar'
);

그런 다음 Magento는 Mage_Catalog_Block_Product_List_Toolbar나머지 요청에 대해 원래 블록을 인스턴스화합니다 .

2 단계는 모듈에서 이것을 호출 할 위치를 결정합니다. 이것은 컨트롤러를위한 것이며 컨트롤러가 끝날 때까지 인스턴스화되지 않는 블록을 다시 작성하기 때문에 컨트롤러 클래스에 다음과 같은 메소드를 추가합니다

protected function _undoRewrites()
{
    $config = Mage::getConfig();        
    $config->setNode(
        'global/blocks/catalog/rewrite/product_list_toolbar',
        'Mage_Catalog_Block_Product_List_Toolbar'
    );    
}

그런 다음 각 작업이 시작될 때이 메소드를 호출하십시오.

public function indexAction()
{
    $this->_undoRewrites();
    $test = Mage::getSingleton('core/layout')->createBlock('catalog/product_list_toolbar');        
    var_dump($test);
}

약간 어색한 것처럼 보일 수 있지만 Magento의 시스템 개체에 대해 영리한 경우에는 어색한 것이 좋습니다. 이를위한 또 다른 장소는 이벤트 controller_action_predispatch또는 controller_action_predispatch_front_controller_action이벤트 및 / 또는 조건부로 적용될 수 있습니다.

이 메소드가 호출 될 때까지 다시 쓰기가 취소되지 않는다는 것을 기억하십시오. 즉 _undoRewrites, 를 호출하기 전에 블록을 인스턴스화하려고 하면 다시 작성된 클래스가 객체를 인스턴스화하는 데 사용됩니다.


19

솔루션 1 :
컨트롤러에서 클래스를 직접 인스턴스화하려고 시도 할 수 있습니다 (php 방식)

대신에

$this->getLayout()->createBlock('catalog/product_list_toolbar');

같은 :

$block = New Magento_Catalog_Product_List_Toolbar;
$this->getLayout()->addBlock(....);

해결 방법 2 :
다른 방법은 모듈에서 원래 클래스를 확장하고 해당 클래스를 사용하는 새 클래스를 만드는 것입니다.

해결 방법 3 :
그렇지 않으면 확장 프로그램이 암호화되지 않은 경우 (우리 모두 오픈 소스를 좋아합니다.)


솔루션 2는 작동하지만 (실용적인 솔루션) rewrite동일한 기본 클래스 에서 두 번째 작업을 수행 할 수 없다는 점에서 좋지 않습니다 . 따라서 팩토리 방법이 작동하지 않습니다 (이미 이미 생각했습니다). 이 작업을 수행하는 Magento 방법이 없을 수도 있지만 조금 더 나은 방법이 있는지 알아 보겠습니다.
Aaron Pollock

해결책 2는 내가 갈 것입니다 ... 프란체스코의 대답을 볼 때까지 제안 할 준비가되었습니다. ;)
davidalger

1
솔루션 2가 가장 좋지만 솔루션 1에 대한 참고 사항 $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")은 블록 클래스 컨텍스트 에 있을 때 와 같이 createBlock에 완전한 클래스 이름을 제공 할 수도 있습니다 . /매개 변수 가 없으면 Magento는 문자열을 그대로 사용하여 클래스를 검색합니다.
Matthias Zeis

1
@Aaron Pollock, 동일한 기본 클래스에서 두 번째 재 작성을 수행 할 수 있습니다. 모듈 네임 스페이스의 이름을 Z (A 뒤에 나오는 문자)로 지정하면 magento가 Amasty 이름 대신 해당 이름을 사용합니다.
Amasty

5

동일한 클래스 별명에 대해 여러 번 다시 쓰면 Magento 구성 로더가 config.xml "wins"에서 구문 분석합니다. 이 문제를 다음과 같이 공격합니다.

  1. 자신 만의 확장 프로그램을 만드십시오.
  2. catalog/product_list_toolbar확장 프로그램에서 다시 작성
  3. Mage_Catalog_Block_Product_List_ToolbarAmasty 클래스 대신 블록을 확장하십시오 .
  4. 이 재 작성 충돌이 의도적이라는 점을 설명하면서 반원들에게 해설하십시오. MageRun을 실행하는 다른 개발자가 방금 만든 다시 쓰기 충돌을 시도하고 수정하는 것을 원하지 않습니다.
  5. 확장 프로그램의 app / etc / modules / blah.xml 파일에 종속성을 추가하여 확장 프로그램이 Amasty 확장 프로그램 이후에로드되도록하십시오.

1

Francesco가 위에서 제안한 것과 비슷하지만 실제로 전체 클래스 이름을 getModel에 전달할 수 있다고 생각합니다. 이런 식으로, 당신은 여전히 ​​똑같은 일을하고 있지만 핵심 방법을 사용합니다. 나는이 방법의 장단점을 완전히 확신하지는 못하지만 아이디어로 이것을 버릴 것이라고 생각했습니다.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

참고로, 이것이 Magento2에서 클래스를로드하는 표준 방법이 될 것이라고 믿습니다.


1

확장 코드를 약간 변경해야합니다. config.xml더 이상 자신의 클래스를 다시 쓰지 말고, 클래스 Amasty_Shopby_Block_Catalog_Product_List_Toolbar를 확장하도록 변경 하십시오 Mage_Catalog_Block_Product_List_Toolbar.


핵심 코드와 같은 확장 코드-다른 사람의 비즈니스 (정확하게 업그레이드하는 기능 유지). 만지지 않는 방법이 있어야합니다. 또한 문제는 Amasty 클래스가 임의의 제품 목록의 맥락에서 핵심 기능을 중단한다는 것입니다. 나는 내 자신의 기능을 주입하지 않습니다; 핵심 기능을 다시 활성화해야합니다. 내 수업은 내가 당신의 해결책을 따르면 비어있을 것이고 거기에 넣은 시도는 더 높은 선행 Amasty 수업에 의해 덮어 쓰여질 것입니다.
Aaron Pollock

이것은 나쁜 습관입니다. 외부 모듈은 항상 손대지 않아야합니다. 모듈을 업데이트해야하는 경우 새 버전 내에서 모든 변경 사항을 다시 실행해야합니다. 유지 관리 측면에서 악몽이 될 수 있습니다.
Michael Türk

새 블록을 만들고 Amasty 도구 모음에서 확장하는 것이 좋습니다.
Amasty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.