Best Practice zum Verbinden von Produktattributen


11

Ich habe eine benutzerdefinierte Tabelle mit einer Produktreferenz product_id. Jetzt möchte ich Produktinformationen (SKU, Name) in meinem Backend-Raster anzeigen , bin mir aber nicht sicher, wie dies am besten funktioniert.

Meine beste Vermutung für SKUist wie folgt:

$collection->join(
    'catalog/product',
    'product_id=`catalog/product`.entity_id',
    array('product_sku' => 'sku')
)

(Code aus der _prepareCollection() Methode in meiner Gitterblockklasse)

Aber was ist mit dem Produktnamen? Es kann in catalog_product_entity_varchar gefunden werden. Mein Verständnis ist, dass Sie es ziemlich einfach bekommen können, wenn Ihr eigenes Ressourcenmodell und Ihre eigene Sammlung darauf basieren, Mage_Eav_Model_Entity_Collection_Abstractweil Sie dann Methoden wie verwenden können joinAttribute. Aber mein Modell basiert auf einer einfachen Tabelle und erstreckt sich von Mage_Core_Model_Resource_Db_Collection_Abstractund es gibt keine joinAttributeMethode zur Verfügung.

Was ist in diesem Fall der beste Weg, um den Produktnamen zu erhalten?

Danke für deine Zeit und Hilfe :-)

Update: Genauer gesagt habe ich über mein Ressourcenmodell und meine Sammlung gesprochen. Es passt zu einem einfachen flachen Tisch mit nur wenigen Attributen wie

entity_id    product_id    created_at    user_id

Meine Absicht ist es, im Backend zu rasteren, wo ich einige Statistiken zeige:

ProductSku    Count(ProductSku)    MAX(created_at)

Soweit ich weiß, ist der beste Ansatz, dies zu tun, die Rasterblockklasse, und die Methode ist zu gehen _prepareCollection().

Meine Methode sieht so aus:

protected function _prepareCollection()
{
    // Get and set our collection for the grid
    $collection = Mage::getResourceModel($this->_getCollectionClass());
    $collection
        ->join(
            'catalog/product',
            'product_id=`catalog/product`.entity_id',
            array('product_sku' => 'sku')
            )
        ->addExpressionFieldToSelect('product_count', 'COUNT({{product_id}})', 'product_id')
        ->addExpressionFieldToSelect('newest', 'MAX({{created_at}})', array('created_at'=>'main_table.created_at'))
        ->getSelect()->group('product_id');
    $this->setCollection($collection);

    return parent::_prepareCollection();
}

Dies funktioniert gut für die SKU (die ich in der _prepareColums()Methode als product_sku bezeichne. Aber was joinmuss ich hier einfügen, um den Namen (und z. B. den Hersteller) zu erhalten?

Mache ich etwas falsch, weil ich es nicht benutzen kann joinLeft()?

Antworten:


13

Fügen Sie in Ihrer Sammlungsklasse ( /Some/Module/Model/Mysql4 (or Resource)/YourModel/Collection.php) diese Methode hinzu:

public function addProductData()
    {
        /** add particular attribute code to this array */
        $productAttributes = array('name', 'price', 'url_key');
        foreach ($productAttributes as $attributeCode) {
            $alias     = $attributeCode . '_table';
            $attribute = Mage::getSingleton('eav/config')
                ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeCode);

            /** Adding eav attribute value */
            $this->getSelect()->join(
                array($alias => $attribute->getBackendTable()),
                "main_table.product_id = $alias.entity_id AND $alias.attribute_id={$attribute->getId()}",
                array($attributeCode => 'value')
            );
            $this->_map['fields'][$attributeCode] = 'value';
        }
        /** adding catalog_product_entity table fields */
        $this->join(
            'catalog/product',
            'product_id=`catalog/product`.entity_id',
            array('sku' => 'sku', 'type_id' => 'type_id')
        );
        $this->_map['fields']['sku']     = 'sku';
        $this->_map['fields']['type_id'] = 'type_id';
        return $this;
    }

