Отфильтровать коллекцию товаров по неплоским атрибутам

14

Я делаю следующее:

$productCollection = Mage::getModel('catalog/product')
    ->getCollection();

$productCollection
    ->addAttributeToFilter('my_attribute', 1);

my_attribute отсутствует в плоских таблицах, но плоские таблицы включены.

Я продолжаю получать полную коллекцию.

Причина, кажется, в \Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSelect:

$columns = $this->getEntity()->getAttributeForSelect($attributeCode);

Нет $this->getEntity()- это экземпляр, Mage_Catalog_Model_Resource_Product_Flatкоторый выбирает плоские поля - и если ничего не найдено, просто возвращает ноль.

Как правильно добавить неплоский атрибут в фильтр коллекции?

В моем случае не имеет смысла добавлять атрибут к плоской таблице.

Alex
источник
Привет, сэр, вы в порядке, чтобы решить путаницу? WAT это значит non-flat attribute? Спасибо. И не делайте magento Запутывающим. Это уже сбивает с толку
Pratik
Я говорю об атрибутах, которых нет в плоском индексе. Это те, для которых «Используется в списке товаров» установлено на «Нет».
Алекс

Ответы:

18

Вы можете присоединиться к нужному столу самостоятельно.

$productCollection = Mage::getModel('catalog/product')
->getCollection();

$table = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'my_attribute')->getBackend()->getTable();
$attributeId = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'my_attribute')->getAttributeId();

$productCollection->getSelect()->join(array('attributeTable' => $table), 'e.entity_id = attributeTable.entity_id', array('my_attribute' => 'attributeTable.value'))
                            ->where("attributeTable.attribute_id = ?", $attributeId)
                            ->where("attributeTable.value = ?", 1);

Вы можете присоединиться к store_id тоже.

Матиас Цейс
источник
Думаю, у меня все равно будет проблема, что я не получаю продукцию всех магазинов. (всякий раз, когда я изначально не видел эту проблему в своем вопросе). Похоже, я хочу полностью отключить плоские индексы.
Алекс
Если вам нужны все продукты, то плоские столы не станут вашими друзьями, да.
Матиас Цейс
Я думаю, что вы можете изменить свой вопрос или принять мой ответ (который работает для исходного вопроса), а затем.
Матиас Зейс
потрясающе .. концепция
Амит Бера
15

Хак (CE 1.6.2.0+) состоит в том, чтобы передать условие как массив и верить этому или нет, это работает как задумано:

$collection->addFieldToFilter(array(array('attribute' => 'my_attribute', 'eq' => 1)));
ColinM
источник
Любая подсказка, почему это работает?
Алекс
3
Это работает, потому что для eav collection addFieldToFilerявляется оберткой для addAttributeToFilterи имеет возможность передать атрибут в виде массива:if (is_array($attribute)) { $sqlArr = array(); foreach ($attribute as $condition) { $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType); } $conditionSql = '('.implode(') OR (', $sqlArr).')'; }
Marius
@ Мариус, это значит, что это не хак? : P Могу ли я чувствовать себя хорошо, используя его?
Эрфан
3
@Erfan. это не хак. это особенность.
Мариус
Сладкий. Странно, что реализация таблицы продуктов (eav / flat) не абстрагируется от таких простых вещей, как фильтрация коллекции. Означает ли это, что мне всегда нужно использовать addFieldToFilter вместо addAttributeToFilter в моем коде, потому что я не буду знать, использует ли он eav или flat? Какой смысл в addAttributeToFilter?
Эрфан
6

Причина ответ ColinM работает из - за код в app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php«s addAttributeToFilterметода. Если вы используете этот формат массива, он не вызывает addAttributeToSelect. В плоском режиме addAttributeToSelectмолча происходит сбой, если атрибут не находится в плоской таблице.

(ниже приведена перефразировка моего ответа на /programming/6271284/can-i-add-other-attributes-to-magentos-flat-product-catalog-table/17021620 - я не уверен, что этикета для этого, но знаю, я бы нашел это полезным)

Я хотел «чистое» решение для выбора и фильтрации коллекций в плоском режиме по неплоским атрибутам, которое:

  • не требует, чтобы у атрибута были определенные настройки в админке (он может быть добавлен пользователем или скрыт в интерфейсе)
  • работает как в плоском, так и в неплоском режиме

Я использовал связанную коллекцию продуктов, но это относится к любой коллекции EAV.

Неверный код:

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->addAttributeToSelect( 'my_custom_attribute' )
    ->addAttributeToFilter( 'my_custom_attribute', 3 )
;

В плоском режиме приведенный выше код молча не может выбрать или отфильтровать атрибут, если он не находится в плоской таблице.

Добавление в избранное:

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->joinAttribute( 'my_custom_attribute', 'catalog_product/my_custom_attribute', 'entity_id', null, 'left' )
    ->addAttributeToSelect( 'my_custom_attribute' )
;

joinAttributeМетод добавляет присоединиться к запросу для атрибута конкретного запрошенного. Это все еще работает, когда атрибут уже находится в плоской таблице, но будет немного менее эффективным, чем просто использование плоской таблицы.

Я использовал leftсоединение, чтобы убедиться, что оно выбирает продукты, если они my_custom_attributeне установлены. Измените это, innerесли вас интересуют только те строки, где они my_custom_attributeустановлены.

Добавление к фильтру (согласно ColinM выше):

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->addAttributeToFilter( array( array( 'attribute' => 'my_custom_attribute', 'eq' => 3 ) ) )
;

Приведенный выше код добавит его в список, а также подчиняется вашему фильтру.

(протестировано в CE 1.6.2.0)

johnorourke
источник
4

В Mage_Rssмодуле они использовали hacky-метод для отключения плоских таблиц. Они используют тот факт, что плоские таблицы всегда отключены в хранилище администратора и поэтому просто эмулируют хранилище администратора.

class Mage_Rss_Helper_Data {

[...]

/**
 * Disable using of flat catalog and/or product model to prevent limiting results to single store. Probably won't
 * work inside a controller.
 *
 * @return null
 */
public function disableFlat()
{
    /* @var $flatHelper Mage_Catalog_Helper_Product_Flat */
    $flatHelper = Mage::helper('catalog/product_flat');
    if ($flatHelper->isEnabled()) {
        /* @var $emulationModel Mage_Core_Model_App_Emulation */
        $emulationModel = Mage::getModel('core/app_emulation');
        // Emulate admin environment to disable using flat model - otherwise we won't get global stats
        // for all stores
        $emulationModel->startEnvironmentEmulation(0, Mage_Core_Model_App_Area::AREA_ADMINHTML);
    }
}

После запуска эмуляции вы должны сбросить его emulationModel->stopEnvironmentEmulation()

Alex
источник
Где был этот ответ 3 дня назад? ; _;
sg3s
Прямо здесь? С 20 марта
Алекс
1

когда вы создаете атрибут, он должен быть на глобальном уровне и быть фильтруемым. Таким образом, он будет использоваться в многоуровневой навигации. Также это потребует, чтобы атрибут был выпадающим или множественным выбором. Я бы лично посоветовал не менять основные файлы в соответствии с вашими потребностями в этом случае.

Сандер Мангель
источник
Я не хочу атрибут в фильтре внешнего интерфейса - я просто хочу сделать фильтрацию коллекции для внутреннего использования.
Алекс