Produktkollektion nach mehreren Kategorien filtern?


7

Ich habe diesen Codeausschnitt, der die zuletzt hinzugefügten Produkte enthält:

$_productCollection = Mage::getResourceModel('catalog/product_collection')
                ->addAttributeToSelect('*')
                ->addAttributeToFilter($preorderAttribute, array(
                    'eq' => Mage::getResourceModel('catalog/product')
                        ->getAttribute($preorderAttribute)
                        ->getSource()
                        ->getOptionId($preorderValue)
                ))
                ->setVisibility(array(2,3,4))
                ->setOrder('created_at', 'desc')
                ->setPage(1, 12);

Ich möchte dies weiter nach Kategorien filtern, z. B. Kategorien mit den IDs 3 und 4. In der Sammlung werden nur Produkte aus den Kategorien 3 und 4 ausgewählt. Wie kann ich das erreichen?

Ich habe versucht, addAttributeToFilternach Kategorie-IDs zu filtern, aber es scheint verschiedene Möglichkeiten zu geben, und es funktioniert weder nicht noch gibt es einen schwerwiegenden Fehler:

Aufruf einer Nichtmitgliedsfunktion getBackend ()

.... jetzt bin ich ratlos.

Jede Hilfe wäre dankbar.

Antworten:


22

Das folgende Codebeispiel zeigt für mich nur bestimmte Produkte der Kategorien 2 (7 und 8). Hoffe es wird für dich funktionieren:

$productCollection = Mage::getModel('catalog/product')
    ->getCollection()
    ->joinField(
        'category_id', 'catalog/category_product', 'category_id', 
        'product_id = entity_id', null, 'left'
    )
    ->addAttributeToSelect('*')
    ->addAttributeToFilter('category_id', array(
            array('finset' => array('7', '8', )),
    ))
    ->addAttributeToSort('created_at', 'desc');

foreach($productCollection as $product){
    echo $product->getId() . "<br/>\n";
};

3
+1 Perfekt. Übrigens können wir auch 'in' anstelle von 'finset' verwenden. Es sieht also wie folgt aus: $ _productCollection-> addAttributeToFilter ('category_id', Array ('in' => Array ('106', '107', '108', '110'))
Haijerome

2
Dieser Code funktioniert nicht, wenn zwei oder mehr Kategorien gefiltert werden müssen und ein Produkt mehreren dieser Kategorien zugeordnet ist. Gibt den Fehler als zurück Item (Mage_Catalog_Model_Product) with the same id "xx" already exist.
MTM

1
Sie können den Fall behandeln, dass es Produkte in mehreren Kategorien gibt, indem Sie sie nach Produkten gruppieren. $productCollection->getSelect()->group('e.entity_id');Denken Sie jedoch daran, dass einige Funktionen wie die Anzahl der Sammlungen durch Hinzufügen einer Gruppierung deaktiviert werden.
Robert Egginton

Der obige Code funktioniert auch nicht mit älteren Versionen von Magento, bei denen Leerzeichen in der Bindevariablen des Joins nicht entfernt wurden. Daher muss die Bedingung erfüllt sein 'product_id=entity_id'- beachten Sie den Mangel an Leerzeichen.
Robert Egginton

Keine Notwendigkeit zu gruppieren, wenn Sie "in" verwenden, wie @Haijerom sagte Bearbeiten: Eigentlich brauchen Sie immer noch, da Sie mehrmals das gleiche Produkt haben können
Erdal G.

4

Eine andere Alternative:

Im Beispiel $categoryIdshandelt es sich um ein Array von Kategorie-IDs. (Ich benutze normalerweise, $collection->getFlag('category_ids')aber für dieses Beispiel geändert, siehe Erklärung weiter unten)

$currentStoreIdwird mit allen Mitteln gefüllt, die die aktuelle Geschäfts-ID erhalten können. (in meinem Beobachterereignis benutze ich $collection->getFlag('store_id'))

$conditions = array(
    'cat_index.product_id=e.entity_id',
    $collection->getConnection()->quoteInto('cat_index.category_id IN (' . $categoryIds . ')', "")
);
if (!Mage::app()->getStore()->isAdmin()) {
    $conditions[] = $collection->getConnection()->quoteInto('cat_index.store_id=?', $currentStoreId );
}
$joinCond = join(' AND ', $conditions);
$fromPart = $collection->getSelect()->getPart(Zend_Db_Select::FROM);

if (isset($fromPart['cat_index'])) {
    $fromPart['cat_index']['joinCondition'] = $joinCond;
    $collection->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
} else {
    $collection->getSelect()->join(
            array('cat_index' => $collection->getTable('catalog/category_product_index')), $joinCond, array('cat_index_category_id' => 'category_id')
    );
}

Ich verwende den obigen Code in einem Beobachter, um mit mehreren Kategorien zu filtern, NACHDEM der eingebaute Aufruf Mage_Catalog_Model_Resource_Product_Collection::_applyProductLimitations()seine Sache tut, da er ein Ereignis namens sendet'catalog_product_collection_apply_limitations_after'

Die _applyProductLimitationsMethode wendet im Wesentlichen die Filter an, die durch den Aufruf von festgelegt wurden addCategoryFilter.

Durch die Verwendung eines Flags in der $collectionist es einfach, die mehreren Kategorie-IDs für den Beobachter zu speichern.

Wenn ich also nach mehreren Kategorien filtern muss, setze ich irgendwann ein Flag für die Sammlung

Ein Beispiel wäre das Umschreiben Mage_Catalog_Model_Category::getProductCollection()

public function getProductCollection() {
    $collection = parent::getProductCollection();
    $collection->setFlag('category_ids',array(19,243,42,54)); //the array of values can be from somehwre, this hard coded array serves purely as an example
    return $collection;    
}

Wenn Magento das Ereignis auslöst, ersetzt mein Code den Kategoriefilter durch meinen Mehrfachfilter :)

