addFilter vs addFieldToFilter


19

Bộ sưu tập Magento có hai phương pháp để lọc:

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

Có vẻ như cả hai phương pháp thêm điều kiện vào Zend_Db_Select. Và những lợi thế nào addFiltermang lại? Khi nào tôi nên sử dụng nó thay vì addFieldToFilter?

Câu trả lời:


49

OK, hãy kiểm tra chúng. Sự khác biệt đầu tiên là addFilter()chung chung hơn và không phải là cơ sở dữ liệu cụ thể. Nó cũng được sử dụng Varien_Directory_Collectionđể lọc theo tên tệp. Nhưng đối với câu trả lời này tôi sẽ tập trung vào Varien_Data_Collection_Db.

Các phương thức của chúng có một chữ ký khác nhau, nơi addFilterdường như kém linh hoạt hơn, nhưng bạn sẽ thấy rằng nó cũng có những ưu điểm của nó:

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)

Thông số

addFieldToFilter () có thể lấy một mảng các trường có một mảng các điều kiện hoặc một trường có một điều kiện duy nhất:

  • addFieldToFilter('field', 'value')

    Kết quả trong: field=value

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

    Kết quả trong: field1=value1 OR field2=value2

Mỗi điều kiện có thể là:

  • một giá trị vô hướng (như 'value1''value2'trên)
  • một mảng trong mẫu [ operator => value ]
  • một Zend_Db_Exprđối tượng
  • một loạt các điều kiện được kết hợp với "HOẶC" (vâng, đó là đệ quy)

Điều này, đặc biệt là cú pháp "toán tử => giá trị" được ghi lại trong mã tại Varien_Db_Adapter_Pdo_Mysql::prepareSqlCondition()- hãy nhớ điều này, tôi tìm kiếm chúng khá thường xuyên:

 * 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

Có thêm tính năng không có giấy tờ trong from/ totoán tử:

  • với ['from' => $dateFrom, 'to' => $dateTo, 'date' => true]các $dateFrom$dateTogiá trị này sẽ được phân tích như ngày. Họ có thể ở bất kỳ hình thức nào được chấp nhận bởiVarien_Date::formatDate()
  • nếu bạn cần tính năng phân tích ngày nhưng chỉ để so sánh một trong <=hoặc >=, bạn có thể bỏ qua một trong hai 'from'hoặc 'to'.
  • 'datetime' => trueđược cho là cũng hoạt động và bao gồm cả thời gian, không chỉ trong ngày, mà còn có một lỗi trong Varien_Db_Ad Module_Pdo_Mysql :: _ readySqlDateCondition () (thiếu $includeTimestamptham số) khiến datetimecông việc giống như date. Cả hai bao gồm thời gian. Vì vậy, nếu bạn cần phải so sánh theo ngày duy nhất, thêm 00:00:00vào fromngày và 23:59:59đến tongày.

Bản đồ trường

Phương pháp sử dụng ánh xạ trường. Ánh xạ trường có thể được định nghĩa trong các lớp tập hợp cụ thể để tạo tên trường bí danh. Dưới đây là một ví dụ từ bộ sưu tập sản phẩm:

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

Thông số

addFilter()chỉ cho phép lọc một trường theo một giá trị và một loại . $typecó thể là bất kỳ:

  • "và" (mặc định) - thêm AND $field=$value vào mệnh đề WHERE (tất nhiên với trích dẫn thích hợp)
  • "hoặc" - thêm "OR $field=$valuevào mệnh đề WHERE (ditto)
  • "chuỗi" - thêm AND $valuevào mệnh đề WHERE (nghĩa là giá trị $ có thể là biểu thức SQL tùy ý)
  • "công khai" - sử dụng ánh xạ trường và _getConditionSql(), tương tự như addFieldToFilter(). Điều này làm cho nó gần như mạnh mẽ, nó chỉ thiếu tính năng để thêm nhiều bộ lọc cho các trường khác nhau kết hợp với OR.

