覆盖Magento 2中的抽象类


13

在Magento 1中,我可以将抽象类复制到本地或社区目录中,当自动加载加载此类时,Magento会使用它。

有一些解决方案可以代替Magento加载我的课程 vendor/magento/framework/Model/AbstractModel.php吗?

di.xml的抽象类首选项不起作用。仅插件?

Answers:


9

仅插件?

是。您可以为抽象类编写插件,并且如果可能的话,始终应优先选择插件。

如果要替换实现,则首选项很有用。AbstractModel如果在逻辑上可能的话,我想不出用例来替换所有扩展模型的实现。因此,您可能想要添加或更改功能,而这正是插件的用途。


1
嗨,在这种情况下,如何覆盖抽象类中的受保护函数?您能帮忙吗
Manashvi Birla

2
那不可能 最好的办法是尝试找到一种方法,以将插件添加到使用受保护方法的公共方法中,并以这种方式更改行为,即使它涉及更多的代码和某些重复。
Fabian Schmengler,

1
“我想不出一个用例来代替所有扩展AbstractModel的模型的实现”我有一个用例:我有一个支付模块,它使用4个控制器的抽象基类,每个控制器都使用一个从base来验证的方法付款网关的响应。现在,响应已发生变化,我将不得不改变所有3
泰罗Lahtinen

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
肮脏的骇客,但有时候这样做可能会有所帮助。如果您希望发票PDF看起来与众不同,M1要求在核心类中进行手动更改(因此请复制到app / code / local),我敢肯定在某些情况下需要这样做。
Zefiryn

5

如果抽象类具有要覆盖的任何公共或受保护的方法,则实际上有一种方法可以使用插件。

我不得不重写方法,_processDownload在内部\Magento\Downloadable\Controller\Download添加一些“ if-s”。(如果有人知道如何使用插件在内部方法中添加类似内容,我将不胜感激)。类是抽象的,因此首选项无效。插件也是如此,因为方法受到保护。我要做的就是Download使用首选项覆盖从扩展的所有类。这些类:

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

然后在它们内部重写父类的方法(我应该重写该方法)。因此,实际上重写方法的代码被复制到三个位置,并且完全相同。

这不是理想的方法,但是可行。


4

您可以尝试使用Magento插件来增强任何Abstract类的现有功能,尽管该功能的范围应为Public。最近,我处理同一问题,需要从“ 最近查看的产品”列表中排除分配了自定义属性的产品

我使用以下语法从名为Magento \ Reports \ Block \ Product \ AbstractProduct的类中为名为getItemsCollection的函数使用了插件:

文件: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>

文件: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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.