addFilter vs addFieldToFilter


19

Magento集合有两种过滤方法:

1. Varien_Data_Collection_Db::addFieldToFilter
2. Varien_Data_Collection::addFilter

似乎这两种方法都将条件添加到Zend_Db_SelectaddFilter带来什么优势?什么时候应该代替它addFieldToFilter

Answers:


49

好,让我们检查一下。第一个区别是addFilter()更通用,而不是特定于数据库。还可用于Varien_Directory_Collection按文件名过滤。但是对于这个答案,我将重点关注Varien_Data_Collection_Db

它们的方法具有不同的签名,addFilter似乎不太灵活,但是您会发现它也具有优点:

1. addFieldToFilter()

/**
 * Add field filter to collection
 *
 * @see self::_getConditionSql for $condition
 *
 * @param   string|array $field
 * @param   null|string|array $condition
 *
 * @return  Mage_Eav_Model_Entity_Collection_Abstract
 */
public function addFieldToFilter($field, $condition = null)

参量

addFieldToFilter()可以采用带有条件数组的字段数组,也可以采用带有单个条件的单个字段:

  • addFieldToFilter('field', 'value')

    结果是: field=value

  • addFieldToFilter(['field1', 'field2'], ['value1', 'value2']);

    结果是: field1=value1 OR field2=value2

每个条件可以是:

  • 单个标量值(如'value1''value2'以上)
  • 形式的数组 [ operator => value ]
  • 一个Zend_Db_Expr对象
  • 与“ OR”组合的条件数组(是的,这是递归的)

这尤其是“ operator => value”语法记录在以下代码中Varien_Db_Adapter_Pdo_Mysql::prepareSqlCondition()-记住这一点,我经常查看它们:

 * If $condition integer or string - exact value will be filtered ('eq' condition)
 *
 * If $condition is array - one of the following structures is expected:
 * - array("from" => $fromValue, "to" => $toValue)
 * - array("eq" => $equalValue)
 * - array("neq" => $notEqualValue)
 * - array("like" => $likeValue)
 * - array("in" => array($inValues))
 * - array("nin" => array($notInValues))
 * - array("notnull" => $valueIsNotNull)
 * - array("null" => $valueIsNull)
 * - array("moreq" => $moreOrEqualValue)
 * - array("gt" => $greaterValue)
 * - array("lt" => $lessValue)
 * - array("gteq" => $greaterOrEqualValue)
 * - array("lteq" => $lessOrEqualValue)
 * - array("finset" => $valueInSet)
 * - array("regexp" => $regularExpression)
 * - array("seq" => $stringValue)
 * - array("sneq" => $stringValue)
 *
 * If non matched - sequential array is expected and OR conditions
 * will be built using above mentioned structure

from/ to运算符中还有其他未记录的功能:

  • ['from' => $dateFrom, 'to' => $dateTo, 'date' => true]$dateFrom$dateTo值会被解析为日期。它们可以采用以下任何一种形式Varien_Date::formatDate()
  • 如果您需要日期解析功能,但仅用于比较<=或之一>=,则可以省略'from''to'
  • 'datetime' => true应该也可以工作,并包括时间,不仅是日期,而且Varien_Db_Adapter_Pdo_Mysql :: __ prepareSqlDateCondition()(缺少$includeTimestamp参数)中存在一个错误,它的datetime工作方式与相同date两者都包含时间。所以,如果你需要按日期仅对比,添加00:00:00from日期23:59:59to日期。

场图

该方法使用字段映射。可以在具体的集合类中定义字段映射以创建别名字段名称。以下是产品集合中的示例:

protected $_map = array('fields' => array(
    'price'         => 'price_index.price',
    'final_price'   => 'price_index.final_price',
    'min_price'     => 'price_index.min_price',
    'max_price'     => 'price_index.max_price',
    'tier_price'    => 'price_index.tier_price',
    'special_price' => 'price_index.special_price',
));

2. addFilter()

/**
 * Add collection filter
 *s
 * @param string $field
 * @param string $value
 * @param string $type and|or|string
 */
public function addFilter($field, $value, $type = 'and')

参量

addFilter()仅允许按单个值和一个类型过滤单个字段。$type可以是以下任何一个:

  • “ and”(默认)-添加AND $field=$value到WHERE子句(当然使用正确的引号)
  • “或”-添加"OR $field=$value到WHERE子句(同上)
  • “ string”-添加AND $value到WHERE子句(即$ value可以是任意SQL表达式)
  • “ public”-使用字段映射_getConditionSql(),类似于addFieldToFilter()。这使其功能几乎一样强大,只是缺少为OR组合的不同字段添加多个过滤器的功能。

Varien_Data_Collection_Db::_renderFilters()您可以看到它们的处理方式。

可扩展性

有一个重要的区别是对...有好处addFilter()。它收集要应用的过滤器,$this->_filters()并且仅Zend_Db_Select在加载集合之前将它们添加到查询对象中。addFieldToFilter()另一方面,立即操作查询对象。

这使您可以操作或删除已添加的过滤器。Varien集合没有为此提供接口,您必须在自定义集合中实现此接口。有一个挂钩方法_renderFiltersBefore()可以覆盖。


我有一个问题,我们可以使用addFilterattributes
Murtuza Zabuawala

@MurtuzaZabuawala不,它不能用于EAV属性
Fabian Schmengler

谢谢您的回答。Fabian,我也很喜欢您的网站上的帖子,但是$ Field在addFilter中可以保留什么值?我正在尝试使用addFilter函数仅过滤模块正在运行的类别中的产品
John

无法使用AFAIK,因为类别不是属性,而是与单独表中的产品相关联。抱歉,无法为您提供解决方案
Fabian Schmengler,

感谢您的答复,不用担心,如果我找到解决方法,我将在此处更新解决方案
约翰·

2

Magento集合有两种过滤波纹管的方法

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter($ field,$ condition = null)

的第一个参数addFieldToFilter是您希望作为过滤依据的属性。第二个是您要寻找的价值。这是我们sku为value 添加一个过滤器n2610

第二个参数也可以用于指定您要执行的过滤类型。这使事情变得有些复杂,值得深入研究。

因此,默认情况下,

$collection_of_products->addFieldToFilter('sku','n2610'); 

(基本上)等于

WHERE sku = "n2610"

看看自己。运行以下

public function testAction()
{
    var_dump(
    (string) 
    Mage::getModel('catalog/product')
    ->getCollection()
    ->addFieldToFilter('sku','n2610')
    ->getSelect());
}

将产生

SELECT `e`.* FROM `catalog_product_entity` AS `e` WHERE (e.sku = 'n2610')'

请记住,如果您使用的是EAV属性,这可能会很快变得复杂。添加属性

var_dump(
(string) 
Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('meta_title','my title')
->getSelect()
);

并且查询变得陈旧。

SELECT `e`.*, IF(_table_meta_title.value_id>0, _table_meta_title.value, _table_meta_title_default.value) AS `meta_title` 
FROM `catalog_product_entity` AS `e` 
INNER JOIN `catalog_product_entity_varchar` AS `_table_meta_title_default` 
    ON (_table_meta_title_default.entity_id = e.entity_id) AND (_table_meta_title_default.attribute_id='103') 
    AND _table_meta_title_default.store_id=0        
LEFT JOIN `catalog_product_entity_varchar` AS `_table_meta_title` 
    ON (_table_meta_title.entity_id = e.entity_id) AND (_table_meta_title.attribute_id='103') 
    AND (_table_meta_title.store_id='1') 
WHERE (IF(_table_meta_title.value_id>0, _table_meta_title.value, _table_meta_title_default.value) = 'my title')

不要太在意这一点,但是如果您在截止日期之前,请不要对SQL过多考虑。

其他比较运算符我敢肯定,您想知道“我是否想要查询之外的其他东西”?不等于,大于,小于,等等。addFieldToFilter方法的第二个参数也已在此处介绍。它支持一种替代语法,在该语法中,您无需传递字符串,而是传递单个元素Array。

该数组的关键是要进行比较的类型。与该键关联的值是您要作为过滤依据的值。让我们重做上面的过滤器,但是使用这种显式的语法

public function testAction()
{
    var_dump(
    (string) 
    Mage::getModel('catalog/product')
    ->getCollection()
    ->addFieldToFilter('sku',array('eq'=>'n2610'))
    ->getSelect()
    );          
}

调出我们的过滤器

addFieldToFilter('sku',array('eq'=>'n2610'))

如您所见,第二个参数是PHP Array。它的键是eq,表示等于。该键的值为n2610,这是我们要过滤的值。

Magento有许多这样的英语语言,例如过滤器,它会给听众中的所有老Perl开发人员带来纪念(或痛苦)的眼泪。

下面列出了所有筛选器,以及它们的SQL等效项的示例。

array("eq"=>'n2610')
WHERE (e.sku = 'n2610')

array("neq"=>'n2610')
WHERE (e.sku != 'n2610')

array("like"=>'n2610')
WHERE (e.sku like 'n2610')

array("nlike"=>'n2610')
WHERE (e.sku not like 'n2610')