Verwenden Sie in Ihrem Rasterblock diese Funktion:

 protected function _prepareCollection()
    {
        $collection = Mage::getModel('some/yourmodel')
            ->getCollection()->addProductData();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

Das sieht vielversprechend aus, funktioniert aber leider nicht. Meine Sammlung erstreckt sich von Mage_Core_Model_Resource_Db_Collection_Abstractund ich erhalte eine Fehlermeldung Call to undefined method Mycompany_Module_Model_Resource_Mymodel_Collection::joinLeft(). Ich denke, das liegt daran, dass ich kein EAV-Ressourcenmodell verwende.
Celldweller

Verwenden Sie join anstelle von joinLeft, ich habe die Antwort bearbeitet
mageUz

doh! Ich fühle mich jetzt dumm! ;-) Und ich weiß nicht warum ich es versucht habe. Vielen Dank!
Celldweller

@ Celldweller, müssen Sie $this->_map['fields']['sku'] = 'sku'in diesem Fall nicht einmal unbedingt verwenden oder ähnliches. Sie benötigen es nur, wenn Sie mehrere identische Feldnamen haben und eine Übersetzung durchführen müssen, um Konflikte zu vermeiden. Es wird lediglich der Overhead für diesen Anwendungsfall hinzugefügt. In einem anderen Anwendungsfall, können Sie verwenden , $this->_map['fields']['my_sku'] = 'sku'dann können Sie mit der Sammlung verwenden und _prepareColumns: $this->addColumn('my_sku', array(…)), es wird Ihnen helfen Konflikt für die Filterung oder Spalten zu verhindern Sortierung , wenn Sie ein Feld haben skuin verschiedenen DB - Tabellen gemeinsam mit der Sammlung verwendet
Sylvain Rayé

Gute Antwort! Dies kann jedoch zu Problemen mit "Artikel mit derselben ID existiert bereits" führen. Ein einfaches $this->getSelect()->group('main_table.product_id');löst das Problem, aber vielleicht kann der Code optimiert werden, so dass überhaupt keine Duplikate erstellt werden?
Simon

4

Hallo Celldweller, ich hoffe es geht dir gut :-)

Vielleicht haben Sie sich in Ihrer Erklärung zur Klasse geirrt. Mage_Core_Model_Resource_Db_Collection_AbstractSie erweitern eine Ressourcensammlung und nicht das Modell, da Sie ein Modell nicht um eine Sammlungsklasse erweitern dürfen, wenn Sie die Magento-Struktur respektieren möchten. Habe ich recht?

Aufgrund meiner Korrektur sehe ich unterschiedliche Ansätze, je nachdem, wie oft Sie das Produktnamenattribut erhalten möchten. In jedem Fall denke ich, dass eine SQL-Abfrage über das Magento Framework der beste und effizienteste Weg ist. Es ist schneller als Mage::getModel('catalog/product')->load(1234)->getName()für jeden geladenen Gegenstand eine. Tatsächlich ist es dem Code, den Sie für das verwenden, sehr ähnlichsku

CODE NICHT GETESTET

Sie möchten diese Informationen jedes Mal, wenn eine Sammlung geladen wird

Sie können in Ihrer Sammlungsklasse einen _beforeLoadsolchen Code in eine Methode setzen:

protected function _beforeLoad()
{
    $productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

    $this->getSelect()
        ->join( array('product_attribute' => $productName->getBackendTable()),
            'main_table.product_id = product_attribute.entity_id',
            array())
        ->where("product_attribute.attribute_id = ?", $productName->getId());
    }

    return parent::_beforeLoad();
}

Sie möchten diese Informationen NUR für das Raster

In Ihrem _prepareCollectionmüssen Sie Ihrer Sammlung eine Methode mit demselben Code wie oben hinzufügen, _beforeLoaddann können Sie die Sammlung mit dieser Methode vorbereiten. Verwenden Sie nicht beide, ich meine, verwenden Sie nicht denselben Code _beforeLoadund dieselben addProductNameMethoden zusammen, sondern nur einen. Hier ist ein Beispiel:

In deine grid.php:

protected function _prepareCollection()
{
    ...
    $collection->addProductName();
    $this->setCollection($collection);
    return parent::_prepareCollection();
}

In Ihre Collection.php:

public function addProductName()
{
    $productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

    $this->getSelect()
        -> join( array('product_attribute' => $productName->getBackendTable()),
            'main_table.product_id = product_attribute.entity_id',
            array())
        ->where("product_attribute.attribute_id = ?", $productName->getId());

    return $this;
}

Schön, Sie noch einmal zu lesen :-) Vielen Dank, aber ich kann die joinLeft () -Methode nicht verwenden. Ich denke, es ist eine reine EAV-Ressourcenmodellmethode. Sie hatten Recht, ich war in meiner ersten Frage ungenau. Ich werde es bearbeiten :)
Celldweller