Trong Varien_Data_Collection_Db::_renderFilters()bạn có thể thấy cách chúng được xử lý.

Khả năng mở rộng

Có một sự khác biệt quan trọng là một lợi thế cho addFilter(). Nó thu thập các bộ lọc được áp dụng $this->_filters()và chỉ thêm chúng vào Zend_Db_Selectđối tượng truy vấn ngay trước khi tải bộ sưu tập. addFieldToFilter()mặt khác thao tác đối tượng truy vấn ngay lập tức.

Điều này cho phép bạn thao tác hoặc xóa các bộ lọc đã được thêm vào. Bộ sưu tập Varien không có giao diện cho nó, bạn phải thực hiện điều này trong bộ sưu tập tùy chỉnh của mình. Có một phương thức hook _renderFiltersBefore()mà bạn có thể ghi đè.


Tôi có một câu hỏi chúng ta có thể sử dụng addFiltervới attributes?
Murtuza Zabuawala

@MurtuzaZabuawala không, nó không thể được sử dụng cho các thuộc tính EAV
Fabian Schmengler

Cảm ơn bạn vì câu trả lời này Fabian, tôi cũng rất thích bài đăng trên trang web của bạn về vấn đề này nhưng trường $ có thể giữ giá trị nào trong addFilter? Tôi đang cố gắng sử dụng chức năng addFilter để chỉ lọc các sản phẩm nằm trong danh mục mà mô-đun đang chạy
John

AFAIK không thể vì các danh mục không phải là thuộc tính nhưng được liên kết với các sản phẩm trong một bảng riêng biệt. Xin lỗi, không thể đưa cho bạn một giải pháp trên đầu tôi, xin lỗi
Fabian Schmengler

Cảm ơn bạn đã phản hồi, không phải lo lắng, nếu tôi tìm được cách nào đó, tôi sẽ cập nhật ở đây với giải pháp của mình
John

2

Bộ sưu tập Magento có hai phương pháp để lọc dưới đây khác nhau

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter ($ field, $ condition = null)

Tham số đầu tiên addFieldToFilterlà thuộc tính bạn muốn lọc theo. Thứ hai là giá trị bạn đang tìm kiếm. Đây là chúng tôi thêm một skubộ lọc cho giá trị n2610.

Tham số thứ hai cũng có thể được sử dụng để chỉ định loại bộ lọc bạn muốn làm. Đây là nơi mọi thứ trở nên phức tạp một chút và đáng để đi sâu hơn một chút.

Vì vậy, theo mặc định, sau đây

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

là (về cơ bản) tương đương với

WHERE sku = "n2610"

Hãy xem cho chính mình. Chạy như sau

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

sẽ mang lại

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

Hãy nhớ rằng, điều này có thể trở nên phức tạp nhanh nếu bạn đang sử dụng thuộc tính EAV. Thêm một thuộc tính

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

và truy vấn được sởn gai ốc.

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

Không tin vào quan điểm, nhưng cố gắng đừng suy nghĩ quá nhiều về SQL nếu bạn đến hạn chót.

Các toán tử so sánh khác Tôi chắc chắn rằng bạn đang tự hỏi về điều gì nếu tôi muốn một cái gì đó khác với một truy vấn bằng cách truy vấn? Không bằng nhau, lớn hơn, nhỏ hơn, v.v. Tham số thứ hai của phương thức addFieldToFilter cũng được bạn đề cập ở đó. Nó hỗ trợ một cú pháp thay thế trong đó, thay vì truyền vào một chuỗi, bạn truyền vào một mảng phần tử duy nhất.

Chìa khóa của mảng này là kiểu so sánh bạn muốn thực hiện. Giá trị được liên kết với khóa đó là giá trị bạn muốn lọc theo. Hãy làm lại bộ lọc ở trên, nhưng với cú pháp rõ ràng này

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

Gọi ra bộ lọc của chúng tôi

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

Như bạn có thể thấy, tham số thứ hai là một mảng PHP. Chìa khóa của nó là eq, viết tắt của bằng. Giá trị cho khóa này là n2610, là giá trị chúng tôi đang lọc.

