addFilter vs addFieldToFilter

19

Koleksi Magento memiliki dua metode untuk memfilter:

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

Tampaknya kedua metode menambahkan kondisi ke mana Zend_Db_Select. Dan apa addFiltermanfaatnya? Kapan saya harus menggunakannya addFieldToFilter?

Lindar
sumber

Jawaban:

49

Oke, mari kita periksa. Perbedaan pertama adalah yang addFilter()lebih umum dan tidak spesifik database. Ini juga digunakan oleh Varien_Directory_Collectionuntuk menyaring berdasarkan nama file. Tetapi untuk jawaban ini saya akan fokus Varien_Data_Collection_Db.

Mereka metode memiliki tanda tangan yang berbeda, di mana addFiltertampaknya kurang fleksibel, tetapi Anda akan melihat bahwa itu memiliki kelebihan juga:

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)

Parameter

addFieldToFilter () dapat mengambil array bidang dengan array kondisi, atau bidang tunggal dengan satu kondisi:

  • addFieldToFilter('field', 'value')

    Hasil dalam: field=value

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

    Hasil dalam: field1=value1 OR field2=value2

Setiap kondisi dapat:

  • nilai skalar tunggal (seperti 'value1'dan di 'value2'atas)
  • sebuah array dalam formulir [ operator => value ]
  • sebuah Zend_Db_Exprobjek
  • berbagai kondisi yang digabungkan dengan "ATAU" (ya, itu rekursif)

Ini, terutama sintaks "operator => value" didokumentasikan dalam kode at Varien_Db_Adapter_Pdo_Mysql::prepareSqlCondition()- ingat ini, saya sering melihatnya:

 * 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

Ada fitur tidak berdokumen tambahan di from/ tooperator:

  • dengan ['from' => $dateFrom, 'to' => $dateTo, 'date' => true]para $dateFromdan $dateTonilai-nilai akan diurai sebagai tanggal. Mereka dapat dalam bentuk apa pun yang diterima olehVarien_Date::formatDate()
  • jika Anda memerlukan fitur penguraian tanggal tetapi hanya untuk membandingkan satu <=atau >=, Anda dapat menghilangkan salah satu 'from'atau 'to'.
  • 'datetime' => trueseharusnya berfungsi juga dan termasuk waktu, tidak hanya hari, tetapi ada bug di Varien_Db_Adapter_Pdo_Mysql :: _ prepSqlDateCondition () ( $includeTimestampparameter yang hilang ) yang membuat datetimepekerjaan sama seperti date. Keduanya termasuk waktu. Jadi jika Anda perlu membandingkan dengan saat ini hanya, tambahkan 00:00:00ke fromtanggal dan 23:59:59ke totanggal.

Pemetaan lapangan

Metode ini menggunakan pemetaan lapangan. Pemetaan bidang dapat didefinisikan dalam kelas koleksi konkret untuk membuat alias bidang. Berikut ini contoh dari koleksi produk:

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')

Parameter

addFilter()hanya memungkinkan pemfilteran bidang tunggal dengan nilai dan tipe tunggal . $typedapat berupa:

  • "and" (default) - menambah AND $field=$valueklausa WHERE (tentu saja dengan kutipan yang tepat)
  • "atau" - menambah "OR $field=$valueklausa WHERE (ditto)
  • "string" - menambah AND $valueklausa WHERE (mis. $ value bisa berupa ekspresi SQL arbitrer)
  • "publik" - menggunakan pemetaan bidang dan _getConditionSql(), mirip dengan addFieldToFilter(). Ini membuatnya hampir sama kuatnya, hanya saja fitur tersebut tidak ada untuk menambahkan beberapa filter untuk berbagai bidang yang dikombinasikan dengan OR.

Di Varien_Data_Collection_Db::_renderFilters()Anda dapat melihat bagaimana mereka diproses.

Kemungkinan diperpanjang

Ada satu perbedaan penting yang merupakan keuntungan bagi addFilter(). Itu mengumpulkan filter untuk diterapkan $this->_filters()dan hanya menambahkannya ke Zend_Db_Selectobjek permintaan tepat sebelum memuat koleksi. addFieldToFilter()di sisi lain memanipulasi objek permintaan dengan segera.

Ini memungkinkan Anda untuk memanipulasi atau menghapus filter yang sudah ditambahkan. Koleksi Varien tidak memiliki antarmuka untuk itu, Anda harus menerapkan ini dalam koleksi khusus Anda. Ada metode kait _renderFiltersBefore()yang bisa Anda timpa.

Fabian Schmengler
sumber
Saya punya pertanyaan yang kita dapat menggunakan addFilterdengan attributes?
Murtuza Zabuawala
@MurtuzaZabuawala tidak, itu tidak dapat digunakan untuk atribut EAV
Fabian Schmengler
Terima kasih atas jawaban ini, Fabian, saya juga menikmati postingan situs web Anda tentang hal ini, tetapi berapa nilai $ field dalam addFilter? Saya mencoba menggunakan fungsi addFilter untuk memfilter hanya produk yang ada dalam kategori modul berjalan
John
AFAIK tidak dimungkinkan karena kategori bukan atribut tetapi terkait dengan produk dalam tabel terpisah. Tidak dapat memberi Anda solusi di atas kepalaku, maaf
Fabian Schmengler
Terima kasih telah merespons, jangan khawatir, jika saya menemukan jalan keluarnya
John
2