Übrigens: Natürlich möchte ich in einer solchen Situation kein product-> load () machen. Erschieß mich, wenn ich es jemals wagen würde! ;-) Mein Ziel ist es, alles in einer Sammlung zu haben, um im Raster sortieren und filtern zu können. Weitere Informationen finden Sie im Update in meinem ersten Beitrag.
Celldweller

Ersetzen Sie also joinLeft durch join, aber Sie haben die andere Antwort bereits akzeptiert, obwohl ich richtig geantwortet habe und als erster geantwortet habe :-(
Sylvain Rayé

Ja, du hast recht. Ich war so froh, dass es endlich geklappt hat, dass ich nicht darüber nachgedacht habe. Ich bin euch beiden sehr dankbar. Hoffe du kannst mir vergeben! Ich schulde dir ein Bier.
Celldweller

Ahah, keine Sorge. Wir treffen uns gerne in Berlin :-)
Sylvain Rayé

4

Ich hatte fast das gleiche Problem, aber ich kann keinen Kommentar hinzufügen, weil ich keinen Ruf habe. Ich habe viel Zeit damit verbracht herauszufinden, was falsch ist (ich habe den Code von Sylvain Rayé verwendet). Meine Produktkollektion wurde aus irgendeinem Grund gefiltert. Also habe ich einen Grund gefunden.

Wenn Sie einige Importwerkzeuge (Magmi usw.) verwenden, werden häufig keine leeren Attribute gleichzeitig erstellt. Daher wird die Verwendung von ->where("product_attribute.attribute_id = ?", $productName->getId())Produkten, die dieses Attribut nicht haben, aus der Auswahl entfernt.

Der richtige Weg ist, joinLeftFolgendes zu verwenden:

$productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

$this->getSelect()
     ->joinLeft(array('product_attribute' => $productName->getBackendTable()),
        "main_table.product_id = product_attribute.entity_id AND
         product_attribute.attribute_id = {$productName->getId()}",
        array());

Hoffe das hilft jemandem.


-2

Benutzerdefiniertes Attribut im Produktraster anzeigen.

Bitte überschreiben Sie diesen Block Mage_Adminhtml_Block_Catalog_Product_Grid in Ihrer Erweiterung und kopieren Sie die Funktionen _prepareCollection und _prepareColumns in die Blockdatei Ihrer Erweiterung.

Fügen Sie den folgenden Code hinzu, um das Attribut in der _prepareCollection-Funktion des Produktrasters Mage_Adminhtml_Block_Catalog_Product_Grid vor der Zeile $ this-> setCollection ($ collection) auszuwählen.

$attributeCode = 'qc_status';//here your attribute code
        $collection->joinAttribute($attributeCode, 'catalog_product/'.$attributeCode, 'entity_id', null, 'left');
        $collection->addAttributeToSelect($attributeCode);

Und dann unten Code für Spalte in _prepareColumns Funktion des Rasters.

$attributeCodeConfig ='qc_status';//Your attribute code...

        $attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $attributeCodeConfig);

        $attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeId);
        $attributeData = $attribute->getData();
        $frontEndLabel = $attributeData['frontend_label'];

        $attributeOptions = $attribute->getSource()->getAllOptions();
        $b = new Mage_Catalog_Model_Resource_Eav_Attribute();
        $attributeOptions2 = array();
        foreach ($attributeOptions as $value) {
            if(!empty($value['value'])) {
                $attributeOptions2[$value['value']] = $value['label'];
            }

        }


        if(count($attributeOptions2) > 0) {
            $this->addColumn($attributeCodeConfig,
                array(
                    'header'=> Mage::helper('catalog')->__($frontEndLabel),
                    'width' => '80px',
                    'index' => $attributeCodeConfig,
                    'type'  => 'options',
                    'options' => $attributeOptions2,

            ));
        } else {
            $this->addColumn($attributeCodeConfig,
                array(
                    'header'=> Mage::helper('catalog')->__($frontEndLabel),
                    'width' => '80px',
                    'index' => $attributeCodeConfig,

            ));
        }

Das Ändern von Kerndateien ist keine gute Vorgehensweise. Gleiches gilt fürnew SomeModel()
sv3n

Wir müssen die Kerndatei nicht ändern. Wir können diesen Block (Mage_Adminhtml_Block_Catalog_Product_Grid) überschreiben, um unsere Funktionalität zu erreichen
Savoo
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.