addFilter vs addFieldToFilter

19

Die Magento-Sammlung bietet zwei Methoden zum Filtern:

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

Scheint, dass beide Methoden wo Bedingung hinzufügen Zend_Db_Select. Und welche Vorteile bringt addFilterdas? Wann sollte ich es verwenden addFieldToFilter?

Lindar
quelle

Antworten:

49

OK, lass sie uns untersuchen. Der erste Unterschied ist, dass addFilter()er allgemeiner und nicht datenbankspezifisch ist. Es wird auch verwendet, um Varien_Directory_Collectionnach Dateinamen zu filtern. Aber für diese Antwort werde ich mich konzentrieren Varien_Data_Collection_Db.

Diese Methoden haben eine andere Signatur, addFilterdie weniger flexibel zu sein scheint, aber Sie werden sehen, dass sie auch ihre Vorteile haben:

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 () kann ein Array von Feldern mit einem Array von Bedingungen oder ein einzelnes Feld mit einer einzelnen Bedingung annehmen:

  • addFieldToFilter('field', 'value')

    Ergebnisse in: field=value

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

    Ergebnisse in: field1=value1 OR field2=value2

Jede Bedingung kann sein:

  • ein einzelner skalarer Wert (wie 'value1'und 'value2'über)
  • ein Array im Formular [ operator => value ]
  • ein Zend_Db_ExprObjekt
  • ein Array von Bedingungen, die mit "OR" kombiniert werden (ja, das ist rekursiv)

Dies, insbesondere die "operator => value" -Syntax, ist im Code unter dokumentiert Varien_Db_Adapter_Pdo_Mysql::prepareSqlCondition()- denken Sie daran, ich schaue sie ziemlich oft nach:

 * 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

Es gibt eine zusätzliche undokumentierte Funktion im Operator from/ to:

  • mit ['from' => $dateFrom, 'to' => $dateTo, 'date' => true]den $dateFromund $dateToWerte werden als Daten analysiert werden. Sie können in jeder Form vorliegen, die von akzeptiert wirdVarien_Date::formatDate()
  • Wenn Sie die Funktion zum Analysieren von Datumsangaben benötigen, jedoch nur zum Vergleichen von <=oder >=, können Sie entweder 'from'oder weglassen 'to'.
  • 'datetime' => truesoll auch funktionieren und die Zeit einschließen, nicht nur den Tag, sondern es gibt einen Fehler in Varien_Db_Adapter_Pdo_Mysql :: _ prepareSqlDateCondition () (fehlender $includeTimestampParameter), der die datetimeArbeit auf die gleiche Weise wie bewirktdate . Beides beinhaltet die Uhrzeit. Wenn Sie also nur 00:00:00nach fromDatum vergleichen müssen, ergänzen Sie das Datum und 23:59:59das toDatum.

Feldzuordnung

Die Methode verwendet die Feldzuordnung. Feldzuordnungen können in konkreten Auflistungsklassen definiert werden, um Alias-Feldnamen zu erstellen. Hier ist ein Beispiel aus der Produktkollektion:

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()Ermöglicht nur das Filtern eines einzelnen Felds nach einem einzelnen Wert und einem Typ . $typekann sein:

  • "and" (Standard) - ergänzt AND $field=$valuedie WHERE-Klausel (natürlich mit korrekter Anführungszeichen)
  • "oder" - ergänzt "OR $field=$valuedie WHERE-Klausel (ebenso)
  • "string" - ergänzt AND $valuedie WHERE-Klausel (dh $ value kann ein beliebiger SQL-Ausdruck sein)
  • "public" - verwendet Feldzuordnung und _getConditionSql()ähnelt addFieldToFilter(). Dies macht es fast so leistungsfähig, es fehlt nur die Funktion, mehrere Filter für verschiedene Felder in Kombination mit ODER hinzuzufügen.

In können Varien_Data_Collection_Db::_renderFilters()Sie sehen, wie sie verarbeitet werden.