array("is"=>'n2610')
WHERE (e.sku is 'n2610')

array("in"=>array('n2610'))
WHERE (e.sku in ('n2610'))

array("nin"=>array('n2610'))
WHERE (e.sku not in ('n2610'))

array("notnull"=>'n2610')
WHERE (e.sku is NOT NULL)

array("null"=>'n2610')
WHERE (e.sku is NULL)

array("gt"=>'n2610')
WHERE (e.sku > 'n2610')

array("lt"=>'n2610')
WHERE (e.sku < 'n2610')

array("gteq"=>'n2610')
WHERE (e.sku >= 'n2610')

array("moreq"=>'n2610') //a weird, second way to do greater than equal
WHERE (e.sku >= 'n2610')

array("lteq"=>'n2610')
WHERE (e.sku <= 'n2610')

array("finset"=>array('n2610'))
WHERE (find_in_set('n2610',e.sku))

array('from'=>'10','to'=>'20')
WHERE e.sku >= '10' and e.sku <= '20'

其中大多数是不言自明的,但有一些值得特别说明

in,nin,find_in_set in和nin条件语句允许您传入值数组。也就是说,您的过滤器数组的值部分本身允许为数组。

array("in"=>array('n2610','ABC123')
WHERE (e.sku in ('n2610','ABC123'))

notnull,null关键字NULL在大多数SQL版本中都是特殊的。它通常不能与标准的等号(=)运算符配合使用。指定notnull或null作为过滤器类型将为您提供NULL比较的正确语法,同时忽略您传入的任何值

array("notnull"=>'n2610')
WHERE (e.sku is NOT NULL)

从-到过滤器这是违反标准规则的另一种特殊格式。您可以指定两个元素数组,而不是单个元素数组。一个元素具有来自的键,另一个元素具有至的键。如键所示,该过滤器使您可以构造一个从/到范围,而不必担心大于和小于符号

public function testAction
{
        var_dump(
        (string) 
        Mage::getModel('catalog/product')
        ->getCollection()
        ->addFieldToFilter('price',array('from'=>'10','to'=>'20'))
        ->getSelect()
        );                      
}

以上收益

WHERE (_table_price.value >= '10' and _table_price.value <= '20')'

AND或OR,还是OR和AND?最后,我们介绍布尔运算符。这是罕见的时刻,我们只按一个属性进行过滤。幸运的是,Magento的收藏涵盖了我们。您可以将对addFieldToFilter的多个调用链接在一起,以获取多个“ AND”查询。

function testAction()
{
        echo(
        (string) 
        Mage::getModel('catalog/product')
        ->getCollection()
        ->addFieldToFilter('sku',array('like'=>'a%'))
        ->addFieldToFilter('sku',array('like'=>'b%'))
        ->getSelect()
        );                                  
}

通过如上所述将多个调用链接在一起,我们将生成一个where子句,其外观类似于以下内容

WHERE (e.sku like 'a%') AND (e.sku like 'b%')

对于刚刚举手的人,是的,上面的示例将始终返回0条记录。sku不能以a a和b开头。我们可能想要的是一个OR查询。这将我们带到了addFieldToFilter的第二个参数的另一个令人困惑的方面。

如果要构建OR查询,则需要传入一个Array of filter数组作为第二个参数。我发现最好将各个过滤器数组分配给变量

public function testAction()
{
        $filter_a = array('like'=>'a%');
        $filter_b = array('like'=>'b%');
}

然后为我所有的过滤器变量分配一个数组

public function testAction()
{
        $filter_a = array('like'=>'a%');
        $filter_b = array('like'=>'b%');
        echo(
        (string) 
        Mage::getModel('catalog/product')
        ->getCollection()
        ->addFieldToFilter('sku',array($filter_a,$filter_b))
        ->getSelect()
        );
}

为了明确起见,这里是前面提到的过滤器数组Array。

array($filter_a,$filter_b)

这将为我们提供WHERE子句,其外观类似于以下内容

WHERE (((e.sku like 'a%') or (e.sku like 'b%')))
  1. Varien_Data_Collection :: addFilter
 addFilter($field, $value, $type = 'and')

addFilter()仅允许按单个值和类型过滤单个字段。$type可以是以下任何一个:

  1. “ and”(默认)-将AND $ field = $ value添加到WHERE子句
  2. “或”-在WHERE子句中添加“ OR $ field = $ value

查看更多细节


1
这什么也没解释。
Fabian Schmengler,

这没有任何意义。它没有描述这些方法的区别
Lindar


2
您更新后的答案大部分是从alanstorm.com/magento_collections复制的。请至少引用您的消息来源!
Fabian Schmengler,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.