Zastąp klasę abstrakcyjną w Magento 2

13

W Magento 1 mogłem skopiować klasę abstrakcyjną do katalogu lokalnego lub społeczności i Magento używał jej, gdy ładowanie automatyczne ładowało tę klasę.

Czy istnieje jakieś rozwiązanie, aby Magento zamiast tego ładował moją klasę vendor/magento/framework/Model/AbstractModel.php?

Preferencje di.xmldla klas abstrakcyjnych nie działają. Tylko wtyczki?

goral
źródło

Odpowiedzi:

9

Tylko wtyczki?

Tak. Możesz pisać wtyczki dla klas abstrakcyjnych, a wtyczki powinny zawsze być preferowane przed preferencjami, jeśli to możliwe.

Preferencje są przydatne, jeśli chcesz zastąpić implementację. Nie mogę wymyślić przypadku użycia, który zastąpiłby implementację dla wszystkich modeli, które rozszerzają się AbstractModel, nawet jeśli jest to logicznie możliwe. Więc prawdopodobnie chcesz dodać lub zmienić funkcjonalność i po to są wtyczki.

Fabian Schmengler
źródło
1
Cześć, jak mogę w tym przypadku zastąpić funkcję chronioną przed klasą abstrakcyjną? czy mógłbyś pomóc
Manashvi Birla
2
To nie jest możliwe. Najlepiej jest spróbować znaleźć sposób na dodanie wtyczek do publicznych metod korzystających z metody chronionej i zmienić zachowanie w ten sposób, nawet jeśli wymaga to więcej kodu i powielenia.
Fabian Schmengler
1
„Nie mogę wymyślić przypadku użycia, który zastąpiłby implementację dla wszystkich modeli, które rozszerzają AbstractModel” Mam taki przypadek użycia: Mam moduł płatności, który używa abstrakcyjnej klasy bazowej dla 4 kontrolerów, z których każdy używa metody od bazy do weryfikacji odpowiedź z bramki płatności. Teraz odpowiedź się zmieniła i musiałbym zmienić wszystkie 3.
Tero Lahtinen
6

Pełne rozwiązanie: dołącz zastąpione klasy przed automatycznym załadowaniem ich przez Magento. Więc krok po kroku:

  1. W pliku app/etc/NonComposerComponentRegistration.phpdodaj wiersz

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. W app/etcpliku miejsce ClassReplacer.phpz zawartością

    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. Miejsce w app/code/Magentojakiejś klasie, która zostanie zastąpiona, npapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php

goral
źródło
1
Brudny hack, ale czasami może być to pomocne. M1 wymagało ręcznych zmian w podstawowych klasach (więc skopiuj do app / code / local), jeśli chcesz, aby faktura PDF wyglądała inaczej, założę się, że będzie jakiś przypadek, w którym będzie to potrzebne.
Zefiryn
5

Jeśli klasa abstrakcyjna ma jakąkolwiek publiczną lub chronioną metodę, którą chcesz zastąpić, istnieje sposób, jeśli nie możesz użyć wtyczek.

Musiałem zastąpić metodę _processDownloadwewnątrz \Magento\Downloadable\Controller\Download, dodając trochę „jeśli-to” w środku. (Jeśli ktoś ma pomysł, jak dodać coś takiego do tej metody za pomocą wtyczek, będę wdzięczny). Klasa jest abstrakcyjna, więc preferencje nie działały. Wtyczki też, ponieważ metoda jest chroniona. To, co musiałem zrobić, to zastąpić wszystkie klasy rozszerzające się Download, używając preferencji. Te klasy:

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

A w nich przepisz metodę z klasy nadrzędnej (tej, którą miałem zastąpić). Tak więc kod zastąpionych metod został skopiowany do trzech miejsc i był dokładnie taki sam.

To nie jest idealne, ale działa.

Bartosz Kubicki
źródło
4

Możesz spróbować użyć wtyczki Magento do ulepszenia istniejącej funkcjonalności dowolnej klasy Abstract, chociaż zakres tej funkcji powinien być publiczny. Ostatnio pracowałem nad tym samym problemem, w którym muszę wykluczyć produkty z przypisanym niestandardowym atrybutem z listy ostatnio oglądanych produktów .

Użyłem wtyczki dla funkcji o nazwie getItemsCollection z klasy Magento \ Reports \ Block \ Product \ AbstractProduct, stosując następującą składnię:

plik: 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>

plik: app \ code \ Package \ Module \ Block \ Obejrzane.php

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

Możesz korzystać zarówno z wtyczek, jak i przed nimi. Mam nadzieję, że ta praca dla ciebie.

Sumit Verma
źródło
1
osiągnąłem sukces z powyższym kodem w jednym z moich wymagań, tak naprawdę chciałem zmienić funkcjonalność metody klasy abstrakcyjnej modułu e-maila, a Wtyczka pomogła mi to osiągnąć, dzięki
bhargav shastri