Erweiterbarkeit

Es gibt einen wichtigen Unterschied, der von Vorteil ist addFilter(). Es sammelt die Filter, die angewendet werden sollen, $this->_filters()und fügt sie erst Zend_Db_Selectunmittelbar vor dem Laden der Sammlung zum Abfrageobjekt hinzu . addFieldToFilter()Auf der anderen Seite wird das Abfrageobjekt sofort bearbeitet.

Auf diese Weise können Sie bereits hinzugefügte Filter bearbeiten oder entfernen. Die Varien-Sammlung hat keine Schnittstelle dafür, Sie müssen dies in Ihrer benutzerdefinierten Sammlung implementieren. Es gibt eine Hook-Methode _renderFiltersBefore(), die Sie überschreiben können.

Fabian Schmengler
quelle
Ich habe eine eine Frage können wir verwenden , addFiltermit attributes?
Murtuza Zabuawala
@ MurtuzaZabuawala Nein, es kann nicht für EAV-Attribute verwendet werden
Fabian Schmengler
Vielen Dank für diese Antwort Fabian, ich habe den Beitrag deiner Website auch darüber genossen, aber welchen Wert kann $ field in addFilter haben? Ich versuche, die AddFilter-Funktion zu verwenden, um nur Produkte zu filtern, die in der Kategorie sind, in der das Modul ausgeführt wird
John
AFAIK nicht möglich, da Kategorien keine Attribute sind, sondern Produkten in einer separaten Tabelle zugeordnet sind. Ich kann Ihnen keine Lösung auf den Kopf stellen, sorry
Fabian Schmengler
Vielen Dank für die Antwort, keine Sorge, wenn ich einen Weg finde, werde ich hier mit meiner Lösung aktualisieren
John
2

Die Magento-Sammlung verfügt über zwei Methoden zum Filtern des Balgs

  1. Varien_Data_Collection_Db :: addFieldToFilter

addFieldToFilter ($ field, $ condition = null)

Der erste Parameter von addFieldToFilterist das Attribut, nach dem Sie filtern möchten. Der zweite ist der Wert, den Sie suchen. Hier fügen wir einen skuFilter für den Wert hinzu n2610.

Der zweite Parameter kann auch verwendet werden, um die Art der Filterung anzugeben, die Sie ausführen möchten. Dies ist der Punkt, an dem die Dinge etwas komplizierter werden und an dem es sich lohnt, etwas tiefer zu gehen.

Also standardmäßig folgendes

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

ist (im Wesentlichen) äquivalent zu

WHERE sku = "n2610"

Überzeugen Sie sich selbst. Folgendes ausführen

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

wird nachgeben

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

Beachten Sie, dass dies schnell kompliziert werden kann, wenn Sie ein EAV-Attribut verwenden. Attribut hinzufügen

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

und die Abfrage wird knorrig.

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

Nicht um den Punkt zu beleuchten, aber versuchen Sie nicht zu viel über die SQL nachzudenken, wenn Sie an der Deadline sind.

Andere Vergleichsoperatoren Ich bin mir sicher, dass Sie sich fragen: "Was ist, wenn ich nach Abfrage etwas anderes als ein Gleichgestelltes möchte?" Nicht gleich, größer als, kleiner als usw. Mit dem zweiten Parameter der addFieldToFilter-Methode haben Sie sich auch hier befasst. Es wird eine alternative Syntax unterstützt, bei der Sie anstelle einer Zeichenfolge ein einzelnes Element-Array übergeben.

Der Schlüssel dieses Arrays ist die Art des Vergleichs, den Sie durchführen möchten. Der diesem Schlüssel zugeordnete Wert ist der Wert, nach dem Sie filtern möchten. Lassen Sie uns den obigen Filter wiederholen, jedoch mit dieser expliziten Syntax

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

Rufen Sie unseren Filter aus

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

