Co mam zrobić, gdy rozszerzenie globalnie nadpisuje klasę i chcę użyć oryginału?

42

Używamy rozszerzenia, które globalnie zastępuje blok 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>

Podczas gdy rozszerzenie działa w kontekście warstwowej kategorii nawigacji, przepisana klasa nie działa poprawnie, gdy wstawimy dowolną listę produktów do innego (niestandardowego) widoku w naszym własnym module wewnętrznym. Jeśli wyjmujemy nadpisywanie rozszerzenia tylko do celów testowych, wszystko działa dobrze.

Jak możemy cofnąć przepisywanie rozszerzenia tylko dla naszego własnego kontrolera, bez edytowania kodu społeczności programisty rozszerzenia?

Aaron Pollock
źródło
2
Jeśli zmienisz klasę, prawdopodobnie zepsujesz rozszerzenie Shopby, ale ... Nigdy tego nie próbowałeś, ale możesz po prostu przepisać tę klasę rozszerzeń we własnym rozszerzeniu Your_Extension_Block_Catalog_Product_List_Toolbar rozszerza Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel
Z tego, co mogę powiedzieć, Magento zezwala tylko na jedną <rewrite>na klasę, więc chociaż mógłbym stworzyć własną klasę rozszerzającą klasę podstawową, nie jestem pewien, jak sprawiłbym, żeby działała metodą getBlock('catalog/product_list_toolbar')fabryczną.
Aaron Pollock
Jeśli jest to płatne rozszerzenie, powinieneś skontaktować się z pomocą techniczną Amasty, wygląda to na błąd
Fra
udało ci się wskazać problem? co powoduje napotkany problem (która funkcja w klasie rozszerzonej)?
FlorinelChis
1
@AaronPollock może, ale ten problem może nadal wynikać z rozszerzenia, które zastępuje rzeczy tak dokładnie, jak to konieczne. Być może lepiej byłoby ponownie przeanalizować sam model dziedziczenia. Może pomogą miksy lub cechy.
kojiro

Odpowiedzi:

25

Ostrzeżenia: Nie ma specjalnie zaprojektowanego sposobu na wykonanie tego, o co prosisz w systemie. Następujące elementy powinny działać, ale nigdy nie wypróbowałem tego szeroko na systemie produkcyjnym, i mogą wystąpić sytuacje, w których spowoduje to więcej problemów, niż jest to warte. Kontynuuj tylko, jeśli nie masz problemów z debugowaniem związanych ze zmianą przepisywania działającego systemu.

Krok 1 polega na cofnięciu przepisywania. Drzewo konfiguracji Magento można zmienić w czasie wykonywania. Jeśli uruchomisz następujący kod

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

Następnie Magento utworzy oryginalny Mage_Catalog_Block_Product_List_Toolbarblok dla pozostałej części żądania.

Krok 2 decyduje, gdzie wywołać to w swoim module. Ponieważ jest to tylko dla twojego kontrolera i przepisuje blok, który nie zostanie utworzony do końca twojego kontrolera, dodałbym metodę do twojej klasy kontrolera coś takiego

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

a następnie po prostu wywołaj tę metodę na początku każdej akcji

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

To może wydawać się trochę niezręczne, ale myślę, że dobrym pomysłem jest być niezręcznym (tj. Oczywistym), gdy jesteś sprytny z obiektami systemowymi Magento. Innym miejscem tego mogą być zdarzenia controller_action_predispatchlub controller_action_predispatch_front_controller_actionzdarzenia i / lub stosowane warunkowo.

Pamiętaj tylko, że przepisywanie nie zostanie cofnięte, dopóki ta metoda nie zostanie wywołana. Oznacza to, że jeśli spróbujesz utworzyć blok przed wywołaniem _undoRewrites, do przepisania obiektu zostanie użyta zmieniona klasa.

Alan Storm
źródło
19

Rozwiązanie 1:
Możesz spróbować utworzyć instancję klasy bezpośrednio (sposób php) w ​​kontrolerze

zamiast

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

coś jak:

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

Rozwiązanie 2:
Innym podejściem byłoby utworzenie nowej klasy w module, która rozszerzy klasę oryginalną i skorzystanie z niej.

Rozwiązanie 3:
W przeciwnym razie, jeśli rozszerzenie nie jest szyfrowane (wszyscy uwielbiamy open source :) możesz spróbować dowiedzieć się, dlaczego to psuje twoje rzeczy

