Best practice per unire gli attributi del prodotto


11

Ho una tabella personalizzata con un riferimento al prodotto product_id. Ora vorrei mostrare le informazioni sul prodotto (sku, nome) nella mia griglia di back-end , ma non sono sicuro di quale sia la migliore pratica per farlo?

La mia ipotesi migliore SKUè la seguente:

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

(codice dal _prepareCollection() metodo nella mia classe di blocco della griglia)

Ma per quanto riguarda il nome del prodotto? Può essere trovato in catalog_product_entity_varchar. La mia comprensione è che puoi piuttosto facilmente ottenerlo se il tuo modello di risorsa e la tua raccolta sono basati su Mage_Eav_Model_Entity_Collection_Abstractperché allora puoi usare metodi come joinAttribute. Ma il mio modello si basa su una tabella semplice e si estende da Mage_Core_Model_Resource_Db_Collection_Abstracte non esiste alcun joinAttributemetodo disponibile.

Quindi qual è il modo migliore per ottenere il nome del prodotto in questo caso?

Grazie per il tuo tempo e aiuto :-)

Aggiornamento: per essere più precisi, stavo parlando del mio modello di risorsa e raccolta. Abbina una semplice tabella piatta con solo alcuni attributi come

entity_id    product_id    created_at    user_id

La mia intenzione è quella di grigliare nel backend in cui mostro alcune statistiche:

ProductSku    Count(ProductSku)    MAX(created_at)

Per quanto ne so, il miglior approccio per farlo è tramite la classe del blocco della griglia e il metodo da seguire è _prepareCollection().

Il mio metodo è simile al seguente:

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();
}

Questo funziona bene per lo sku (che nel _prepareColums()metodo definisco product_sku . Ma cosa joindevo inserire qui per ottenere il nome (e ad esempio il produttore)?

Sto sbagliando qualcosa perché non posso usarlo joinLeft()?

Risposte:


13

Nella tua classe di raccolta ( /Some/Module/Model/Mysql4 (or Resource)/YourModel/Collection.php) aggiungi questo metodo:

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;
    }

Nel tuo blocco della griglia usa questa funzione:

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

Sembra promettente, ma purtroppo non funziona. La mia raccolta si estende da Mage_Core_Model_Resource_Db_Collection_Abstracte ottengo un errore Call to undefined method Mycompany_Module_Model_Resource_Mymodel_Collection::joinLeft(). Immagino che sia perché non uso un modello di risorse EAV?
Celldweller,

Usa join invece di joinLeft, ho modificato la risposta
mageUz

doh! Mi sento stupido ora! ;-) E non so perché l'ho provato. Grazie mille!
Celldweller,

@Celldweller, non hai nemmeno assolutamente bisogno di usare $this->_map['fields']['sku'] = 'sku'o simili in questo caso. Ne hai bisogno solo se hai diversi nomi di campi identici e devi fare una traduzione per evitare conflitti. Aggiunge solo un sovraccarico per questo caso d'uso. In un altro caso d'uso, è possibile utilizzare $this->_map['fields']['my_sku'] = 'sku'quindi è possibile utilizzare con la raccolta e _prepareColumns: $this->addColumn('my_sku', array(…))ti aiuterà a prevenire conflitti per il filtro o l'ordinamento delle colonne se si dispone di un campo skuutilizzato in diverse tabelle DB comuni alla raccolta
Sylvain Rayé

Bella risposta! Tuttavia, può causare problemi "elemento con lo stesso ID già esistente". Un semplice $this->getSelect()->group('main_table.product_id');risolve il problema, ma forse il codice può essere ottimizzato, in modo che i duplicati non vengano creati in primo luogo?
Simon,

4

Ciao Celldweller, spero che tu stia bene :-)

Forse hai sbagliato nella tua spiegazione sulla classe Mage_Core_Model_Resource_Db_Collection_Abstract, estendi una raccolta di risorse non il modello perché non devi estendere un modello con una classe di raccolta se vuoi rispettare la struttura di Magento. Ho ragione?

