Как выбрать товары (или другие объекты), отвечающие дизъюнктивному условию?

[16 июля 2019 г.]    Российская сборка Magento 2.52.2
Magento 2: модули и услуги
magereport.com: составление перечня необходимых для установки заплаток SUPEE
#1 Хыиуду
  • Группа: Пользователь
  • Сообщений: 56
  • Регистрация: 05.07.2012

18.07.2012 10:29

Насколько я понял,
Mage :: getModel ( 'catalog/product' )
-> getCollection ()
-> addFieldToFilter ( 'vendor' ,array( 'in' => array('Sony', 'Fuji') ))
-> addFieldToFilter ( 'price' ,array( 'qteq' => '15000' )) 

дает выборку where vendor in ('Sony','Fuji') and price>=15000
Mage :: getModel ( 'catalog/product' )
-> getCollection ()
-> addFieldToFilter ( 'vendor' , array( array( 'eq' => 'Fuji' ), array ('like' => '%son%')))

дает where vendor='Fuji' or vendor like '%son%'
Как можно сделать выборку where vendor = 'Fuji' or price>15000?
В смысле, сложность в том, чтобы объединить с помощью or два фильтра для разных атрибутов товара

#2 Дмитрий Федюк
  • Администратор
  • Иконка
  • Группа: Администратор
  • Сообщений: 8995
  • Регистрация: 20.02.2010

18.07.2012 10:41

Надо использовать оператор 'or'.

#3 Хыиуду
  • Группа: Пользователь
  • Сообщений: 56
  • Регистрация: 05.07.2012

18.07.2012 10:42

И как будет выглядеть синтаксис в этом случае?

#4 Дмитрий Федюк
  • Администратор
  • Иконка
  • Группа: Администратор
  • Сообщений: 8995
  • Регистрация: 20.02.2010

18.07.2012 10:47

<?php

class Df_PromoGift_Model_Mysql4_Rule_Collection extends Mage_SalesRule_Model_Mysql4_Rule_Collection {
    
    protected function _beforeLoad() {
    
        /** @var Varien_Db_Select $select */
        $select = $this->getSelect ();
    
        df_assert ($select instanceof Varien_Db_Select);
    
    
        /** @var Zend_Db_Adapter_Abstract $adapter */
        $adapter = $select->getAdapter();
    
        df_assert ($adapter instanceof Zend_Db_Adapter_Abstract);
    
    
        /**
         * Отбраковываем отключенные правила
         */
        $this
            ->addFieldToFilter (
                $adapter->quoteIdentifier (Df_SalesRule_Const::DB__SALESRULE__IS_ACTIVE)
                ,
                array ('eq' => 1)
            )
        ;
    
    
    
        /**
         * Нас интересуют только правила типа «Percent of product price discount»,
         * потому что именно такими правилами определяются промо-подарки
         */
        $this
            ->addFieldToFilter (
                $adapter->quoteIdentifier (Df_SalesRule_Const::DB__SALESRULE__SIMPLE_ACTION)
                ,
                array ('eq' => Df_SalesRule_Const::BY_PERCENT_ACTION)
            )
        ;
    
    
    
        /**
         * Выбираем правила, дающую 100-процентную скидку
         * (другими словами, предоставляющие товары в поларок)
         */
        $this
            ->addFieldToFilter (
                $adapter->quoteIdentifier (Df_SalesRule_Const::DB__SALESRULE__DISCOUNT_AMOUNT)
                ,
                array ('eq' => 100)
            )
        ;
    
    
    
        /**
         * Отбраковываем правила с истёкшим сроком действия.
         *
         * Обратите внимание, что правила, недействующие сейчас, но запланированные на будущее,
         * мы не отбраковываем, потому что они могут стать действующими
         * в период между данным процессом (индексацией) и покупкой.
         */
        $this
            ->addFieldToFilter (
                $adapter->quoteIdentifier (Df_SalesRule_Const::DB__SALESRULE__TO_DATE)
                ,
                array (
                     'or' =>
                        array (
                            array (
                                'from'=> Zend_Date::now ()
                                ,
                                'datetime' => true
                            )
                            ,
                            array ('is' => new Zend_Db_Expr (Df_Zf_Const::NULL))
                        )
                )
            )
        ;
        
        parent::_beforeLoad();
    
    }
}


#5 Дмитрий Федюк
  • Администратор
  • Иконка
  • Группа: Администратор
  • Сообщений: 8995
  • Регистрация: 20.02.2010

18.07.2012 11:28

В моём примере дизъюнкция применена к одному и тому же полю.
Дизъюнкцию из нескольких полей коллекции можно сделать посредством перекрытия метода initSelect и применения там стандартных предикатов Zend_Db_Select типа orWhere.

#6 Хыиуду
  • Группа: Пользователь
  • Сообщений: 56
  • Регистрация: 05.07.2012

18.07.2012 13:05

Ничего не понял. Однако спасибо за направляющий пинок - хотя бы понял, в какую сторону копать код.
Ответ оказался довольно простым. Выборка товаров с объединением с помощью or выглядит так:
addFieldToFilter ( array( array( 'attribute'=>'vendor', 'eq' => 'Fuji' ), array ('attribute'=>'price', 'gteq'=>15000)))

#7 Хыиуду
  • Группа: Пользователь
  • Сообщений: 56
  • Регистрация: 05.07.2012

26.07.2012 10:18

Было замечено, что по умолчанию при создании SQL запроса используется INNER JOIN, что начисто убивает весь смысл дизъюнкции. Поэтому для того, чтобы действительно получить все товары, у которых либо производитель Fuji, либо цена не меньше 15000, надо писать так:
addAttributeToFilter (
array( array( 'attribute'=>'vendor', 'eq' => 'Fuji' ), array ('attribute'=>'price', 'gteq'=>15000)),
NULL,
'left'
)

Поделиться темой: