Was mache ich, wenn eine Erweiterung eine Klasse global überschreibt und ich das Original verwenden möchte?

42

Wir verwenden eine Erweiterung, die den Mage_Catalog_Block_Product_List_Toolbar-Block global überschreibt.

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

Während die Erweiterung im Kontext einer geschichteten Navigationskategorie funktioniert, funktioniert die umgeschriebene Klasse nicht ordnungsgemäß, wenn wir eine beliebige Produktliste in eine andere (benutzerdefinierte) Ansicht in unserem eigenen internen Modul einfügen. Wenn wir die Erweiterung nur zu Testzwecken überschreiben, funktioniert alles einwandfrei.

Wie können wir das Umschreiben einer Erweiterung nur für unseren eigenen Controller rückgängig machen, ohne den Community-Code des Erweiterungsentwicklers zu bearbeiten?

Aaron Pollock
quelle
2
Wenn Sie die Klasse ändern werden Sie wahrscheinlich die Shopby Erweiterung brechen , aber ... nie versucht , dies jedoch können Sie nur diese Erweiterungen Klasse in Ihrer eigenen Nebenstelle neu zu schreiben wollen Your_Extension_Block_Catalog_Product_List_Toolbar erweitert Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel
<rewrite>Nach allem, was ich sagen kann, erlaubt Magento nur eine pro Klasse. Obwohl ich meine eigene Klasse erstellen konnte, um die Kernklasse zu erweitern, bin ich mir nicht sicher, wie ich sie über die getBlock('catalog/product_list_toolbar')Factory-Methode zum Laufen bringen würde .
Aaron Pollock
Wenn es sich um eine Erweiterung bezahle ist , sollten Sie Amasty Support kontaktieren, diesen Blick als Bug
Ab
haben Sie es geschafft, das Problem genau zu bestimmen? Was verursacht das Problem, mit dem Sie konfrontiert sind (welche Funktion in der erweiterten Klasse)?
FlorinelChis
1
@AaronPollock vielleicht, aber dieses Problem könnte immer noch von einer Erweiterung herrühren, die die Dinge genau so weit überschreibt, wie es nötig ist. Vielleicht ist es besser, das Vererbungsmodell selbst erneut zu untersuchen. Vielleicht helfen Mixins oder Eigenschaften.
Kojiro

Antworten:

25

Vorsichtsmaßnahmen: Es gibt keine spezielle Methode, um die Anforderungen des Systems zu erfüllen. Das Folgende sollte funktionieren, aber ich habe es auf einem Produktionssystem noch nie ausgiebig ausprobiert, und es kann Situationen geben, in denen es mehr Probleme verursacht, als es sich lohnt. Fahren Sie nur fort, wenn Sie mit dem Debuggen von Problemen im Zusammenhang mit dem Ändern der Umschreibungen eines funktionierenden Systems vertraut sind.

Schritt 1 macht das Neuschreiben rückgängig. Der Magento-Konfigurationsbaum kann zur Laufzeit geändert werden. Also, wenn Sie den folgenden Code ausführen

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

Dann instanziiert Magento den ursprünglichen Mage_Catalog_Block_Product_List_ToolbarBlock für den Rest der Anfrage.

In Schritt 2 wird entschieden, wo dies in Ihrem Modul aufgerufen werden soll. Da dies nur für Ihren Controller gilt und ein Block neu geschrieben wird, der erst am Ende Ihres Controllers instanziiert wird, füge ich Ihrer Controller-Klasse so etwas wie eine Methode hinzu

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

Rufen Sie diese Methode zu Beginn jeder Ihrer Aktionen auf

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

Dies mag etwas klobig erscheinen, aber ich denke, es ist eine gute Idee, klobig (dh offensichtlich) zu sein, wenn Sie mit Magentos Systemobjekten klug sind. Ein anderer Ort dafür könnten die Ereignisse controller_action_predispatchoder sein controller_action_predispatch_front_controller_actionund / oder bedingt angewendet werden.

Denken Sie daran, dass das Umschreiben erst dann rückgängig gemacht wird, wenn diese Methode aufgerufen wird. Das heißt, wenn Sie versuchen, einen Block vor dem Aufruf zu instanziieren _undoRewrites, wird die neu geschriebene Klasse verwendet, um das Objekt zu instanziieren.

Alan Storm
quelle
19

Lösung 1:
Sie können versuchen, die Klasse direkt in Ihrem Controller zu instanziieren (PHP-Methode)

Anstatt von

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

so etwas wie:

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

Lösung 2:
Ein anderer Ansatz wäre, in Ihrem Modul eine neue Klasse zu erstellen, die die ursprüngliche Klasse erweitert und diese verwendet.

