Magento 2.2.3中重写FilterList及插件报错的技术问询
解决Magento 2.2.3中重写FilterList类的问题
咱们一步步来解决你遇到的两个问题:如何正确重写Magento\Catalog\Model\Layer\FilterList,以及修复插件方式引发的类型错误,还有preference不生效的排查思路。
一、使用Preference方式重写FilterList
Preference是直接替换原类的方式,正确配置步骤如下:
- 配置di.xml
在你的模块的app/code/YourVendor/YourModule/etc/di.xml中添加preference节点:
<?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\Layer\FilterList" type="YourVendor\YourModule\Model\Layer\FilterList" /> </config>
- 创建重写类
在app/code/YourVendor/YourModule/Model/Layer/FilterList.php中编写自定义类,必须继承原类,且构造函数参数要和原类完全一致:
<?php namespace YourVendor\YourModule\Model\Layer; use Magento\Catalog\Model\Layer; use Magento\Catalog\Model\Layer\FilterableAttributeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Store\Model\StoreManagerInterface; class FilterList extends \Magento\Catalog\Model\Layer\FilterList { public function __construct( FilterableAttributeListInterface $filterableAttributes, ScopeConfigInterface $scopeConfig, StoreManagerInterface $storeManager, array $filters = [] ) { parent::__construct($filterableAttributes, $scopeConfig, $storeManager, $filters); } // 重写你需要修改的方法,比如getFilters public function getFilters(Layer $layer) { // 先调用原方法获取默认过滤器 $filters = parent::getFilters($layer); // 这里添加你的自定义逻辑,比如调整过滤器顺序、添加自定义过滤器等 // 示例:移除价格过滤器 // foreach ($filters as $key => $filter) { // if ($filter instanceof \Magento\Catalog\Model\Layer\Filter\Price) { // unset($filters[$key]); // } // } return $filters; } }
如果Preference不生效,排查这些点:
- 确认模块已启用:执行
bin/magento module:status YourVendor_YourModule,未启用的话运行bin/magento module:enable YourVendor_YourModule && bin/magento setup:upgrade - 检查di.xml路径和内容:确保文件在模块的
etc目录下,且for和type的类名完全正确 - 清理缓存:执行
bin/magento cache:clean config和bin/magento cache:flush - 检查类文件路径:命名空间要和文件目录对应,比如
YourVendor\YourModule\Model\Layer\FilterList对应app/code/YourVendor/YourModule/Model/Layer/FilterList.php
二、修复插件方式的TypeError错误
你遇到的致命错误是因为around方法的参数签名完全错了。Magento插件的around方法有固定参数顺序:
- 被拦截的原对象($subject)
- 闭包($proceed),用于调用原方法
- 原方法的参数(这里是$layer)
你的代码把原方法的参数放在了闭包前面,导致类型不匹配。正确的插件写法如下:
- 编写插件类
在app/code/YourVendor/YourModule/Plugin/Model/Layer/FilterList.php中创建插件:
<?php namespace YourVendor\YourModule\Plugin\Model\Layer; use Magento\Catalog\Model\Layer; use Magento\Catalog\Model\Layer\FilterList as OriginalFilterList; class FilterList { /** * 拦截getFilters方法 * @param OriginalFilterList $subject 原类对象 * @param \Closure $proceed 调用原方法的闭包 * @param Layer $layer 原方法的参数 * @return array */ public function aroundGetFilters(OriginalFilterList $subject, \Closure $proceed, Layer $layer) { // 原方法执行前的自定义逻辑 // 比如记录日志、准备参数等 // 调用原方法获取结果 $filters = $proceed($layer); // 原方法执行后的自定义逻辑 // 比如修改返回的过滤器数组 // 示例:添加一个自定义过滤器 // $customFilter = $subject->objectManager->create(\YourVendor\YourModule\Model\Layer\Filter\Custom::class, ['layer' => $layer]); // $filters[] = $customFilter; return $filters; } }
- 配置插件
在app/code/YourVendor/YourModule/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\Layer\FilterList"> <plugin name="yourmodule_filterlist_around_plugin" type="YourVendor\YourModule\Plugin\Model\Layer\FilterList" sortOrder="10" /> </type> </config>
错误原因说明:
你之前的代码把FilterableAttributeListInterface作为第二个参数,但实际上around方法的第二个参数必须是\Closure类型的$proceed,原方法的参数($layer)是第三个参数,这就导致了PHP类型校验失败,抛出TypeError。
最后提醒
不管用哪种方式重写,修改后都要:
- 清理配置缓存和全缓存
- 必要时执行
bin/magento setup:di:compile(生产模式下) - 确认模块的依赖关系正确,没有和其他模块的重写冲突
内容的提问来源于stack exchange,提问作者Nandhini Nagaraj
相关产品推荐
相关产品推荐

