我正在为拥有基于Magento的商店的客户工作。它充满了产品,但所述产品的名称有点凌乱。他没有坚持一个命名惯例,但多年来一直使用不同的惯例。因此,每当他使用Admin中的Name过滤器查找某些内容时 - >管理产品部分,结果有很多不足之处。
所以我想知道是否有办法使滤波算法更加宽松,特别是在字顺序方面。因为如果您的产品名称为“ word1 word2 word3 ”,并且您搜索“ word1 word3 ”,则产品不会出现在结果中。
任何暗示都将受到赞赏。干杯!
8月28日更新:我的搜索引导我进入类* Mage_Adminhtml_Block_Widget_Grid *,更确切地说是其受保护的方法* _addColumnFilterToCollection()*。在这里你有 $ cond 变量,如果你打印出来它会给你这样的东西:
Array([like] => Zend_Db_Expr Object([_ expression:protected] =>'%search term%'))
这里,如果我可以拦截该搜索词,并在提交给* Zend_Db_Expr *对象之前将其变为'%search%term%',我可能会解决我的问题。那么,有什么想法吗?
答案 0 :(得分:3)
这需要编写具有一定复杂性的自定义模块。
期望,word1 word3
的过滤应该至少返回匹配的子集,过滤word1 word2 word3
确实会返回,这是基于Magento执行的错误假设OR
搜索此网格过滤器。
这是不的情况。在这种情况下,Magento不执行OR
,但LIKE
搜索。
这也解释了为什么结果集
LIKE name = '%word1 word2 word3%'
通常从不 *可以匹配
的结果集LIKE name = '%word1 word3%'
我认为Mage_Adminhtml_Block_Catalog_Product_Grid::_prepareCollection()
是您的代码需要覆盖的最小值,以帮助您入门。
*除了word2 == word3
,当然还有
答案 1 :(得分:2)
您可以将'filter_condition_callback'添加到Magento中的任何网格。为Magento产品网格创建重写并将此参数添加到“名称”字段。像
$this->addColumn('name',
array(
'header'=> Mage::helper('catalog')->__('Name'),
'index' => 'name',
'filter_condition_callback' => array($this, 'filter_name_callback'),
));
然后在同一个类中确定filter_name_callback方法。 像这样:
protected function filter_name_callback($collection, $column)
{
$names = $column->getFilter()->getValue();
$namesArray = explode(' ', $names);
$cond = array();
foreach ($namesArray as $item)
{
$cond[] = 'main_table.name LIKe %'.$item.'%';
}
$collection->getSelect()->where("(".implode(' OR ', $cond).")");
}
代码未经过测试,示例很简单,但我认为您理解这个想法;)祝您好运!
答案 2 :(得分:1)
好的,这是这个问题的解决方案。请注意,我没有对此进行太多测试,只是在我当地的测试magento上。所以可能会出现问题。
我们的工作类是Mage_Adminhtml_Block_Widget_Grid,位于'app / code / core / Mage / Adminhtml / Block / Widget / Grid.php'中。你应该在'app / code / local / Mage / Adminhtml / Block / Widget / Grid.php'中复制这个文件,以免覆盖核心类。
现在,在该文件中转到名为_addColumnFilterToCollection的函数。在这里,删除'} else {'语句中的所有内容并替换为:
$cond = $column->getFilter()->getCondition();
if ($field == "name" && isset($cond)) {
$filterOrig = $cond['like'];
$filterReplaced = str_replace(" ", "%", $filterOrig);
$newZendDbExpr = new Zend_Db_Expr($filterReplaced);
$modifCond = array('like'=>$newZendDbExpr);
$this->getCollection()->addFieldToFilter($field , $modifCond);
} else if ($field && isset($cond)) {
$this->getCollection()->addFieldToFilter($field , $cond);
}
'$ cond'变量是这里的关键。如果你打印它,你会得到类似的东西:
Array([like] => Zend_Db_Expr Object([_expression:protected] => '%filter term%'));
该代码段基本上拦截传递给Zend_Db_Expr对象的过滤器术语,将其传递给str_replace()以用'%'通配符替换任何空格,然后将其发送回对象。
现在,如果您的产品名称为'word1 word2 word3',并按术语'word1 word3'进行搜索过滤,您将获得正确的结果。我愿意接受建议,这可能不是最好的方法。我会在正确测试之后更新。干杯!
SEP 06更新:嗯,经过一些实时测试,结果很好,正是我想要的。似乎也没有负面的性能影响。
有趣的是,这个小修改适用于在管理界面中有产品网格的每个地方进行过滤(例如,手动创建新订单并单击添加产品或在管理类别中 - > ;无论什么类别 - >类别产品标签)
SEP 06更新2 :存在问题。如果您在Orders网格中并尝试按状态过滤,则会引发错误。我需要使此过滤器仅适用于Name字段。有什么想法吗?
SEP 06更新3 :我修改了脚本以仅应用于产品网格的名称字段。现在,按可见性或按状态等顺序与过滤器产品没有冲突。
答案 3 :(得分:0)
要对通配符%搜索给定的列,并且如果可以覆盖核心Grid.php
,则可以在网格类中执行以下操作:
protected function _prepareColumns()
{
parent::_prepareColumns();
// assuming the column is 'name' for product name in the product grid
$this->getColumn('name')->setFilterConditionCallback([$this, 'allowWildcardInFilter']);
...
}
/**
* Allow wildcard % in column search
*/
public function allowWildcardInFilter($collection, $column)
{
if ($value = $column->getFilter()->getValue()) {
if ($field = $column->getFilterIndex() ? $column->getFilterIndex() : $column->getIndex()) {
/**
* @var $helper Mage_Core_Model_Resource_Helper_Mysql4
*/
$helper = Mage::getResourceHelper('core');
$likeExpression = $helper->addLikeEscape($value, [
'position' => 'any',
'allow_string_mask' => true
]);
$collection->addFieldToFilter($field, ['like' => $likeExpression]);
}
}
}