当您在Magento 2中使用块,模型,控制器,帮助器时,如果修改核心文件不好,这可能会对另一个程序产生一定的影响。因此,今天,我强烈建议以一种便捷的方式重写所有文件的好方法。本主题向您展示在Magento 2中使用插件和首选项时如何重写块,模型,控制器,帮助器。
重写块,模型,控制器,助手的概述
方法1:使用插件
由于不便之处,如果使用首选项,则Plugin似乎是重写Magento 2中的块,模型,控制器,帮助器的明智选择。使用Plugin,您可以在代码/目标类的功能之前,之后和周围执行代码。无需替换,这只是在核心代码之前/之后插入一些代码,然后观察核心/目标类的功能,并在核心/目标类的功能之间运行我们的代码。另外,有可能来自多个模块的插件在相同核心/目标类的功能之前/之后/周围插入自己的代码。
块覆盖
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Block\Product\View">
<plugin name="Mageplaza-yourmodule-product-block" type="Mageplaza\HelloWorld\Plugin\ProductPlugin" sortOrder="5" />
</type>
</config>
在这里启用包含方法之前,之后和周围的所有方法。
- 首先,
beforeGetProduct
方法将被激活。 - 接下来,
aroundGetPrduct
将处于活动状态。
注意:使用around方法意味着您可以在观察到的函数之前和之后直接插入代码。具体来说,我要提及的函数是getProduct()
并且在class中观察到了Magento\Catalog\Block\Product\View
。
- 最后,
afterGetProduct
方法将被激活。您可以查看var/log/debug.log
并确认方法的执行顺序。
app/code/Mageplaza/HelloWorld/Plugin/ProductPlugin.php
<?php
namespace Mageplaza\HelloWorld\Plugin;
class ProductPlugin
{
public function beforeGetProduct(\Magento\Catalog\Block\Product\View $subject)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug(__METHOD__ . ' - ' . __LINE__);
}
public function afterGetProduct(\Magento\Catalog\Block\Product\View $subject, $result)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug(__METHOD__ . ' - ' . __LINE__);
return $result;
}
public function aroundGetProduct(\Magento\Catalog\Block\Product\View $subject, \Closure $proceed)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug(__METHOD__ . ' - ' . __LINE__);
// call the core observed function
$returnValue = $proceed();
// logging to test override
$logger->debug(__METHOD__ . ' - ' . __LINE__);
return $returnValue;
}
}
?>
模型替代
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Product">
<plugin name="Mageplaza-yourmodule-product-model" type="Mageplaza\HelloWorld\Plugin\ProductPlugin" sortOrder="1" />
</type>
</config>
在此命令中,启用“ before”和“ after”方法可以在观察到的方法之前和之后运行代码getName($product)
。
app/code/Mageplaza/HelloWorld/Plugin/ProductPlugin.php
<?php
namespace Mageplaza\HelloWorld\Plugin;
class ProductPlugin
{
public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Model Override Test before');
return $name;
}
public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Model Override Test after');
return $result;
}
}
?>
控制器
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Controller\Product\View">
<plugin name="MageplazaHelloWorldControllerProductView" type="Mageplaza\HelloWorld\Plugin\ProductPlugin" sortOrder="10"/>
</type>
</config>
在此命令中,启用了“ around”方法以execute
在class中存在的观察到的方法之前和之后运行代码Magento\Catalog\Controller\Product\View
。
app/code/Mageplaza/HelloWorld/Plugin/ProductPlugin.php
<?php
namespace Mageplaza\HelloWorld\Plugin;
class ProductPlugin
{
public function aroundExecute(\Magento\Catalog\Controller\Product\View $subject, \Closure $proceed)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug(__METHOD__ . ' - ' . __LINE__);
// call the core observed function
$returnValue = $proceed();
// logging to test override
$logger->debug(__METHOD__ . ' - ' . __LINE__);
return $returnValue;
}
}
?>
协助
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Helper\Data">
<plugin name="MageplazaHelloWorldHelperData" type="Mageplaza\HelloWorld\Plugin\ProductPlugin" sortOrder="10"/>
</type>
</config>
在此命令中,启用了“ around”方法以getProduct()
在class中存在的观察到的方法之前和之后运行代码Magento\Catalog\Controller\Product\View
。
app/code/Mageplaza/HelloWorld/Plugin/ProductPlugin.php
<?php
namespace Mageplaza\HelloWorld\Plugin;
class ProductPlugin
{
public function aroundGetProduct(\Magento\Catalog\Helper\Data $subject, \Closure $proceed)
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug(__METHOD__ . ' - ' . __LINE__);
// call the core observed function
$returnValue = $proceed();
// logging to test override
$logger->debug(__METHOD__ . ' - ' . __LINE__);
return $returnValue;
}
}
?>
方法2:使用首选项
在Magento 1中,首选项被称为类重写。现在,您将知道您应该如何使用首选项来重写块,模型,控制器,助手。
块覆盖
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Block\Product\View" type="Mageplaza\HelloWorld\Block\Catalog\Product\View" />
</config>
那时,您可以重写getProduct()
class的功能Magento\Catalog\Block\Product\View
,那么您只需在var/log/debug.log
此测试中登录一些消息即可。
app/code/Mageplaza/HelloWorld/Block/Catalog/Product/View.php
<?php
namespace Mageplaza\HelloWorld\Block\Catalog\Product;
class View extends \Magento\Catalog\Block\Product\View
{
/**
* Retrieve current product model
*
* @return \Magento\Catalog\Model\Product
*/
public function getProduct()
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Block Override Test');
if (!$this->_coreRegistry->registry('product') && $this->getProductId()) {
$product = $this->productRepository->getById($this->getProductId());
$this->_coreRegistry->register('product', $product);
}
return $this->_coreRegistry->registry('product');
}
}
?>
模型替代
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Model\Product" type="Mageplaza\HelloWorld\Model\Catalog\Product" />
</config>
那时,您可以重写getName()
class的功能Magento\Catalog\Model\Product
,那么您只需在var/log/debug.log
此测试中登录一些消息即可。
app/code/Mageplaza/HelloWorld/Model/Catalog/Product.php
<?php
namespace Mageplaza\HelloWorld\Model\Catalog;
class Product extends \Magento\Catalog\Model\Product
{
/**
* Get product name
*
* @return string
* @codeCoverageIgnoreStart
*/
public function getName()
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Model Override Test');
return $this->_getData(self::NAME);
}
}
?>
控制器超越
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Controller\Product\View" type="Mageplaza\HelloWorld\Controller\Catalog\Product\View" />
</config>
那时,您可以重写execute()
class的功能Magento\Catalog\Controller\Product\View
,那么您只需在var/log/debug.log
此测试中登录一些消息即可。
app/code/Mageplaza/HelloWorld/Controller/Product/View.php
<?php
namespace Mageplaza\HelloWorld\Controller\Catalog\Product;
class View extends \Magento\Catalog\Controller\Product\View
{
/**
* Product view action
*
* @return \Magento\Framework\Controller\Result\Forward|\Magento\Framework\Controller\Result\Redirect
*/
public function execute()
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Controller Override Test');
// Get initial data from request
$categoryId = (int) $this->getRequest()->getParam('category', false);
$productId = (int) $this->getRequest()->getParam('id');
$specifyOptions = $this->getRequest()->getParam('options');
if ($this->getRequest()->isPost() && $this->getRequest()->getParam(self::PARAM_NAME_URL_ENCODED)) {
$product = $this->_initProduct();
if (!$product) {
return $this->noProductRedirect();
}
if ($specifyOptions) {
$notice = $product->getTypeInstance()->getSpecifyOptionMessage();
$this->messageManager->addNotice($notice);
}
if ($this->getRequest()->isAjax()) {
$this->getResponse()->representJson(
$this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode([
'backUrl' => $this->_redirect->getRedirectUrl()
])
);
return;
}
$resultRedirect = $this->resultRedirectFactory->create();
$resultRedirect->setRefererOrBaseUrl();
return $resultRedirect;
}
// Prepare helper and params
$params = new \Magento\Framework\DataObject();
$params->setCategoryId($categoryId);
$params->setSpecifyOptions($specifyOptions);
// Render page
try {
$page = $this->resultPageFactory->create(false, ['isIsolated' => true]);
$this->viewHelper->prepareAndRender($page, $productId, $this, $params);
return $page;
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
return $this->noProductRedirect();
} catch (\Exception $e) {
$this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
$resultForward = $this->resultForwardFactory->create();
$resultForward->forward('noroute');
return $resultForward;
}
}
}
?>
协助
app/code/Mageplaza/HelloWorld/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Helper\Data" type="Mageplaza\HelloWorld\Helper\Catalog\Data" />
</config>
那时,您可以重写getProduct()
class的功能Magento\Catalog\Helper\Data
,那么您只需在var/log/debug.log
此测试中登录一些消息即可。
app/code/Mageplaza/HelloWorld/Helper/Catalog/Data.php
<?php
namespace Mageplaza\HelloWorld\Helper\Catalog;
class Data extends \Magento\Catalog\Helper\Data
{
/**
* Retrieve current Product object
*
* @return \Magento\Catalog\Model\Product|null
*/
public function getProduct()
{
// logging to test override
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
$logger->debug('Helper Override Test');
return $this->_coreRegistry->registry('current_product');
}
}
?>
但是,如果两个或多个模块尝试重写同一核心类,则该首选项可能会造成不便的冲突。
如果您仍然遇到任何麻烦,请对此主题发表评论,我们将尽快为您提供帮助。