Überschreiben Sie die abstrakte Klasse in Magento 2

12

In Magento 1 konnte ich die abstrakte Klasse in ein lokales oder Community-Verzeichnis kopieren und Magento verwendete sie, wenn Autoload diese Klasse lud.

Gibt es eine Lösung, um zu machen, dass Magento stattdessen meine Klasse lädt vendor/magento/framework/Model/AbstractModel.php?

Einstellungen di.xmlfür abstrakte Klassen funktionieren nicht. Nur Plugins?

goral
quelle

Antworten:

8

Nur Plugins?

Ja. Sie können Plugins für abstrakte Klassen schreiben. Plugins sollten nach Möglichkeit immer den Einstellungen vorgezogen werden.

Einstellungen sind nützlich, wenn Sie eine Implementierung ersetzen möchten . Ich kann mir keinen Anwendungsfall vorstellen, der die Implementierung für alle Modelle, die erweitert werden AbstractModel, ersetzt, wenn dies überhaupt logisch möglich ist. Sie möchten also wahrscheinlich Funktionen hinzufügen oder ändern, und dafür sind Plugins gedacht.

Fabian Schmengler
quelle
1
Hallo, wie kann ich eine geschützte Funktion von der abstrakten Klasse in diesem Fall überschreiben?
Könnten
2
Das ist nicht möglich. Versuchen Sie am besten, den öffentlichen Methoden, die die geschützte Methode verwenden, Plug-ins hinzuzufügen, und ändern Sie das Verhalten auf diese Weise, auch wenn dies mehr Code und einige Duplikationen erfordert.
Fabian Schmengler
1
"Ich kann mir keinen Anwendungsfall vorstellen, um die Implementierung für alle Modelle zu ersetzen, die AbstractModel erweitern." Ich habe einen solchen Anwendungsfall: Ich habe ein Zahlungsmodul, das eine abstrakte Basisklasse für 4 Controller verwendet, die jeweils eine Methode von base verwenden, um zu überprüfen die Antwort vom Zahlungsgateway. Jetzt hat sich die Reaktion geändert und ich müsste alle 3 ändern.
Tero Lahtinen
6

Vollständige Lösung: Schließen Sie ersetzte Klassen ein, bevor Sie sie von Magento automatisch laden. Also Schritt für Schritt:

  1. In Datei app/etc/NonComposerComponentRegistration.phpZeile hinzufügen

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. In- app/etcPlace-Datei ClassReplacer.phpmit Inhalt

    class ClassReplacer
    {
        public function includeReplacedFiles($src)
        {
            try {
                $replacedFiles = $this->listDir($src, false, true);
                foreach ($replacedFiles as $replacedFile) {
                    include_once $src . $replacedFile;
                }
            } catch (Exception $e) {
                return;
            }
        }
    
        protected function listDir($dir, $prependDir = false, $recursive = false, $entityRegexp = null, $currPath = '')
        {
            if (!is_dir($dir)) {
                return array();
            }
            $currPath = $prependDir ? $dir : $currPath;
            $currPath = $currPath !== '' ? rtrim($currPath, '/') . '/' : '';
            $files = array();
            foreach (scandir($dir) as $file) {
                if (in_array($file, array('.', '..'))) {
                    continue;
                }
                $entity = $currPath . $file;
                if ($recursive && is_dir("$dir/$file")) {
                    $files = array_merge($files, $this->listDir("$dir/$file", false, true, $entityRegexp, $entity . '/'));
                    continue;
                }
                if ($entityRegexp && !preg_match($entityRegexp, $entity)) continue;
                $files[] = $entity;
            }
            return $files;
        }
    }
    $replace = new ClassReplacer();
    $replace->includeReplacedFiles(dirname(__DIR__) . '/code/Magento/');
  3. Platz für app/code/Magentoeine Klasse, die ersetzt wird, zapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php

goral
quelle
1
Schmutziger Hack, aber manchmal kann es hilfreich sein, das zu können. M1 erforderte manuelle Änderungen in den Kernklassen (also in App / Code / Local kopieren). Wenn das PDF der Rechnung anders aussehen soll, gibt es bestimmt Fälle, in denen dies erforderlich ist.
Zefiryn
5

Wenn abstrakte Klassen über eine öffentliche oder geschützte Methode verfügen, die Sie überschreiben möchten, gibt es tatsächlich eine Möglichkeit, wenn Sie keine Plugins verwenden können.

Ich musste die Methode _processDownloadinside \Magento\Downloadable\Controller\Downloadüberschreiben und ein paar 'if-s' hinzufügen. (Wenn jemand eine Idee hat, wie ich mit Plugins so etwas hinzufügen kann, bin ich dankbar). Klasse ist abstrakt, Präferenz hat nicht funktioniert. Plugins auch, da Methode geschützt ist. Das, was ich tun musste, war, alle Klassen außer Kraft zu setzen, von Downloaddenen aus ich sie bevorzugte. Diese Klassen:

Magento\Downloadable\Controller\Download\Link Magento\Downloadable\Controller\Download\LinkSample Magento\Downloadable\Controller\Download\Sample

Und in ihnen schreiben Sie die Methode aus der Elternklasse um (die, die ich überschreiben sollte). Der Code der überschriebenen Methoden wurde also an drei Stellen kopiert und war genau derselbe.

Es ist nicht ideal, aber es funktioniert.

Bartosz Kubicki
quelle
4

Sie können versuchen, mit dem Magento-Plug-in die vorhandene Funktionalität einer Abstract-Klasse zu erweitern. Der Funktionsumfang sollte jedoch Public sein. Vor kurzem habe ich an demselben Problem gearbeitet, bei dem ich Produkte mit benutzerdefinierten Attributen aus der Liste der zuletzt angezeigten Produkte ausschließen muss .

Ich habe das Plugin für die Funktion getItemsCollection aus der Klasse Magento \ Reports \ Block \ Product \ AbstractProduct mit der folgenden Syntax verwendet:

Datei: app \ code \ Package \ Module \ etc \ frontend \ di.xml

<type name="Magento\Reports\Block\Product\AbstractProduct">
    <plugin name="Package_Module::aroundGetItemsCollection" type="Package\Module\Block\Viewed" sortOrder="20"/>
</type>

Datei: App \ Code \ Package \ Module \ Block \ Viewing.php

public function afterGetItemsCollection(
    $subject, $result
) {
    $result = $result->addAttributeToFilter('skip_hire_product', [['neq' => 1], ['null' => true]], 'left');
    return $result;
}

Sie können sowohl vor als auch um Plugins verwenden. Hoffe diese Arbeit für dich.

Sumit Verma
quelle
1
Ich habe Erfolg mit dem obigen Code in einer meiner Anforderungen, eigentlich wollte ich einige Funktionen der abstrakten Klassenmethode des E-Mail-Moduls ändern und das Plugin hat mir dabei geholfen, danke
bhargav shastri