【问题标题】:Magento filter product collection by multiple categoriesMagento 按多个类别过滤产品集合
【发布时间】:2012-02-27 16:00:21
【问题描述】:

有没有一种简单的方法可以按多个类别过滤产品集合?要获取任何列出的类别中的所有项目? addCategoryFilter 似乎不允许使用数组。

是单独获取每个感兴趣类别的集合然后合并它们的唯一方法吗?

我知道以前可以使用类似的东西

addAttributeToFilter('category_ids',array('finset'=>array('1','2')))

或类似的,但自 1.4 以来不再可能。

注意:我使用的是 1.6,如果有任何用处,我使用的是这样的:

$product = Mage::getModel('catalog/product');
$_productCollection = $product->getCollection()
  ->addAttributeToSelect('*')
  ->addAttributeToFilter('status',1)
  ->addStoreFilter();

【问题讨论】:

  • 不幸的是,没有任何简单的方法可以做到这一点。

标签: magento collections


【解决方案1】:

这是一种不需要修改核心的方法。 它取自this post,并添加了“组”子句来处理重复的产品记录。

$categories = array(7,45,233);

        $collection = Mage::getModel('catalog/product')->getCollection()
            ->addAttributeToSelect('*')
            ->joinField('category_id',
                'catalog/category_product',
                'category_id',
                'product_id=entity_id',
                null,
                'left')
            ->addAttributeToFilter('category_id', array('in' => $categories));
        $collection->getSelect()->group('e.entity_id');

【讨论】:

  • 连接有效,但过滤无效。 WHERE 子句中没有添加任何内容。
  • 我也尝试过这个解决方案并遇到了与@ButtleButkus 相同的问题......我看到连接已添加到生成的查询中,但没有 WHERE 条件。我们正在使用 Magento EE 1.12(又名 CE 1.7)。
  • 我一直在单步执行代码,当 Magento 的平面目录关闭时,此解决方案将起作用。启用平面目录时,会发生以下情况。 addAttributeToFilter 方法识别出 category_id 字段不在 SELECT 列表中,并调用 addAttributeToSelect 进行添加。然后 addAttributeToSelect 方法失败,因为 category_id 不是产品属性,并且没有过滤器添加到集合中。
  • 感谢您解释 group 子句,我正在寻找类似的解决方案,但不明白它是如何工作的。不,我愿意!
  • @JimOHalloran 我的经历完全相反。仅在打开平面目录时才有效。
【解决方案2】:

Magento现在的工作方式,就是获取Store,在store上,你可以像$oStoreCollection->addCategoryFilter(array('1','2'));

我发现了一个可能对您有所帮助的解决方案,位于:

http://www.magentocommerce.com/boards/&/viewthread/201114/#t329230

他们使用的代码如下所示: 覆盖Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection,添加如下方法:

public function addCategoriesFilter($categories)
    {
        $this->_productLimitationFilters['category_ids'] = $categories;

        if ($this->getStoreId() == Mage_Core_Model_App::ADMIN_STORE_ID) {
            $this->_applyZeroStoreProductLimitations();
        } else {
            $this->_applyProductLimitations();
        }

        return $this;
    }

    protected function _applyProductLimitations()
    {
        $this->_prepareProductLimitationFilters();
        $this->_productLimitationJoinWebsite();
        $this->_productLimitationJoinPrice();
        $filters = $this->_productLimitationFilters;

        // Addition: support for filtering multiple categories.
        if (!isset($filters['category_id']) && !isset($filters['category_ids']) && !isset($filters['visibility'])) {
            return $this;
        }

        $conditions = array(
            'cat_index.product_id=e.entity_id',
            $this->getConnection()->quoteInto('cat_index.store_id=?', $filters['store_id'])
        );
        if (isset($filters['visibility']) && !isset($filters['store_table'])) {
            $conditions[] = $this->getConnection()
                ->quoteInto('cat_index.visibility IN(?)', $filters['visibility']);
        }

        // Addition: support for filtering multiple categories.
        if (!isset($filters['category_ids'])) {
             $conditions[] = $this->getConnection()
                ->quoteInto('cat_index.category_id=?', $filters['category_id']);
            if (isset($filters['category_is_anchor'])) {
                $conditions[] = $this->getConnection()
                    ->quoteInto('cat_index.is_parent=?', $filters['category_is_anchor']);
            }
        } else {
            $conditions[] = $this->getConnection()->quoteInto('cat_index.category_id IN(' . implode(',', $filters['category_ids']) . ')', "");
        }

        $joinCond = join(' AND ', $conditions);
        $fromPart = $this->getSelect()->getPart(Zend_Db_Select::FROM);
        if (isset($fromPart['cat_index'])) {
            $fromPart['cat_index']['joinCondition'] = $joinCond;
            $this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
        }
        else {
            $this->getSelect()->join(
                array('cat_index' => $this->getTable('catalog/category_product_index')),
                $joinCond,
                array('cat_index_position' => 'position')
            );
        }

        $this->_productLimitationJoinStore();

        Mage::dispatchEvent('catalog_product_collection_apply_limitations_after', array(
            'collection'    => $this
        ));

        return $this;
    }

    protected function _applyZeroStoreProductLimitations()
    {
        $filters = $this->_productLimitationFilters;

        // Addition: supprot for filtering multiple categories.
        $categoryCondition = null;
        if (!isset($filters['category_ids'])) {
            $categoryCondition = $this->getConnection()->quoteInto('cat_pro.category_id=?', $filters['category_id']);
        } else {
            $categoryCondition = $this->getConnection()->quoteInto('cat_pro.category_id IN(' . implode(',', $filters['category_ids']) . ')', "");
        }

        $conditions = array(
            'cat_pro.product_id=e.entity_id',
            $categoryCondition
        );
        $joinCond = join(' AND ', $conditions);

        $fromPart = $this->getSelect()->getPart(Zend_Db_Select::FROM);
        if (isset($fromPart['cat_pro'])) {
            $fromPart['cat_pro']['joinCondition'] = $joinCond;
            $this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
        }
        else {
            $this->getSelect()->join(
                array('cat_pro' => $this->getTable('catalog/category_product')),
                $joinCond,
                array('cat_index_position' => 'position')
            );
        }

        return $this;
    }

