web-dev-qa-db-fra.com

Magento addFieldToFilter: deux champs, correspondant comme OU, pas ET

Je suis coincé là-dessus depuis quelques heures. Je l'ai fait fonctionner en piratant quelques lignes dans /lib/Varien/Data/Collection/Db.php, mais je préfère utiliser la bonne solution et laisser mon cœur intact.

Tout ce que je dois faire est d'obtenir une collection et de la filtrer par deux champs ou plus. Dire, customer_firstname et remote_ip. Voici mon (dysfonctionnel sans piratage 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: (exemple extrait 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 j'enveloppe cela avec un try/catch, il se déplace dans _getConditionSql () et donne cette erreur:

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

Quelqu'un at-il un code fonctionnel et fonctionnel pour le faire? J'utilise Magento 1.9 (Enterprise). Merci!

42
Gabriel H

J'ai une autre façon d'ajouter une condition or dans le champ:

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

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

$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 SQL WHERE quelque chose comme:

... 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 un autre ensemble de parenthèses pour une condition OR.

24
CJ Dennis

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

Ça me donne

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

Ce n'est peut-être pas le "chemin du magento" mais j'étais coincé 5 heures là-dessus.

J'espère que cela vous aidera

16
user654539

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 se traduit par 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)))
11
Michael Payne

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: http://docs.magentocommerce.com/Varien/Varien_Data/Varien_Data_Collection_Db.html#_getConditionSql

9
Anda B

Merci Anda, votre message a été d'une grande aide !! Cependant, la phrase OR n'a pas vraiment fonctionné pour moi et je recevais une erreur: getCollection () "argument non valide fourni pour foreach" .

Voici donc ce que j'ai fini (remarquez que l'attribut est spécifié 3 fois au lieu de 2 dans ce cas):

  $collection->addFieldToFilter('attribute', array(  
    array('attribute'=>'my_field1','eq'=>'my_value1'),            
    array('attribute'=>'my_field2','eq'=>'my_value2') ));

addFieldToFilter nécessite d'abord un champ puis une condition -> link.

7
jazkat

Il y a un peu de confusion ici, mais permettez-moi d'essayer de clarifier les choses:

Disons que vous vouliez sql qui ressemblait à quelque chose comme:

SELECT 
    `main_table`.*, 
    `main_table`.`email` AS `invitation_email`, 
    `main_table`.`group_id` AS `invitee_group_id` 
FROM 
    `enterprise_invitation` AS `main_table` 
WHERE (
    (status = 'new') 
    OR (customer_id = '1234')
)

Pour ce faire, votre collection doit être formatée comme suit:

$collection = Mage::getModel('enterprise_invitation/invitation')->getCollection();

$collection->addFieldToFilter(array('status', 'customer_id'), array(
array('status','eq'=>'new'),
array('customer_id', 'eq'=>'1234') ));

Maintenant, pour voir à quoi cela ressemble, vous pouvez toujours faire écho à la requête que cela crée en utilisant

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

Pour créer une simple condition OR pour la collecte, utilisez le format ci-dessous:

    $orders = Mage::getModel('sales/order')->getResourceCollection();
    $orders->addFieldToFilter(
      'status',
      array(
        'processing',
        'pending',
      )
    );

Cela produira du SQL comme ceci:

WHERE (((`status` = 'processing') OR (`status` = 'pending')))
2
XPS

C'est la vraie manière magento:

    $collection=Mage::getModel('sales/order')
                ->getCollection()
                ->addFieldToFilter(
                        array(
                            'customer_firstname',//attribute_1 with key 0
                            'remote_ip',//attribute_2 with key 1
                        ),
                        array(
                            array('eq'=>'gabe'),//condition for attribute_1 with key 0
                            array('eq'=>'127.0.0.1'),//condition for attribute_2
                                )
                            )
                        );
2
Gabriel
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()
        );
}

Résultat:

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

Source: http://alanstorm.com/magento_collections

2
De Nguyen