Wie Sie sehen können, ist der zweite Parameter ein PHP-Array. Sein Schlüssel ist eq, was für gleich steht. Der Wert für diesen Schlüssel ist n2610. Dies ist der Wert, nach dem gefiltert wird.

Magento hat eine Reihe dieser englischsprachigen Filter, die alten Perl-Entwicklern im Publikum eine Träne der Erinnerung (und vielleicht Schmerzen) bereiten.

Nachfolgend sind alle Filter zusammen mit einem Beispiel für ihre SQL-Entsprechungen aufgeführt.

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'

Die meisten davon sind selbsterklärend, aber einige verdienen einen besonderen Hinweis

in, nin, find_in_set Mit den Bedingungen in und nin können Sie ein Array von Werten übergeben. Das heißt, der Wertteil Ihres Filterarrays darf selbst ein Array sein.

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

notnull, null Das Schlüsselwort NULL ist in den meisten SQL-Varianten eine Besonderheit. Mit dem Standard-Gleichheitsoperator (=) wird es normalerweise nicht gut. Wenn Sie als Filtertyp notnull oder null angeben, erhalten Sie die richtige Syntax für einen NULL-Vergleich, während Sie den übergebenen Wert ignorieren

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

from - to filter Dies ist ein weiteres spezielles Format, das gegen die Standardregel verstößt. Anstelle eines einzelnen Elementarrays geben Sie ein Array mit zwei Elementen an. Ein Element hat den Schlüssel von, das andere Element hat den Schlüssel von. Wie die angezeigten Tasten zeigen, können Sie mit diesem Filter einen Von / Bis-Bereich erstellen, ohne sich Gedanken über Symbole machen zu müssen, die größer oder kleiner sind

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

Die obigen Ausbeuten

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

UND oder ODER, oder ist das ODER und UND? Schließlich kommen wir zu den Booleschen Operatoren. Es ist der seltene Moment, in dem wir nur nach einem Attribut filtern. Glücklicherweise haben uns Magentos Sammlungen abgedeckt. Sie können mehrere Aufrufe an addFieldToFilter ketten, um eine Reihe von AND-Abfragen zu erhalten.

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

Indem Sie wie oben mehrere Aufrufe verketten, erstellen Sie eine where-Klausel, die ungefähr wie folgt aussieht

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

Für diejenigen von Ihnen, die gerade Ihre Hand erhoben haben, würde das obige Beispiel immer 0 Datensätze zurückgeben. Kein SKU kann mit BEIDEM beginnen. Was wir hier wahrscheinlich wollen, ist eine ODER-Abfrage. Dies bringt uns zu einem weiteren verwirrenden Aspekt des zweiten Parameters von addFieldToFilter.

Wenn Sie eine ODER-Abfrage erstellen möchten, müssen Sie ein Array von Filter-Arrays als zweiten Parameter übergeben. Ich finde es am besten, Ihre individuellen Filter-Arrays Variablen zuzuweisen

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

und dann ein Array aller meiner Filtervariablen zuweisen

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

Im Interesse der Eindeutigkeit ist hier das oben erwähnte Array von Filter-Arrays.

array($filter_a,$filter_b)

Dieser Wille gibt uns eine WHERE-Klausel, die ungefähr wie folgt aussieht

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

addFilter()Ermöglicht nur das Filtern eines einzelnen Felds nach einem einzelnen Wert und einem Typ. $typekann sein:

  1. "and" (Standard) - Fügt der WHERE-Klausel den Wert AND $ field = $ hinzu
  2. "oder" - fügt der WHERE-Klausel OR $ field = $ value hinzu

Weitere Details

Abdul
quelle
1
Das erklärt nichts.
Fabian Schmengler
Das ergibt keinen Sinn. Es beschreibt nicht den Unterschied dieser Methoden
Lindar
2
Ihre aktualisierte Antwort wird größtenteils von alanstorm.com/magento_collections kopiert . Bitte geben Sie mindestens Ihre Quellen an!
Fabian Schmengler