plugin,也称为拦截器,是一个类,它通过拦截函数调用并在函数调用之前、之后或周围运行代码来修改公共类函数的行为。这允许您替换或扩展任何类或接口的原始公共方法的行为。
作为Magento 2的一个强大功能,plugin:
用于更改公共类函数的行为。
不能用于在启动Magento\Framework\Interception之前实例化的final类、final方法、非公共类、静态方法、构造函数、虚拟类型和对象。
插件允许您自定义一个方法,可以在该方法之前、之后和周围调用该方法。为了避免冲突,同一类的插件根据其排序顺序依次执行。
插件可以在di中声明。模块的xml文件(全局或基于区域),具有以下结构
<config>
<type name="{ObservedType}">
<plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false" />
</type>
</config>
声明plugin时必须指定以下元素:
Type name:plugin观察的类、接口。
Plugin name:标识plugin的任意名称。还用于合并插件的配置。
Plugin type:plugin类或其虚拟类型的名称。指定此元素时使用以下命名约定:\Vendor\Module\Plugin<ClassName>
其他属性:
sortOrder:调用相同方法的插件将基于排序顺序运行。
disabled:要禁用plugin,请将此元素设置为true。默认值为false。
下面是一个简单语法的示例:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Checkout\Model\ShippingInformationManagement">
<plugin name="save-in-quote" type="Magenest\GiftRegistry\Plugin\Checkout\ShippingInformationManagement" sortOrder=”1” disabled=”false”/>
</type>
</config>
plugin类型
如前所述,Magento 2 plugin有三种类型:before、after和around。
1.Before plugin
Before方法用于在调用方法之前更改方法的参数或添加一些行为。Magento在调用观察到的方法之前运行所有的before方法。在插件能够访问传递给方法的参数之前。这些方法必须与前缀为“before”的观察方法同名。
下面是before方法的一个示例,该方法检查礼品注册中心中商品的购买者是否向礼品注册中心的所有者发送问候语。
public function beforeSaveAddressInformation(
\Magento\Checkout\Model\ShippingInformationManagement $subject,
$cartId,
\Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
){
$return = [$cartId, $addressInformation];
$address = $addressInformation->getShippingAddress();
if($address instanceof \Magento\Quote\Api\Data\AddressInterface ){
$extAttributes = $address->getExtensionAttributes();
$giftregistryMessage = $extAttributes->getGiftregistryMessage();
if(!isset($giftregistryMessage) || $giftregistryMessage == ""){
$extAttributes->setGiftregistryMessage(__("I wish you a wonderful Birthday!"));
}
}
return $return;
}
2.After plugin
After方法更改原始方法返回的值,或在调用原始方法后添加行为。Magento在原始方法完成后运行所有后续方法。插件可以访问原始方法的结果之后。自从Magento 2.2之后,插件还可以访问输入参数。
必须将“after”前缀添加到此方法的名称中。例如:
public function afterSaveAddressInformation(
\Magento\Checkout\Model\ShippingInformationManagement $subject,
$result,
$cartId,
\Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
){
$address = $addressInformation->getShippingAddress();
if($address instanceof \Magento\Quote\Api\Data\AddressInterface ){
$extAttributes = $address->getExtensionAttributes();
$giftregistryMessage = "From Magenest store: ".$extAttributes->getGiftregistryMessage();
if(!isset($giftregistryMessage) || $giftregistryMessage == ""){
$extAttributes->setGiftregistryMessage($giftregistryMessage);
}
}
return $result;
}
3. Around plugin
Around方法可以更改原始方法的参数和返回值,或者在调用方法之前/之后添加行为。将“around”前缀添加到此方法的名称。
public function aroundSaveAddressInformation(
\Magento\Checkout\Model\ShippingInformationManagement $subject,
\Closure $proceed,
$cartId,
\Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
) {
$address = $addressInformation->getShippingAddress();
if($address instanceof \Magento\Quote\Api\Data\AddressInterface ){
try{
$extAttributes = $address->getExtensionAttributes();
$giftregistryMessage = $extAttributes->getGiftregistryMessage();
$giftregistryId = $this->_helperCart->getRegistryId();
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $this->_quoteRepository->getActive($cartId);
$quoteId = $quote->getId();
$tranModel = $this->_tranFactory->create();
$this->_tranResource->load($tranModel,$quoteId,'quote_id');
$tranModel->addData([
'giftregistry_id' => $giftregistryId,
'message' => $giftregistryMessage,
'quote_id' => $quoteId
]);
$this->_tranResource->save($tranModel);
}catch (\Exception $exception){
$this->_logger->critical($exception->getMessage());
}
}
return $proceed($cartId, $addressInformation);
}
当您包装一个接受参数的方法时,您的插件也必须接受这些参数,并且您必须在调用可继续调用时转发这些参数。必须小心匹配默认参数和方法原始签名的类型提示