addFilter vs addFieldToFilter


19

Колекція Magento має два способи фільтрації:

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

Здається, що обидва способи додають туди, де умова Zend_Db_Select. І які переваги addFilterприносить? Коли я повинен використовувати його замість addFieldToFilter?

Відповіді:


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об'єкт
  • масив умов, які поєднуються з "АБО" (так, це рекурсивно)

Цей синтаксис "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 :: _ PrepaSqlDateCondition () (відсутній $includeTimestampпараметр), що робить datetimeроботу так само, як і date. Обидва включають час. Так що, якщо вам потрібно порівнювати тільки за датою, додати 00:00:00до fromдатою і 23:59:59до toдати.

Картографічне поле

Метод використовує картографічне поле. Відображення полів можна визначити в конкретних класах збору для створення псевдонімів імен полів. Ось приклад із колекції товарів:

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 $field=$value до пункту WHERE (звичайно, при правильному цитуванні)
  • "або" - додає "OR $field=$value до пункту WHERE (ditto)
  • "рядок" - додає AND $value до пункту WHERE (тобто значення $ може бути довільним виразом SQL)
  • "public" - використовує картографічне поле та _getConditionSql()подібне до addFieldToFilter(). Це робить його майже таким же потужним, йому лише відсутня можливість додавання декількох фільтрів для різних полів у поєднанні з АБО.

В Varien_Data_Collection_Db::_renderFilters() ви можете побачити , як вони обробляються.

Розширюваність

Є одна важлива відмінність, яка є перевагою addFilter(). Він збирає фільтри, які слід застосувати, $this->_filters()і лише додає їх до Zend_Db_Selectоб'єкта запиту безпосередньо перед завантаженням колекції.addFieldToFilter()з іншого боку, негайно маніпулює об'єктом запиту.

Це дозволяє вам маніпулювати або видаляти фільтри, які вже були додані. Колекція Varien не має для неї інтерфейсу, ви повинні реалізувати це у вашій спеціальній колекції. Існує метод гачка, _renderFiltersBefore()який можна перекрити.


У мене є одне питання , чи можна використовувати addFilterз attributes?
Murtuza Zabuawala

@MurtuzaZabuawala ні, його не можна використовувати для атрибутів EAV
Fabian Schmengler

Дякую за цю відповідь, Фабіан, мені також сподобався пост вашого веб-сайту, але яке значення може мати $ field у addFilter? Я намагаюся використовувати функцію addFilter для фільтрації лише тих продуктів, які належать до категорії, в якій працює модуль
Джон

AFAIK неможливий, оскільки категорії не є атрибутами, а асоціюються з продуктами в окремій таблиці. Не можу дати вам рішення на голові, вибачте
Фабіан Шменглер

Дякую за відповідь, не хвилюйтесь, якщо я знайду спосіб його вирішення, я оновлю тут своє рішення
Джон

2

Колекція Magento має два способи фільтрування внизу різних

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter ($ поле, $ умова = null)

Перший параметр addFieldToFilter- це атрибут, за яким ви хочете відфільтрувати. Друга - цінність, яку ви шукаєте. Ось ми додаємо skuфільтр для значення 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 також охопив вас там. Він підтримує альтернативний синтаксис, де замість передачі рядка ви передаєте один елемент масиву.

Ключ цього масиву - тип порівняння, який ви хочете зробити. Значення, пов’язане з цим ключем, - це значення, за яким ви хочете відфільтрувати. Давайте повторимо вищевказаний фільтр, але з цим явним синтаксисом

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

Виклик нашого фільтра

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

Як бачите, другий параметр - це масив PHP. Його ключовим елементом є еквівалент, який означає рівність. Значення цього ключа 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 Умови та умови 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 Це ще один спеціальний формат, який порушує стандартне правило. Замість масиву одного елемента ви задаєте масив з двома елементами. Один елемент має ключ від, інший елемент - ключ від. Як вказано в клавішах, цей фільтр дозволяє створити діапазон / в діапазон, не турбуючись про більше, ніж символи

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

ІЛИ АБО, або це АБО та І? Нарешті, ми підходимо до булевих операторів. Це рідкісний момент, коли ми фільтруємо лише один атрибут. На щастя, колекції Magento охопили нас. Ви можете з'єднати декілька викликів до addFieldToFilter, щоб отримати ряд запитів "І".

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

Об’єднавши декілька викликів, як описано вище, ми створимо пункт де, який виглядає приблизно так

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

Тим із вас, хто щойно підняв руку, так, наведений вище приклад завжди повертає 0 записів. Жодна ску не може починатися з БОТИ a та a b. Що ми, мабуть, хочемо тут - це АБО запит. Це приводить нас до іншого заплутаного аспекту другого параметра addFieldToFilter.

Якщо ви хочете створити запит АБО, вам потрібно передати масив фільтрів масивів як другий параметр. Я вважаю, що найкраще призначити ваші індивідуальні масиви фільтрів змінним

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
  2. "або" - додає "АБО $ поле = значення $ до пункту WHERE

Детальніше


1
Це нічого не пояснює.
Фабіан Шменглер

Це не має сенсу. Тут не описано різницю цих методів
Ліндар

Дивіться більше деталей wiki.magento.com/display/m1wiki/Using+Magento+1.x+collections
Абдул

2
Ваша оновлена ​​відповідь здебільшого скопійована з alanstorm.com/magento_collections . Принаймні, цитуйте свої джерела!
Фабіан Шменглер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.