Magento có một số ngôn ngữ tiếng Anh như các bộ lọc sẽ mang lại một giọt nước mắt nhớ (và có lẽ là nỗi đau) cho bất kỳ nhà phát triển perl cũ nào trong khán giả.

Dưới đây là tất cả các bộ lọc, cùng với một ví dụ về các tương đương SQL của chúng.

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'

Hầu hết trong số này là tự giải thích, nhưng một số ít xứng đáng với một chú thích đặc biệt

in, nin, find_in_set Các điều kiện trong và nin cho phép bạn truyền vào một mảng các giá trị. Nghĩa là, phần giá trị của mảng bộ lọc của bạn được phép là một mảng.

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

notnull, null Từ khóa NULL đặc biệt trong hầu hết các hương vị của SQL. Nó thường không chơi tốt với toán tử đẳng thức (=) tiêu chuẩn. Chỉ định notnull hoặc null làm loại bộ lọc của bạn sẽ giúp bạn có được cú pháp chính xác để so sánh NULL trong khi bỏ qua bất kỳ giá trị nào bạn chuyển vào

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

từ - đến bộ lọc Đây là một định dạng đặc biệt khác phá vỡ quy tắc chuẩn. Thay vì một mảng phần tử đơn, bạn chỉ định một mảng hai phần tử. Một yếu tố có chìa khóa từ, yếu tố khác có chìa khóa để. Như các khóa được chỉ định, bộ lọc này cho phép bạn tạo một phạm vi từ / đến phạm vi mà không phải lo lắng về lớn hơn và nhỏ hơn các ký hiệu

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

Sản lượng trên

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

VÀ hoặc HOẶC, hoặc đó là HAY và VÀ? Cuối cùng, chúng ta đến với các toán tử boolean. Đó là khoảnh khắc hiếm hoi khi chúng ta chỉ lọc theo một thuộc tính. May mắn thay, Bộ sưu tập của Magento đã bảo vệ chúng tôi. Bạn có thể xâu chuỗi nhiều cuộc gọi với addFieldToFilter để nhận được một số truy vấn của trò chơi TRỰC TIẾP.

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

Bằng cách kết hợp nhiều cuộc gọi như trên, chúng tôi sẽ tạo ra một mệnh đề where trông giống như sau

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

Đối với những bạn vừa giơ tay, vâng, ví dụ trên sẽ luôn trả về 0 hồ sơ. Không có sku có thể bắt đầu với CẢ HAI a và b. Những gì chúng ta có thể muốn ở đây là một truy vấn HOẶC. Điều này đưa chúng ta đến một khía cạnh khó hiểu khác của tham số thứ hai của addFieldToFilter.

Nếu bạn muốn xây dựng một truy vấn OR, bạn cần truyền một mảng của bộ lọc Mảng trong như là tham số thứ hai. Tôi thấy tốt nhất là chỉ định bộ lọc riêng lẻ của bạn cho các biến

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

và sau đó gán một mảng của tất cả các biến bộ lọc của tôi

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

Để giải thích rõ ràng, đây là Mảng bộ lọc đã nói ở trên.

array($filter_a,$filter_b)

Điều này sẽ cho chúng ta một mệnh đề WHERE trông giống như sau

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

addFilter()chỉ cho phép lọc một trường theo một giá trị và một loại. $typecó thể là bất kỳ:

  1. "và" (mặc định) - thêm AND $ field = $ value vào mệnh đề WHERE
  2. "hoặc" - thêm "OR $ field = $ value vào mệnh đề WHERE

Xem thêm chi tiết


1
Điều này không giải thích bất cứ điều gì.
Fabian Schmengler

Điều này không có ý nghĩa gì. Nó không mô tả sự khác biệt của các phương pháp này
Lindar


2
Câu trả lời cập nhật của bạn chủ yếu được sao chép từ alanstorm.com/magento_collections . Vui lòng trích dẫn nguồn của bạn ít nhất!
Fabian Schmengler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.