Lösung 3:
Andernfalls, wenn die Erweiterung nicht verschlüsselt ist (wir alle lieben Open Source :), können Sie herausfinden, warum sie Ihre Inhalte beschädigt

Fra
quelle
Lösung 2 funktioniert (pragmatische Lösung), aber es ist nicht so toll, dass ich keine Sekunde rewritemit derselben Basisklasse machen kann. Daher funktioniert die Factory-Methode nicht (ich glaube, Sie haben dies bereits erkannt). Vielleicht gibt es keinen Magento-Weg, um dies zu tun, aber lasst uns ein bisschen nachsehen, ob es einen besseren Weg gibt.
Aaron Pollock
Lösung 2 ist das, womit ich gehen würde ... Ich machte mich bereit, dies vorzuschlagen, bis ich Francescos Antwort sah. ;)
Davidalger
1
Auch wenn mir Lösung 2 am besten gefällt, ein Hinweis zu Lösung 1: Sie können createBlock auch einen vollständigen Klassennamen geben (wie $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")in einem Blockklassenkontext). Wenn /der Parameter keine enthält , verwendet Magento die Zeichenfolge wie sie ist, um nach der Klasse zu suchen.
Matthias Zeis
1
@Aaron Pollock, Sie KÖNNEN das zweite Neuschreiben auf derselben Basisklasse durchführen. Nennen Sie den Modul-Namespace einfach Z (jeder Buchstabe nach A) und Magento verwendet ihn anstelle von Amasty one.
Amasty
5

Wenn für denselben Klassenalias mehrere Überschreibungen vorhanden sind, wird die letzte vom Magento-Konfigurationslader aus config.xml "analysiert". Ich würde dieses Problem angreifen, indem ich:

  1. Erstellen Sie eine eigene neue Erweiterung.
  2. Schreiben Sie die catalog/product_list_toolbarin Ihrer Erweiterung
  3. Mage_Catalog_Block_Product_List_ToolbarLassen Sie Ihren Block anstelle der Amasty-Klasse verlängern.
  4. Kommentieren Sie Ihre Klasse großzügig und erklären Sie, dass dieser Umschreibungskonflikt beabsichtigt ist. Sie möchten nicht, dass ein anderer Entwickler, der MageRun ausführt, versucht, den soeben erstellten Überschreibungskonflikt zu "beheben".
  5. Fügen Sie eine Abhängigkeit in die Datei app / etc / modules / blah.xml Ihrer Erweiterung ein, um sicherzustellen, dass Ihre Erweiterung nach der Amasty geladen wird.
Jim OHalloran
quelle
1

Ähnlich dem, was Francesco oben vorgeschlagen hat, aber ich glaube, Sie können den vollständigen Klassennamen tatsächlich an getModel übergeben. Auf diese Weise machen Sie immer noch das Gleiche, verwenden jedoch die Kernmethoden, um dies zu tun. Ich bin mir nicht ganz sicher, welche Vor- und Nachteile diese Methode hat, aber ich dachte, ich würde das als Idee rausschmeißen.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

Ich bin der Meinung, dass dies die Standardmethode zum Laden von Klassen in Magento2 sein wird.

jmspldnl
quelle
1

Ich fürchte, Sie müssen den Erweiterungscode geringfügig ändern. Schreiben Sie die Klasse nicht config.xmlmehr in Ihrer eigenen um , sondern ändern Sie sie Amasty_Shopby_Block_Catalog_Product_List_Toolbar, um die Klasse zu erweitern, die sich wiederum erweitert Mage_Catalog_Block_Product_List_Toolbar.

Paul Grigoruta
quelle
Ich sehe Erweiterungscode wie Kerncode - das Geschäft eines anderen (um die Fähigkeit zu erhalten, ein sauberes Upgrade durchzuführen). Es muss einen Weg geben, der es vermeidet, ihn zu berühren. Das Problem ist auch, dass die Amasty-Klasse die Kernfunktionalität im Kontext einer beliebigen Produktliste bricht. Ich möchte meine eigene Funktionalität nicht einbinden. Ich muss die Kernfunktionalität wiederbeleben. Wenn ich Ihrer Lösung folgen würde, wäre meine eigene Klasse leer, und alle Korrekturversuche, die ich dort einreichte, würden von der Amasty-Klasse mit dem höheren Präzedenzfall überschrieben.
Aaron Pollock
Das ist eine schlechte Angewohnheit. Externe Module sollten immer unberührt bleiben. Wenn Sie Ihr Modul aktualisieren müssen, müssen Sie alle Änderungen in der neuen Version wiederholen. Dies könnte in Bezug auf die Wartbarkeit zu einem Albtraum werden.
Michael Türk
Sie sollten einen neuen Block erstellen und ihn in der FROM Amasty-Symbolleiste erweitern, nicht umgekehrt.
Amasty