addFilter vs addFieldToFilter


19

Magentoコレクションには、フィルタリングのための2つの方法があります。

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

両方のメソッドがwhere条件をに追加するようZend_Db_Selectです。また、どのような利点がありaddFilterますか?代わりにaddFieldToFilterいつ使用する必要がありますか?

回答:


49

OK、それらを調べてみましょう。最初の違いは、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」と組み合わせた条件の配列(はい、それは再帰的です)

これ、特に「演算子=>値」の構文は次のコードに記載されています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$dateToVarien_Date::formatDate()
  • 日付解析機能が必要な場合、<=またはの>=いずれかを比較するだけの場合は、'from'またはのいずれかを省略できます'to'
  • 'datetime' => trueは、1日だけでなく、時刻も含むように機能することになっていますが、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式にすることができます)
  • 用途フィールドマッピングと- 「公共」_getConditionSql()に似ました、addFieldToFilter()。これにより、ほぼ同じように強力になります。ORを組み合わせたさまざまなフィールドに複数のフィルターを追加する機能が欠けています。

ではVarien_Data_Collection_Db::_renderFilters()、あなたそれらがどのように処理されるかを見ることができます。

拡張性

の利点である重要な違いが1つありaddFilter()ます。適用するフィルターを収集し、コレクションを読み込む直前にクエリオブジェクトに$this->_filters()追加するだけZend_Db_Selectです。addFieldToFilter()一方、クエリオブジェクトをすぐに操作します。

これにより、既に追加されているフィルターを操作または削除できます。Varienコレクションにはインターフェースがありません。これをカスタムコレクションに実装する必要があります。_renderFiltersBefore()オーバーライドできるフックメソッドがあります。


一つ質問があります addFilterありattributesますか?
ムルツザザブアワラ

@MurtuzaZabuawalaいいえ、EAV属性には使用できません
ファビアンシュメングラー

この答えをありがとうFabian、これに関するあなたのウェブサイトの投稿も楽しみましたが、addFilterで$ fieldが保持できる値は何ですか?私は、モジュールが実行されているカテゴリにある製品のみフィルタリングするかaddFilter機能を使用しようとしている
ジョン

カテゴリは属性ではなく、別のテーブルの製品に関連付けられているため、FAIKはできません。私の頭の上で解決策を提供することはできません、ごめんなさい
ファビアン・シュメングラー

回答いただきありがとうございます。心配する必要はありません。方法を見つけたら、ここでソリューションを更新します
ジョン

2

Magentoコレクションには、以下の2つのフィルタリング方法があります。

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter($ field、$ condition = null)

の最初のパラメーターaddFieldToFilterは、フィルター処理する属性です。2番目は、探している値です。skuvalueのフィルターを追加していますn2610

2番目のパラメーターを使用して、実行するフィルタリングのタイプを指定することもできます。これは、物事が少し複雑になる場所であり、もう少し詳しく説明する価値があります。

したがって、デフォルトでは、次の

$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メソッドの2番目のパラメーターでも同様に説明します。文字列を渡す代わりに、単一要素の配列を渡す代替構文をサポートしています。

この配列のキーは、作成する比較のタイプです。そのキーに関連付けられている値は、フィルター処理する値です。上記のフィルターをやり直しましょうが、この明示的な構文で

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

フィルターを呼び出す

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

ご覧のとおり、2番目のパラメーターはPHP配列です。そのキーはeqで、equalsを表します。このキーの値は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)

from-to filterこれは、標準ルールを破る別の特別な形式です。単一の要素配列の代わりに、2つの要素配列を指定します。一方の要素にはキーがあり、もう一方の要素にはキーがあります。キーが示すように、このフィルターにより、大なり記号よりも小さい記号を心配することなく、開始/終了範囲を構築できます。

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ですか?最後に、ブール演算子について説明します。1つの属性のみでフィルタリングを行うのはまれな瞬間です。幸いなことに、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の両方で始めることはできません。ここでおそらく必要なのはORクエリです。これにより、addFieldToFilterの2番目のパラメーターの別の混乱する側面に至ります。

ORクエリを作成する場合は、2番目のパラメーターとしてフィルター配列の配列を渡す必要があります。個々のフィルター配列を変数に割り当てるのが最善だと思います

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($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」(デフォルト)-WHERE句にAND $ field = $ valueを追加します
  2. 「または」-「OR $ field = $ value」をWHERE句に追加します

詳細を見る


1
これは何も説明しません。
ファビアンシュメングラー

これは意味がありません。これらの方法の違いについては説明しません
-Lindar


2
更新された回答の大部分は、alanstorm.com / magento_collectionsからコピーされます。少なくともソースを引用してください!
ファビアンシュメングラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.