### 个人理解
类似在方法这个层次的中间件,允许在被代理的方法前、后做一些其他事情。主要有 before、after 和 around 方法。可以对比 laravel 或者其他框架中的 middleware 来理解,或者类比设计模式中的装饰器模式,或者 python 中的 decorator,只不过是在 method 这个层次。
### 适用场景
plugin 不能被用在以下类型中
> - Final method
> - Final class
> - 非 public 方法
> - 类方法(比如静态方法)
> - __construct()
> - Virtual Types
> - 在 Framework\Interception 启动之前初始化的对象
Plugin 可以被用在下面几个情况中
> - class
> - interface
> - 抽象类
> - 父类
通过在 Magento 源码中搜索 <plugin 就能在 di.xml 文件中搜索到很多 plugin 的例子。
### before plugin
before plugin 会在被监听的方法之前运行。before plugin 有以下几条规则
> - before 关键词会被添加到被监听的方法前面,比如如果监听的是 getSomeValue 方法,那么在 plugin 中对应的方法名称就是 beforeGetSomeValue (下称为 before plugin method)
> - before plugin method 中的第一个参数是被监听的对象实例,通常缩写为 $subject 或者直接使用对应的类名,在例子中是 $processor
> - before plugin method 中的剩余所有参数都必须和被监听的方法中的参数一致。
> - before plugin method 返回的参数必须是一个数组,返回值类型和个数必须和被监听的方法一致。
在<MAGENTO_DIR>module-payment/etc/frontend/di.xml 我们能看到类似下面的写法
```
<type name="Magento\Checkout\Block\Checkout\LayoutProcessor">
<plugin name="ProcessPaymentConfiguration"
type="Magento\Payment\Plugin\PaymentConfigurationProcess"/>
</type>
```
上面代码中 plugin 的 beforeProcess 方法监听的 Magento\Checkout\Block\Checkout\LayoutProcessorMagento\Checkout\Block\Checkout\LayoutProcessor 中的 Magento\Checkout\Block\Checkout\LayoutProcessor process 方法。
```php
public function process($jsLayout)
{
//代码块
return $jsLayout;
}
```
before plugin 的实现是通过 Magento\Payment\Plugin\PaymentConfigurationProcess 类中的 beforeProcess 方法来完成的。
```php
public function beforeProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $processor,
$jsLayout) {
// 代码块...
return [$jsLayout];
}
```
### around plugin
around plugin 功能允许我们在被监听的方法前、后运行一部分我们自己的代码。这个功能使我们能够在改变输入参数的同时改变返回结果值。
关于 around plugin, 要记住的几个要点有
> - plugin 中的第一个参数是监听的类的实例
> - plugin 中的第二个参数是一个 callable/Closure 类型。通常写作 callable $proceed ,调用 $proceed 时的入参需要和被监听方法参一致。
> - 其余的参数需要和被监听方法一致。
> - plugin 的返回值必须和原函数保持一致。通常是直接返回 return $proceed(…) 或者先调用 $returnValue = $proceed(); 后直接返回 $returnValue; 有时候我们也需要修改 $returnValue;
下面来看一个 around plugin 的例子。
<MAGENTO_DIR>module-grouped-product/etc/di.xml 文件中
```
<type name="Magento\Catalog\Model\ResourceModel\Product\Link">
<plugin name="groupedProductLinkProcessor" type="Magento\GroupedProduct\Model\ResourceModel\Product\Link\RelationPersister" />
</type>
```
plugin 中的方法监听的是 Magento\GroupedProduct\Model\ResourceModel\Product\Link\RelationPersister 类中的 aroundDeleteProductLink 方法
```php
public function aroundDeleteProductLink(
\Magento\GroupedProduct\Model\ResourceModel\Product\Link $subject,
\Closure $proceed, $linkId) {
// The rest of the code...
$result = $proceed($linkId);
// The rest of the code...
return $result;
}
```
### after plugin
after plugin 主要是在被监听的方法之后执行一部分代码。
在写 after plugin 的时候,要记住以下几点:
> - plugin 的第一个参数是被监听类型的实例
> - plugin 的第二个参数是被监听方法的执行结果,通常叫做 $result ,也可以在被监听方法返回值之后被调用。例如下面例子中的 $data
> - 剩下的其他参数和被监听方法一致
> - plugin 必须返回和 $result|$data 同类型的返回值
在 module-catalog/etc/di.xml 中的 after plugin 的例子如下:
```
<type name="Magento\Indexer\Model\Config\Data">
<plugin name="indexerProductFlatConfigGet"
type="Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData" />
</type>
```
plugin 中监听的方法是 Magento\Indexer\Model\Config\Data 类中的 get 方法
```php
public function get($path = null, $default = null) {
// The rest of the code...
return $data;
}
```
Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData 类中的 afterGet 就是这里的 after plugin 的实现,具体如下:
```php
public function afterGet(Magento\Indexer\Model\Config\Data, $data, $path = null, $default = null) {
// The rest of the code...
return $data;
}
```
使用 plugin 时需要特别注意, 它十分灵活,但是也很容易产生 Bug 和造成性能瓶颈,尤其是在多个 plugin 监听同一个方法的时候。
- Magento 基本概念
- Magento 中的 Plugin
- Magento 中的 Events 和 observers
- Magento 中的 Areas
- Magento 中的请求处理流程
- Magento 中的模块(Modules)
- Magento 中的 Cache
- Magento 中的依赖注入
- Magento 中的 Console commands
- Magento 中的 Cron jobs
- 掌握 Entities
- 理解 model 的类型
- 理解 setup scripts
- 实体扩展
- 初入 web API
- users 的几种不同类型
- 授权的不同类型
- APIs 的不同类型
- 使用 Magento 现有的 API
- 创建自定义 web APIs
- 理解 search criteria
- Magento 后台开发
- 使用 listing 组件
- 使用 form 组件
- 开发前台功能
- 搭建前台开发环境
- 初始化 & 调用 JS 组件
- 开始使用 RequireJS
- 替换 jQuery widget 组件
- 扩展 jQuery widget 组件
- 创建 jQuery widgets 组件
- 创建 UI/KnockoutJS 组件
- 扩展 UI/KnockoutJS 组件
- 自定义 Catalog
- 创建参考尺寸
- 创建当天发货
- 标识新产品
- Magento 性能最佳实践
- Magento 硬件推荐配置
- 软件推荐
- 架构参考
- 配置项最佳实践
- 高级设置
- 其他
- 如何通过 Burp Suite 和 Xdebug 来调试 Magento
- Mageno checkout 必知必会
- Magento 安装(新手必看)
- 安装流程
- 系统要求