将依赖项注入Magento 2 CRUD /抽象模型


12

是否可以将依赖项注入到Magento 2 CRUD模型中?

也就是说-Magento 2有一个基本的抽象模型类:Magento\Framework\Model\AbstractModel。如果要创建简单的“创建,读取,更新,删除”模型对象,则可以使用自己的类来扩展该类。

class Foo extends Magento\Framework\Model\AbstractModel
{
}

是否可以在模型的__construct方法中注入依赖项?当我尝试时,最终出现以下错误。

致命错误:无法实例化抽象类Magento \ Framework \ Model \ ResourceModel \ AbstractResource

罪魁祸首似乎是AbstractModel__construct方法。

public function __construct(
    \Magento\Framework\Model\Context $context,
    \Magento\Framework\Registry $registry,
    \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
    \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
    array $data = []
) {

此构造函数(Magento\Framework\Model\ResourceModel\AbstractResourceMagento\Framework\Data\Collection\AbstractDb)中有两种类型提示,它们不是 Magento对象管理器接口。它们是抽象类。当我扩展此类并尝试添加注入的依赖项时

class Foo extends Magento\Framework\Model\AbstractModel
{
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = [],
        \Package\Module\Model\Mine $mine,

    ) {
        //...
        parent::__construct($context, $registry, $resource, $resourceCollection, $data);

    }
}

当对象管理器尝试实例化抽象类时,Magento退出。

我可以通过将对象依赖关系移到抽象类的前面来“修复”此问题

    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,

        \Package\Module\Model\Mine $mine,

        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = [],
    ) {  

但是,这改变了参数顺序。在完全由对象管理的类中,这不是问题。但是,这些抽象类类型提示存在的事实意味着,Magento系统的某些部分将手动(即,不通过对象管理器或DI)实例化CRUD对象,并按照该特定顺序传递符合类型提示的对象。

这样安全吗?即,这些抽象类在抽象模型的构造函数中是否只是旧版代码,而不使用?还是系统的某些部分仍将使用这些,这意味着不可能将依赖项注入到CRUD模型中?

Answers:


9

首先,构造函数是class的私有api。构造函数具有特殊含义,不需要与父类具有相同的参数列表/顺序。

是否可以将依赖项注入到Magento 2 CRUD模型中?

当然是。

这样安全吗?

是的,但是Magento对象管理器假定所有可选参数都放在列表的末尾,而可选参数之后的必需参数将无法解析。

$ resource,$ resourceCollection参数是旧参数,但仍在Model类中广泛使用。大多数模型使用这样的代码来初始化资源和集合类。

protected function _construct() { 
    $this->_init('Magento\AdminNotification\Model\Resource Model\Inbox'); 
}

这就是为什么此参数是可选的。但是,例如,在单元测试中,我们在构造函数中传递资源或集合模拟,以允许替换实现。


@Kanday Magento的工程/建筑部门是否曾经公开声明核心类的构造函数顺序无关紧要?还是仅仅是大多数人的希望?
艾伦·斯托姆

我不会称其为“无关紧要”。只是OM会将必需的参数传递给构造函数,并且它不依赖于父类的顺序。此外,IN使用参数名称,因此现在最好不要更改它们(这与php语言不同,在PHP语言中,您可以根据需要更改参数名称)
KAndy

我不确定我是否理解您的意思。您是在说未来的某个时候,核心的Magento系统代码可能会开始再次将参数/参数顺序视为重要的?
艾伦·斯托姆

我相信,没有
康提

再次感谢!FWIW,对于Google员工来说,这样做似乎是安全的。据我所知,没有Magento系统代码会自动以构造函数参数顺序盲目实例化模型。
艾伦·斯托姆

6

这似乎是安全的。至少,magento在许多地方都在这样做。有关示例,请参见以下(非排他)类列表中的__construct方法

  • \ Magento \主题\模型\主题\文件
  • \ Magento \主题\模型\设计
  • \ Magento \ Sales \ Model \ Order \ Creditmemo

不幸的是,我无法回答您问题的另一部分。


4
  1. 您如何使用模型?
  2. 你的情况$mine必需的参数,同时$resource$resourceCollection$data可选的。可选参数应始终排在最后,否则就无法像使用可选参数一样使用它们。因此,我认为应该$mine在任何可选参数之前指定。

除了那些Abstract参数不是依赖注入的参数外,如果Magento核心系统代码期望它们在那里,那么移到$mine队列的最前面将产生错误。如果Magento核心系统代码使用它们,为什么它们在那里?这就是我要探究的问题。仅仅因为我可以在移动参数的情况下使用我的模型,但这并不安全。
艾伦·斯托姆

某些模型可能仍使用这些可选参数来传递自定义资源模型。例如,github.com
magento/

Magento使用反射来确定参数是否可选。和PHP作为考虑需要站在面前参数的所有参数要求。所以,如果你移动$mine之前可选参数,他们成为真正可选的,Magento的只是传递默认值(nullarray())。如果将必需参数放在可选参数之后,PHP会将可选参数视为必需参数,Magento尝试实例化它们(但没有偏好)。
BuskaMuza

尽管我同意这看起来令人困惑,也许我们可以为抽象类设置一个首选项,而不是在模型类中处理它。因此,始终会注入真实对象。
BuskaMuza
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.