Переопределить абстрактный класс в Magento 2

13

В Magento 1 я мог копировать абстрактный класс в локальный каталог или каталог сообщества, и Magento использовал его, когда автозагрузка загружала этот класс.

Есть ли какое-то решение, чтобы Magento загружал мой класс vendor/magento/framework/Model/AbstractModel.php?

Предпочтения в di.xmlотношении абстрактных классов не работают. Только плагины?

горал
источник

Ответы:

9

Только плагины?

Да. Вы можете написать плагины для абстрактных классов, и плагины всегда должны быть предпочтительнее предпочтений, если это возможно.

Предпочтения полезны, если вы хотите заменить реализацию. Я не могу придумать вариант использования для замены реализации для всех расширяющихся моделей AbstractModel, если это даже логически возможно. Так что вы, вероятно, хотите, чтобы добавить или изменить функциональность, и это то, для чего плагины.

Фабиан Шменглер
источник
1
Привет, как я могу переопределить защищенную функцию из абстрактного класса в этом случае? не могли бы вы помочь
Манашви Бирла
2
Это невозможно. Лучше всего попытаться найти способ добавить плагины к публичным методам, которые используют защищенный метод, и изменить поведение таким образом, даже если это требует больше кода и некоторого дублирования.
Фабиан Шменглер
1
«Я не могу придумать вариант использования для замены реализации для всех моделей, расширяющих AbstractModel» У меня есть такой вариант использования: у меня есть модуль оплаты, который использует абстрактный базовый класс для 4 контроллеров, каждый из которых использует метод из базы для проверки ответ от платежного шлюза. Теперь ответ изменился, и мне пришлось бы поменять все 3.
Теро Лахтинен
6

Полное решение: включите замененные классы перед тем, как magento автоматически загрузит их. Итак, шаг за шагом:

  1. В файле app/etc/NonComposerComponentRegistration.phpдобавить строку

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. В app/etcместе файла ClassReplacer.phpс содержанием

    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. Поместите в app/code/Magentoкакой-нибудь класс, который будет заменен, напримерapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php

горал
источник
1
Грязный хак, но иногда бывает полезно сделать это. M1 требовал ручных изменений в основных классах (поэтому скопируйте в app / code / local), если вы хотите, чтобы PDF-файл счета-фактуры выглядел по-другому, я уверен, что в некоторых случаях это понадобится.
Зефирин
5

Если у абстрактного класса есть какой-либо открытый или защищенный метод, который вы хотите переопределить, на самом деле есть способ, если вы не можете использовать плагины.

Мне пришлось переопределить метод _processDownloadвнутри \Magento\Downloadable\Controller\Download, добавив несколько «если-s» внутри. (Если у кого-то есть идея, как я могу добавить что-то подобное в метод с использованием плагинов, я буду благодарен). Класс абстрактный, поэтому предпочтение не сработало. Плагины тоже как метод защищены. То, что я должен был сделать, это переопределить все расширения класса Download, используя предпочтения. Эти классы:

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

И внутри них переписать метод из родительского класса (тот, который я должен был переопределить). Так что на самом деле код переопределенных методов был скопирован в три места и был точно таким же.

Это не идеально, но работает.

Бартош Кубицки
источник
4

Вы можете попробовать использовать плагин Magento для расширения существующей функциональности любого класса Abstract, хотя область действия функции должна быть Public. Недавно я работал над той же проблемой, в которой мне нужно исключить продукты, имеющие собственный атрибут, назначенный из списка недавно просмотренных продуктов .

Я использовал плагин для функции с именем getItemsCollection из класса с именем Magento \ Reports \ Block \ Product \ AbstractProduct, используя следующий синтаксис:

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

file: app \ code \ Package \ Module \ Block \ Viewed.php

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

Вы можете использовать как вокруг, так и перед плагинами тоже. Надеюсь, эта работа для вас.

Сумит Верма
источник
1
я добился успеха с приведенным выше кодом в одном из моих требований, на самом деле я хотел изменить некоторые функциональные возможности метода абстрактного класса модуля электронной почты, и плагин помог мне достичь этого, спасибо
bhargav shastri