42 votes

Magento addFieldToFilter : Deux champs, correspondance par OU, pas par ET

Je suis bloqué sur ce sujet depuis quelques heures. J'ai réussi à le faire fonctionner en modifiant quelques lignes dans le fichier /lib/Varien/Data/Collection/Db.php mais je préfère utiliser la bonne solution et ne pas toucher à mon cœur.

Tout ce que je dois faire, c'est obtenir une collection et la filtrer par deux champs ou plus. Dites, customer_firstname y remote_ip . Voici mon (disfonctionnel sans hacking Db.php ) code :

$collection = Mage::getModel('sales/order')->getCollection()->
addAttributeToSelect("*")->
addFieldToFilter(array(array('remote_ip', array('eq'=>'127.0.0.1')),
array('customer_firstname', array('eq'=>'gabe'))), array('eq'=>array(1,2,3)));

Avec un stock Db.php J'ai essayé ceci : (échantillon tiré de http://magentoexpert.blogspot.com/2009/12/retrieve-products-with-specific.html )

$collection->addFieldToFilter(array(
    array('name'=>'orig_price','eq'=>'Widget A'),
    array('name'=>'orig_price','eq'=>'Widget B'),           
));

Mais cela me donne cette erreur :

Warning: Illegal offset type in isset or empty  in magento/lib/Varien/Data/Collection/Db.php on line 369

Si je l'entoure d'un try/catch, il passe ensuite à _getConditionSql() et donne cette erreur :

Warning: Invalid argument supplied for foreach()  in magento/lib/Varien/Data/Collection/Db.php on line 412

Quelqu'un a-t-il un code fonctionnel pour faire cela ? J'utilise Magento 1.9 (Enterprise). Merci.

72voto

Riyazkhan Points 319

J'ai un autre moyen d'ajouter un or sur le terrain :

->addFieldToFilter(
    array('title', 'content'),
    array(
        array('like'=>'%$titlesearchtext%'), 
        array('like'=>'%$contentsearchtext%')
    )
)

25voto

CJ Dennis Points 565

Les conditions OR peuvent être générées comme suit :

$collection->addFieldToFilter(
    array('field_1', 'field_2', 'field_3'), // columns
    array( // conditions
        array( // conditions for field_1
            array('in' => array('text_1', 'text_2', 'text_3')),
            array('like' => '%text')
        ),
        array('eq' => 'exact'), // condition for field 2
        array('in' => array('val_1', 'val_2')) // condition for field 3
    )
);

Cela va générer une condition WHERE SQL du type :

... WHERE (
         (field_1 IN ('text_1', 'text_2', 'text_3') OR field_1 LIKE '%text')
      OR (field_2 = 'exact')
      OR (field_3 IN ('val_1', 'val_2'))
    )

Chaque tableau imbriqué (<condition>) génère une autre série de parenthèses pour une condition OR.

16voto

user654539 Points 111

J'ai également essayé d'obtenir le field1 = 'a' OR field2 = 'b'

Votre code n'a pas fonctionné pour moi.

Voici ma solution

$results = Mage::getModel('xyz/abc')->getCollection();
$results->addFieldToSelect('name');
$results->addFieldToSelect('keywords');
$results->addOrder('name','ASC');
$results->setPageSize(5);

$results->getSelect()->where("keywords like '%foo%' or additional_keywords  like '%bar%'");

$results->load();

echo json_encode($results->toArray());

Cela me donne

SELECT name, keywords FROM abc WHERE keywords like '%foo%' OR additional_keywords like '%bar%' .

Ce n'est peut-être pas la "méthode Magento", mais j'ai été bloqué 5 heures là-dessus.

J'espère que cela vous aidera

12voto

Michael Payne Points 148

Voici ma solution dans Enterprise 1.11 (devrait fonctionner dans CE 1.6) :

    $collection->addFieldToFilter('max_item_count',
                    array(
                        array('gteq' => 10),
                        array('null' => true),
                    )
            )
            ->addFieldToFilter('max_item_price',
                    array(
                        array('gteq' => 9.99),
                        array('null' => true),
                    )
            )
            ->addFieldToFilter('max_item_weight',
                    array(
                        array('gteq' => 1.5),
                        array('null' => true),
                    )
            );

Ce qui donne ce SQL :

    SELECT `main_table`.*
    FROM `shipping_method_entity` AS `main_table`
    WHERE (((max_item_count >= 10) OR (max_item_count IS NULL)))
      AND (((max_item_price >= 9.99) OR (max_item_price IS NULL)))
      AND (((max_item_weight >= 1.5) OR (max_item_weight IS NULL)))

9voto

Anda B Points 749

Pour filtrer par plusieurs attributs, utilisez quelque chose comme :

//for AND
    $collection = Mage::getModel('sales/order')->getCollection()
    ->addAttributeToSelect('*')
    ->addFieldToFilter('my_field1', 'my_value1')
    ->addFieldToFilter('my_field2', 'my_value2');

    echo $collection->getSelect()->__toString();

//for OR - please note 'attribute' is the key name and must remain the same, only replace //the value (my_field1, my_field2) with your attribute name

    $collection = Mage::getModel('sales/order')->getCollection()
        ->addAttributeToSelect('*')
        ->addFieldToFilter(
            array(
                array('attribute'=>'my_field1','eq'=>'my_value1'),
                array('attribute'=>'my_field2', 'eq'=>'my_value2')
            )
        );

Pour plus d'informations, consultez le site : http://docs.magentocommerce.com/Varien/Varien_Data/Varien_Data_Collection_Db.html#_getConditionSql

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X