Sulla base della mia correzione, vedo diversi tipi di approccio, a seconda della frequenza con cui desideri ottenere l'attributo del nome del prodotto. In ogni caso, penso che fare una query sql tramite Magento Framework sia il modo migliore ed efficiente. È più veloce che fare un Mage::getModel('catalog/product')->load(1234)->getName()per ogni elemento caricato. Quindi in effetti sarà molto simile al codice che usi persku

CODICE NON TESTATO

Desideri tali informazioni ogni volta che viene caricata una raccolta

Nella tua classe di raccolta puoi impostare un _beforeLoadmetodo come un codice:

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();
}

Desideri tali informazioni SOLO per la griglia

Nel tuo _prepareCollection, dovrai aggiungere un metodo nella tua raccolta con lo stesso codice che è stato fatto sopra in _beforeLoadpoi puoi preparare la raccolta usando questo metodo. Non usare entrambi, voglio dire non usare insieme lo stesso codice _beforeLoade addProductNamemetodi, usare solo uno di essi. Ecco un esempio:

Nel tuo grid.php:

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

Nella tua collezione.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;
}

Ottimo per rileggerti :-) Grazie mille ma non posso usare il metodo joinLeft (). Immagino che sia un metodo solo modello di risorsa EAV? Avevi ragione, non ero preciso nella mia domanda iniziale. Lo modificherò :)
Celldweller,

Oh e btw: ovviamente non voglio fare un prodotto-> load () in una situazione del genere. Sparami se mai osassi! ;-) Il mio obiettivo è quello di avere tutto in una raccolta per poter fare l'ordinamento e il filtraggio nella griglia. Vedi l'aggiornamento nel mio post iniziale per ulteriori dettagli.
Celldweller,

Quindi sostituisci joinLeft con join ma hai già accettato l'altra risposta anche se ho risposto correttamente ed è stata la prima a rispondere :-(
Sylvain Rayé

Si hai ragione. Ero così felice che alla fine ha funzionato, che non ci ho pensato. Sono molto grato ad entrambi. Spero che tu possa perdonarmi! Ti devo una birra.
Celldweller,

ahah non preoccuparti. Ci vediamo a Berlino con piacere :-)
Sylvain Rayé,

4

Ho avuto quasi lo stesso problema, ma non posso aggiungere un commento, perché non ho 50 reputazione. Ho trascorso molto tempo a cercare di capire cosa non va (ho usato il codice di Sylvain Rayé). La mia raccolta di prodotti per qualche motivo filtrata. Quindi ho trovato un motivo.

Se si utilizzano alcuni strumenti di importazione (magmi, ecc.), Spesso non creano attributi vuoti contemporaneamente. Pertanto, l'utilizzo di ->where("product_attribute.attribute_id = ?", $productName->getId())prodotti che non dispongono di questo attributo scomparirà dalla selezione.

Il modo giusto sta usando joinLeftcosì:

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

Spero che questo aiuti qualcuno.


-2

Visualizza l'attributo personalizzato sulla griglia del prodotto.

Sovrascrivi questo blocco Mage_Adminhtml_Block_Catalog_Product_Grid nella tua estensione e copia le funzioni _prepareCollection e _prepareColumns nel file di blocco della tua estensione.

Aggiungi il codice seguente per selezionare attribet nella funzione _prepareCollection della griglia del prodotto Mage_Adminhtml_Block_Catalog_Product_Grid prima di $ this-> setCollection ($ collection) line.

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

E poi sotto il codice per la colonna nella funzione _prepareColumns della griglia.

$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,

            ));
        }

Modificare i file core non è una buona pratica. Lo stesso pernew SomeModel()
sv3n,

non è necessario modificare il file core. Possiamo sovrascrivere quel blocco (Mage_Adminhtml_Block_Catalog_Product_Grid) per realizzare la nostra funzionalità
Savoo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.