有针对性的依赖注入

有针对性的依赖注入

2016年4月27日发布 in 发展历程
Magento Imagine 2016回顾
2016年4月19日
偷路易
骆驼袭击黑市
2016年5月20日

全球替代

设置类替代时,通常希望它们在整个Magento中应用。但是,有时您可能只想在一个特定位置覆盖一个类。我们Classy Llama最近正在为Magento 2开发一个模块,该模块需要Magento控制器返回与该控制器通常提供的URL不同的URL。’的服务依赖性。我们希望此修改适用于此一个控制器类,而没有其他地方。

 

在以下示例控制器中,让’s说您想更改此控制器的方式’s URL helper 功能s by having the getBaseUrl() method 返回 a different URL, and it is not possible to directly edit the controller or its dependency:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
指数 延伸 \Magento\构架\应用程式\行动\行动
{
    / **
    * @var \ Magento \ 构架 \ 网址
     * /
    受保护的 $ urlHelper;
    / **
    * @param \ Magento \ 构架 \ 应用程式 \ 行动 \ 语境 $ context
    * @param \ Magento \ 构架 \ 网址 $ url
     * /
    上市 功能 __构造(
        \Magento\构架\应用程式\行动\语境 $ context,
        \Magento\构架\网址 $ url
    ) {
        $ 这个->urlHelper = $ url;
        父母::__构造($ context);
    }
    / **
     * @返回无效
     * /
    上市 功能 执行()
    {
        回声 $ 这个->urlHelper->getBaseUrl();
    }
}

You could 创建 a 类 that 延伸 \Magento\Framework\Url, override the getBaseURL() 功能, and then set up a preference. You could even set up a plugin to modify the method’s behavior. Unfortunately for us, both of these options are essentially global overrides. Since the getBaseURL() method is used 在 many other places, overriding it globally would potentially break other core 类es that rely 上 \Magento\Framework\Url as a dependency.

但是,有一种方法可以 有选择地 使用构造函数参数注入修改功能。正如我们将在以下示例中看到的那样,构造函数参数注入可以替换特定的类’依赖项具有新的或更新的依赖项,并且只要您创建的新类扩展了构造函数中指定的必需类,Magento 2就不会抱怨类型不正确。为了说明这个概念,我编写了一个小模块,您可以 从GitHub此处获取.

依赖注入

本文假定您熟悉Magento 2中实现的依赖项注入的概念。有关更多信息,请查看 Magento 2开发人员文档。艾伦·肯特(Alan Kent)也写了 关于依赖注入的优秀文章 涉及可注射,不可注射和工厂等概念。

覆盖依赖’单一位置的方法

扩展我们前面的示例,让’看一下我们如何使用构造函数自变量注入来选择性地修改类’ behavior. Here is a simple example using the 类 \Dholden\DiExample\Controller\ExampleOne\Index from the GitHub project:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
命名空间 德霍尔登\二例\控制者\例子一;
指数 延伸 \Magento\构架\应用程式\行动\行动
{
    / **
    * @var \ Magento \ 构架 \ 网址
     * /
    受保护的 $原始;
    / **
    * @var \ Magento \ 构架 \ 网址
     * /
    受保护的 $修改;
    / **
    * @param \ Magento \ 构架 \ 应用程式 \ 行动 \ 语境 $ context
    * @param \ Magento \ 构架 \ 网址 $ url1
    * @param \ Magento \ 构架 \ 网址 $ url2
     * /
    上市 功能 __构造(
        \Magento\构架\应用程式\行动\语境 $ context,
        \Magento\构架\网址 $ url1,
        \Magento\构架\网址 $ url2
    ) {
        $ 这个->原版的 = $ url1;
        $ 这个->改性 = $ url2;
        父母::__构造($ context);
    }
    / **
     * @返回无效
     * /
    上市 功能 执行()
    {
        回声 '

原始基本网址: ‘ . $ 这个->original->getBaseUrl() . ‘

‘; 回声 ‘

修改后的基本网址: ‘ . $ 这个->modified->getBaseUrl() . ‘

‘; } }

This simple controller calls the getBaseUrl() method from \Magento\Framework\Url. Notice that $ url1 and $ url2 both 在stantiate \Magento\Framework\Url, yet the output of the “ExampleOne”控制器如下:

原始基本网址: http://example.dev/

Modified Base URL: http://newurl.dev/

在调用完全相同的方法时,输出是完全不同的,并且此功能上的差异仅适用于 这个 控制器类。要了解发生了什么,让’s first look at \Dholden \ 二例 \ 模型 \ 修改网址:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
命名空间 德霍尔登\二例\模型;
/ **
*返回修改后的URL
* /
修改网址 延伸 \Magento\构架\网址
{
    / **
     * {@inheritdoc}
     * /
    上市 功能 getBaseUrl($参数 = []) {
        返回 'http://newurl.dev/';
    }
}

This simple 类 延伸 \Magento\Framework\Url and overrides the 父母 功能 getBaseUrl(). Nothing too special here. We could at 这个 point, setup a configuration preference for the 类, but 这个 would override 这个 method across all of Magento 2. We shall 在stead use dependency 在jection to 有选择地 override 上e constructor argument 在 上e 类. Let’看看我们的etc / di.xml:

1
2
3
4
5
6
7
8
<!- ?XML文件 ="1.0"?- >
    
        
             德霍尔登\二例\模型\修改网址
        
    
     ...

We’re replacing the third constructor argument of our controller (i.e. $ url2) with the object \Dholden \ 二例 \ 模型 \ 修改网址, and since 这个 类 延伸 \Magento\Framework\Url, it fulfills the requirement as set 在 the constructor.

更进一步