Fra
źródło
Rozwiązanie 2 działa (rozwiązanie pragmatyczne), ale nie jest świetne, ponieważ nie mogę zrobić sekundy rewritena tej samej klasie bazowej. Dlatego metoda fabryczna nie zadziała (zdałeś sobie z tego sprawę, myślę, że już). Może nie ma na to sposobu Magento, ale zastanówmy się, czy jest lepszy sposób.
Aaron Pollock
Rozwiązaniem 2 jest to, z czym bym poszedł ... Przygotowywałem się, by to zasugerować, dopóki nie zobaczyłem odpowiedzi Francesco. ;)
davidalger
1
Chociaż najbardziej podoba mi się rozwiązanie 2, uwaga do rozwiązania 1: możesz także podać pełną nazwę klasy, aby utworzyć blok (tak jak $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")wtedy, gdy jesteś w kontekście klasy blokowej). Jeśli nie ma /parametru Magento, po prostu użyje łańcucha, aby wyszukać klasę.
Matthias Zeis
1
@Aaron Pollock, MOŻESZ zrobić drugie przepisanie tej samej klasy bazowej. Po prostu nazwij przestrzeń nazw modułu na Z (dowolna litera po A), a magento użyje jej zamiast Amasty.
Amasty
5

Jeśli istnieje wiele przeróbek dla tego samego aliasu klasy, to ostatni moduł ładujący konfigurację Magento analizuje z pliku config.xml „wygrywa”. Zaatakowałbym ten problem przez:

  1. Utwórz własne rozszerzenie.
  2. Przepisz catalog/product_list_toolbarw swoim rozszerzeniu
  3. Niech twój blok zostanie przedłużony Mage_Catalog_Block_Product_List_Toolbarzamiast klasy Amasty.
  4. Swobodnie komentuj swoją klasę, wyjaśniając, że ten konflikt przepisywania jest celowy. Nie chcesz, aby inny programista, który uruchamia MageRun, próbował „naprawić” właśnie utworzony konflikt przepisywania.
  5. Dodaj zależność w pliku aplikacji / etc / modules / blah.xml rozszerzenia, aby mieć pewność, że rozszerzenie zostanie załadowane po Amasty.
Jim OHalloran
źródło
1

Podobne do tego, co sugerował Francesco powyżej, ale wierzę, że możesz przekazać pełną nazwę klasy, aby uzyskać getModel. W ten sposób nadal robisz to samo, ale używasz do tego podstawowych metod. Nie jestem całkowicie pewien zalet / wad tej metody, ale pomyślałem, że przedstawię to jako pomysł.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

Na marginesie, uważam, że będzie to standardowy sposób ładowania klas w Magento2.

jmspldnl
źródło
1

Obawiam się, że musisz wprowadzić niewielką zmianę w kodzie rozszerzenia. Nie przepisuj już klasy we własnym zakresie config.xml, po prostu zmień, Amasty_Shopby_Block_Catalog_Product_List_Toolbaraby rozszerzyć klasę, która z kolei się wydłuży Mage_Catalog_Block_Product_List_Toolbar.

Paul Grigoruta
źródło
Widzę kod rozszerzenia jak kod podstawowy - czyjąś firmę (aby zachować możliwość czystej aktualizacji). Musi istnieć sposób, który pozwoli go nie dotknąć. Problem polega także na tym, że klasa Amasty łamie podstawową funkcjonalność w kontekście dowolnej listy produktów. Nie wstrzykuję własnej funkcjonalności; Muszę ożywić podstawową funkcjonalność. Moja własna klasa, gdybym podążała za twoim rozwiązaniem, byłaby pusta, a wszelkie próby wprowadzenia poprawek, które tam wprowadzę, zostałyby zastąpione przez wyższą precedensową klasę Amasty.
Aaron Pollock
To zły nawyk. Moduły zewnętrzne powinny być zawsze nietknięte. Jeśli musisz zaktualizować moduł, musisz ponownie wykonać wszystkie zmiany w nowej wersji. Może to stać się koszmarem pod względem łatwości konserwacji.
Michael Türk
Lepiej utwórz nowy blok i rozszerz go o pasek narzędzi Amasty, a nie odwrotnie.
Amasty