然后它被这样调用:

$collection = Mage::getModel('catalog/product')->getCollection()
                        ->addAttributeToSelect('*')
                        ->distinct(true) // THIS IS WHAT YOU NEED TO ADD
                        ->addCategoriesFilter($category->getAllChildren(true)); // Make sure you don't forget to retrieve your category here.

HTH

【讨论】:

  • 谢谢。我都添加了,现在得到一个未知的方法错误。由于某种原因,它无法识别添加的内容,有什么想法吗?
  • Fatal error: Call to undefined method Mage_Catalog_Model_Resource_Product_Collection::addCategoriesFilter()....
  • Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php 似乎根本没有被加载
  • 你真的扩展了 Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection?
  • 我最终通过过滤attribute_set_id 找到了替代解决方案。我会将此标记为正确,因为它似乎对论坛中的某些人也有效。
【解决方案3】:

如果您想过滤多个类别,使用 AND(因此产品必须在类别 A、B 和 C 中才能显示,您需要有多个连接:

$products = Mage::getModel('catalog/product')->getCollection()
    ->joinField('category_id_1', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
    ->joinField('category_id_2', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
    ->addAttributeToFilter('category_id_1', array('eq' => 358))
    ->addAttributeToFilter('category_id_2', array('eq' => 252))
// etc...
;

【讨论】:

    【解决方案4】:

    我设法用以下代码解决了这个问题(经过多次试验和错误):

    $collection = Mage::getModel('catalog/product')->getCollection();
    $collection->addAttributeToFilter('status', 1);
    $collection->addAttributeToSelect(array('name','sku','price','small_image'));
    
    // Filter by multiple categories
    $collection->joinField('category_id','catalog/category_product','category_id','product_id=entity_id',null,'left');
    $data_cats = $this->getRequest()->getParam('categories');
    // Or $data_cats = array(85,86,87,88);
    
          $filter_cats = array();
          foreach ($data_cats as $value_cats) {
             $filter_cats[] = array(
             'attribute' => 'category_id',
             'finset'    => $value_cats
          );
    }
    
    $collection->addAttributeToFilter($filter_cats);
    

    希望这对某人有所帮助;)

    【讨论】:

      【解决方案5】:
      • Magento 1.8.0.0;
      • 在管理员中启用了平面目录;
      • 确保您已经缓存了要放置它的块;
      • 请勿在付费主题中添加此内容..
      • 这里硬编码的内部连接复制了这个:

        $collection->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());

        没有 'cat_index.category_id=2'

      $category = Mage::getModel('catalog/category')->load(100);
      $allChildsIds = $category->getAllChildren($category);
      
      $visibility = Mage::getModel('catalog/product_visibility');
      
      $collection = Mage::getResourceModel('catalog/product_collection');
      $collection = $this->_addProductAttributesAndPrices($collection)
        ->addStoreFilter()
        ->setFlag('do_not_use_category_id', true)
        ->setFlag('disable_root_category_filter', true)
        ->addAttributeToSort('created_at', 'desc');
      
      $whereCategoryCondition = $collection->getConnection()
        ->quoteInto('cat_index.category_id IN(?) ', $allChildsIds);
      $collection->getSelect()->where($whereCategoryCondition);
      
      $conditions = array();
      $conditions[] = "cat_index.product_id = e.entity_id";
      $conditions[] = $collection->getConnection()
        ->quoteInto('cat_index.store_id = ? ', Mage::app()->getStore()->getStoreId());
      $conditions[] = $collection->getConnection()
        ->quoteInto('cat_index.visibility IN(?) ', $visibility->getVisibleInCatalogIds());
      
      $collection->getSelect()->join(
        array('cat_index' => $collection->getTable('catalog/category_product_index')),
        join(' AND ', $conditions),
        array()
      );
      
      $collection
        ->setPageSize(3)
        ->setCurPage(1);
      
      $collection->load();
      

      【讨论】:

        【解决方案6】:

        使用多个类别 ID 过滤产品集合

        $all_categories = array('3','13','113');   
        $productCollection = Mage::getModel('catalog/product')->getCollection();
        $productCollection->joinField('category_id', 'catalog/category_product', 'category_id', 
                            'product_id = entity_id', null, 'left')
                          ->addAttributeToSelect('*')
                          ->addAttributeToFilter('type_id', array('eq' => 'simple'))
                          ->addAttributeToFilter('category_id', array($all_categories));
        foreach($productCollection as $product)
        {
            echo $product->getId() .$product->getName() . "<br/>";
        }
        

        您可以删除产品类型的条件,即 type_id 或根据需要进行修改。

        【讨论】:

          【解决方案7】:

          参考:https://www.fmeextensions.com/blog/get-product-collection-by-category-id-magento-2/

          $ids = [1,2,3,4,5,6,7];
          $collectionFactory = $objectManager->get('\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory')->create();
          $products = $collectionFactory->addAttributeToSelect('*')
                                      ->addCategoriesFilter(['in' => $ids]);
          
          foreach ($products as $product) {
              echo $product->getId() . "<br />";
              echo $product->getName() . "<br />";
              echo $product->getProductUrl() . "<br />"; 
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-02
            • 1970-01-01
            • 2014-09-19
            • 1970-01-01
            相关资源
            最近更新 更多