很好,但是让’s说您想使用 。同样的原则适用,但有一点小小的警告,我们很快就会意识到。让’s take a look at \Dholden\DiExample\Controller\ExampleTwo\Index from our Github project:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
命名空间 德霍尔登\二例\控制者\例二;
指数 延伸 \Magento\构架\应用程式\行动\行动
{
    / **
    * @var \ Magento \ 目录 \ 模型 \ Category
     * /
    受保护的 $ category原始;
    / **
    * @var \ Magento \ 目录 \ 模型 \ Category
     * /
    受保护的 $ 类别已修改;
    / **
    * @param \ Magento \ 构架 \ 应用程式 \ 行动 \ 语境 $ context
    * @参数\ Magento \ 目录 \ 模型 \ 类别工厂 $ categoryFactory1
    * @param \ Magento \ 目录 \ 模型 \ 类别工厂 $ categoryFactory2
     * /
    上市 功能 __构造(
        \Magento\构架\应用程式\行动\语境 $ context,
        \Magento\目录\模型\类别工厂 $ categoryFactory1,
        \Magento\目录\模型\类别工厂 $ categoryFactory2
    ) {
        $ 这个->categoryFactory1 = $ categoryFactory1;
        $ 这个->categoryFactory2 = $ categoryFactory2;
        $ 这个->类别原始 = $ categoryFactory1->创建();
        $ 这个->类别已修改 = $ categoryFactory2->创建();
        父母::__构造($ context);
    }
    / **
     * @返回无效
     * /
    上市 功能 执行()
    {
        $ 这个->类别原始->加载(1);
        $ 这个->类别已修改->加载(1);
        回声 '

类别1的名称: ‘ . $ 这个->categoryOriginal->getName() . ‘

‘; 回声 ‘

类别2的名称: ‘ . $ 这个->categoryModified->getName() . ‘

‘; } }

该控制器输出ID为的类别名称‘1’,但是就像在我们的第一个示例中一样,即使调用了相同的方法,调用getName的结果也有所不同。此示例与上一个示例的主要区别在于,我们在控制器中调用工厂’s constructor. We are then 在stantiating two new 在stances of \Magento\Catalog\Model\Category using the 厂’s 创建() method. Our desire is to override the getName() method of \Magento\Catalog\Model\Category, but 上ly 在 our specific example 类 and 无处.

Like 在 our first example, we have 创建d a new 类 (德霍尔登\DiExample\Model\ModifiedCategory) that 延伸 \Magento\Catalog\Model\Category and overrides the getName() method, but now our etc/di.xml looks a bit different:

1
2
3
4
5
6
<!- ?XML文件 ="1.0"?- >
...
    
        
            德霍尔登\二例\模型\ModifiedCategoryFactory

由于我们在课堂上使用工厂’ constructor to 创建 new 在stances of the category 类, we need to override these factories 在 some manner. But we have 创建d a new category 类 (\Dholden\DiExample\Model\ModifiedCategory) that modifies the getName() method. As you may have noticed, factories are not the 类es themselves. They 上ly 创建 new 在stances of the 类es whose methods we wish to 有选择地 override.

我们显然需要通过 到控制器,所以逻辑方法是附加‘Factory’ to the end of our constructor argument, i.e. our new 类, 在 di.xml. Unfortunately, 这个 will cause an error because the 厂 that will the auto-generated by Magento 2 will not fulfill the requirements of the constructor argument because it does not extend \Magento\Catalog\Model\CategoryFactory as the constructor has specified. If we try to view the controller as-is, the page will 返回 the following error 在 our browser:

Recoverable Error: Argument 3 passed to 德霍尔登\DiExample\Controller\ExampleTwo\Index\Interceptor::__construct() must be an 在stance of Magento\Catalog\Model\CategoryFactory, 在stance of 德霍尔登 \ 二例 \ 模型 \ ModifiedCategoryFactory given...

从错误消息中,我们了解到Magento 2创建的工厂不会扩展控制器中指定的工厂’s constructor. The solution is to have that 厂 在herit from \Magento\Catalog\Model\CategoryFactory. But how do we do 这个, since the 厂 was auto-generated? Fortunately for us, we can manually 创建 our own factories and have Magento 2 use these over its own auto-generated 类es. Take a look at the following 厂 located 在 the same folder as our new ModifiedCategory 类:

的PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
命名空间 德霍尔登\二例\模型;
ModifiedCategoryFactory 延伸 \Magento\目录\模型\类别工厂
{
    / **
     * {@inheritdoc}
     * /
    上市 功能 __构造(\Magento\构架\对象管理器接口 $ objectManager, $ 在stanceName = '\ 德霍尔登 \ 二例 \ 模型 \ ModifiedCategory')
    {
        父母::__构造($ objectManager, $ 在stanceName);
    }
    / **
     * {@inheritdoc}
     * /
    上市 功能 创建(数组 $数据 = [])
    {
        返回 $ 这个->_objectManager->创建($ 这个->_instanceName, $数据);
    }
}

Here we 创建 a 厂 that 延伸 \Magento\Catalog\Model\CategoryFactory. The 类别工厂 类 will still be auto-generated by Magento 2, but since our 厂 now 延伸 it, it will now fulfill the requirement of the controller’的构造函数参数。

结论

构造函数参数注入使您可以修改类’行为,特别是由类依赖项提供给您的方法,而无需直接修改类本身,也无需更改它们在系统或区域范围内的行为。我希望这个概念对您未来的Magento 2项目有帮助。

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *

该网站使用Akismet减少垃圾邮件。 了解如何处理您的评论数据.

最近的帖子查看全部
2020年10月22日
通过 阿什莉·科利弗 商业见解, 优雅的骆马 2020年10月22日
毫无疑问,2020年是历史性的一年。火灾,全球大流行,暴动,老虎王等’只是冰山一角。如 […]