Dies ist im Wesentlichen die Vorgehensweise meines Moduls " Dynamische Kategorieprodukte" für seine Filter mit mehreren Kategorien.

Ref Der Kerncode von addCategoryFilter:

/**
 * Specify category filter for product collection
 *
 * @param Mage_Catalog_Model_Category $category
 * @return Mage_Catalog_Model_Resource_Product_Collection
 */
public function addCategoryFilter(Mage_Catalog_Model_Category $category)
{
    $this->_productLimitationFilters['category_id'] = $category->getId();
    if ($category->getIsAnchor()) {
        unset($this->_productLimitationFilters['category_is_anchor']);
    } else {
        $this->_productLimitationFilters['category_is_anchor'] = 1;
    }

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

    return $this;
}

2

Ich habe mit den Techniken gearbeitet, die sowohl in den Antworten von @monojit banik als auch in den Antworten von @ ProxiBlue angeboten wurden, und habe den Fehler "Item (Mage_Catalog_Model_Product) mit der gleichen ID" xx "bereits vorhanden" erhalten, der in @ MTMs Kommentar mit beiden identifiziert wurde.

Um den Fehler zu vermeiden, der außerhalb der Sammlungslast in der geschichteten Navigation auftritt, habe ich verschiedene Methoden ausprobiert, um einen bestimmten Satz von Produkten in einem einzigen Durchgang zu erhalten, aber nichts, was ich mir ausgedacht habe, hat funktioniert.

Letztendlich (BEARBEITEN: basierend auf diesem Blog-Beitrag, https://www.muddyweb.com/general-ramblings/filtering-a-magento-product-collection-by-multiple-categories/ ) habe ich zwei separate Sammlungsladungen verwendet um den eindeutigen Produktsatz zu erhalten und den Fehler wie folgt zu vermeiden. Die Verwendung von zwei Durchgängen kann zu Leistungseinbußen führen, aber es war nichts zu bemerken.

    $category_ids = [helper method to get desired category id array];

    //Need distinct products even if products are assigned to more than one of 
    //  the selected categories.
    $id_collection = Mage::getModel('catalog/product')->getCollection()
        ->addAttributeToSelect('id')
        ->addAttributeToFilter('status', 1)
        ->addAttributeToFilter('visibility', 4)
        ->addStoreFilter();

    $conditions = array();
    foreach ($category_ids as $categoryId) {
        if (is_numeric($categoryId)) {
            $conditions[] = "{{table}}.category_id = $categoryId";
        }
    }

    $id_collection->distinct(true)
        ->joinField('category_id', 'catalog/category_product', null,
                    'product_id = entity_id', implode(" OR ", $conditions), 'inner');

    $ids = $id_collection->getAllIds();

    //Now, use the product ids array obtained above to get the final product collection.
    /** @var Mage_Catalog_Model_Resource_Product_Collection $collection */
    $collection = Mage::getResourceModel('catalog/product_collection')
        ->setStoreId($this->getStoreId())
        ->addAttributeToSelect('*')
        ->addAttributeToFilter('entity_id', array('in' => $ids) )
    ;

Klappt wunderbar. Gute Methode
Erdal G.

0

Ich habe es geschafft, dies (nach langem Ausprobieren) mit dem folgenden Code zu beheben:

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

Hoffe das hilft jemandem;)



-1

Fehler: 'ungültiges Attribut entity_id' Leerzeichen zwischen product_id = entity_id !! Die gute Syntax lautet:

 ->joinField(
    'category_id', 'catalog/category_product', 'category_id', 
    'product_id=entity_id', null, 'left'
)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.