Koleksi Magento memiliki dua metode untuk penyaringan di bawah berbeda

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter ($ field, $ condition = null)

Parameter pertama addFieldToFilteradalah atribut yang ingin Anda filter. Yang kedua adalah nilai yang Anda cari. Di sini kami menambahkan skufilter untuk nilainya n2610.

Parameter kedua juga dapat digunakan untuk menentukan jenis pemfilteran yang ingin Anda lakukan. Di sinilah segala sesuatunya menjadi sedikit rumit, dan layak untuk masuk dengan sedikit lebih dalam.

Jadi secara default, berikut ini

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

(pada dasarnya) setara dengan

WHERE sku = "n2610"

Lihatlah sendiri. Menjalankan yang berikut ini

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

akan menghasilkan

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

Ingat, ini bisa menjadi rumit dengan cepat jika Anda menggunakan atribut EAV. Tambahkan atribut

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

dan kueri menjadi degil.

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')

Bukan untuk mempermasalahkan intinya, tetapi cobalah untuk tidak terlalu memikirkan SQL jika Anda berada di tenggat waktu.

Operator Perbandingan Lainnya Saya yakin Anda bertanya-tanya “bagaimana jika saya menginginkan sesuatu selain yang sama dengan kueri”? Tidak sama, lebih besar dari, kurang dari, dll. Parameter kedua metode addFieldToFilter telah Anda bahas di sana juga. Ini mendukung sintaks alternatif di mana, alih-alih meneruskan dalam string, Anda meneruskan dalam satu elemen Array.

Kunci dari array ini adalah jenis perbandingan yang ingin Anda buat. Nilai yang terkait dengan kunci itu adalah nilai yang ingin Anda filter. Mari kita ulangi filter di atas, tetapi dengan sintaks eksplisit ini

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

Memanggil filter kami

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

Seperti yang Anda lihat, parameter kedua adalah Array PHP. Kuncinya adalah eq, yang berarti sama dengan. Nilai untuk kunci ini adalah n2610, yang merupakan nilai yang kami filterkan.

Magento memiliki sejumlah filter berbahasa Inggris seperti ini yang akan membawa air mata kenangan (dan mungkin sakit) untuk setiap pengembang perl tua di penonton.

Di bawah ini adalah semua filter, bersama dengan contoh setara SQL-nya.

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'

Sebagian besar sudah cukup jelas, tetapi beberapa pantas mendapat info khusus

in, nin, find_in_set Kondisional in dan nin memungkinkan Anda untuk melewatkan Array nilai. Artinya, bagian nilai array filter Anda sendiri diizinkan menjadi array.

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

notnull, null Kata kunci NULL khusus di sebagian besar rasa SQL. Biasanya tidak akan bermain bagus dengan operator kesetaraan standar (=). Menentukan notnull atau null sebagai tipe filter Anda akan memberi Anda sintaks yang benar untuk perbandingan NULL sambil mengabaikan nilai apa pun yang Anda berikan

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

from - to filter Ini adalah format khusus lain yang melanggar aturan standar. Alih-alih array elemen tunggal, Anda menentukan array elemen dua. Satu elemen memiliki kunci dari, elemen lainnya memiliki kunci untuk. Seperti tombol yang ditunjukkan, filter ini memungkinkan Anda untuk membangun dari / ke jangkauan tanpa harus khawatir lebih besar dari dan kurang dari simbol

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

Hasil di atas

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

DAN atau ATAU, atau ATAU dan DAN itu? Akhirnya, kami datang ke operator boolean. Ini adalah momen langka di mana kita hanya memfilter berdasarkan satu atribut. Untungnya, Koleksi Magento sudah kita liput. Anda dapat menyatukan beberapa panggilan ke addFieldToFilter untuk mendapatkan sejumlah pertanyaan "DAN".

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

Dengan menggabungkan beberapa panggilan seperti di atas, kami akan menghasilkan klausa tempat yang terlihat seperti berikut ini

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

Bagi Anda yang baru saja mengangkat tangan, ya, contoh di atas akan selalu mengembalikan 0 catatan. Tidak ada sku yang bisa dimulai dengan KEDUA a dan a. Apa yang mungkin kita inginkan di sini adalah kueri ATAU. Ini membawa kita ke aspek membingungkan lain dari parameter kedua addFieldToFilter.

Jika Anda ingin membuat kueri ATAU, Anda harus meneruskan Array Array filter sebagai parameter kedua. Saya menemukan yang terbaik untuk menetapkan Array filter individual Anda ke variabel

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

dan kemudian menetapkan array dari semua variabel filter saya

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()
        );
}

Untuk menjadi eksplisit, inilah Array filter yang disebutkan di atas.

array($filter_a,$filter_b)

Ini akan memberi kita klausa WHERE yang terlihat seperti berikut

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

addFilter()hanya memungkinkan pemfilteran bidang tunggal dengan nilai dan tipe tunggal. $typedapat berupa:

  1. "and" (default) - menambahkan AND $ field = $ value ke klausa WHERE
  2. "atau" - menambahkan "ATAU $ bidang = $ nilai ke klausa WHERE

Lihat Lebih Detail

Abdul
sumber
1
Ini tidak menjelaskan apa pun.
Fabian Schmengler
Ini tidak masuk akal. Itu tidak menggambarkan perbedaan dari metode ini
Lindar
2
Jawaban Anda yang diperbarui sebagian besar disalin dari alanstorm.com/magento_collections . Harap mengutip sumber Anda setidaknya!
Fabian Schmengler