Meilleure pratique pour joindre des attributs de produit

11

J'ai un tableau personnalisé avec une référence de produit product_id. Maintenant, je voudrais afficher les informations sur les produits (sku, nom) dans ma grille principale , mais je ne sais pas quelle est la meilleure pratique pour le faire?

Ma meilleure estimation SKUest la suivante:

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

(code de la _prepareCollection() méthode dans ma classe de bloc de grille)

Mais qu'en est-il du nom du produit? Il peut être trouvé dans catalog_product_entity_varchar. Ma compréhension est que vous pouvez plutôt facilement l'obtenir si votre propre modèle de ressources et collection est basé sur, Mage_Eav_Model_Entity_Collection_Abstractcar alors vous pouvez utiliser des méthodes comme joinAttribute. Mais mon modèle est basé sur une table simple et s'étend de Mage_Core_Model_Resource_Db_Collection_Abstractet il n'y a pas de joinAttributeméthode disponible.

Alors, quelle est la meilleure façon d'obtenir le nom du produit dans ce cas?

Merci pour votre temps et votre aide :-)

Mise à jour: Pour être plus précis, je parlais de mon modèle de ressources et de ma collection. Il correspond à une simple table plate avec seulement quelques attributs comme

entity_id    product_id    created_at    user_id

Mon intention est de grille dans le backend où je montre quelques statistiques:

ProductSku    Count(ProductSku)    MAX(created_at)

Pour autant que je sache, la meilleure approche pour ce faire, est via la classe de bloc de grille et la méthode à suivre est _prepareCollection().

Ma méthode ressemble à ceci:

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

Cela fonctionne bien pour le sku (que j'appelle product_sku dans la _prepareColums()méthode. Mais que joindois-je insérer ici pour obtenir le nom (et par exemple le fabricant)?

Suis-je en train de faire quelque chose de mal parce que je ne peux pas l'utiliser joinLeft()?

Celldweller
la source

Réponses:

13

Dans votre classe de collection ( /Some/Module/Model/Mysql4 (or Resource)/YourModel/Collection.php) ajoutez cette méthode:

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

Dans votre bloc de grille, utilisez cette fonction:

 protected function _prepareCollection()
    {
        $collection = Mage::getModel('some/yourmodel')
            ->getCollection()->addProductData();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }
mageUz
la source
Cela semble prometteur, mais cela ne fonctionne malheureusement pas. Ma collection s'étend de Mage_Core_Model_Resource_Db_Collection_Abstractet j'obtiens une erreur Call to undefined method Mycompany_Module_Model_Resource_Mymodel_Collection::joinLeft(). Je suppose que c'est parce que je n'utilise pas de modèle de ressource EAV?
Celldweller
Utilisez join au lieu de joinLeft, j'ai modifié la réponse
mageUz
doh! Je me sens stupide maintenant! ;-) Et je ne sais pas pourquoi je l'ai essayé. Merci beaucoup!
Celldweller
@Celldweller, vous n'avez même pas absolument besoin d'utiliser $this->_map['fields']['sku'] = 'sku'ou similaire dans ce cas. Vous n'en avez besoin que si vous avez plusieurs noms de champs identiques et devez faire une traduction pour éviter les conflits. Il ajoute simplement des frais généraux pour ce cas d'utilisation. Dans un autre cas d'utilisation, vous pouvez utiliser $this->_map['fields']['my_sku'] = 'sku'ensuite vous pouvez utiliser avec la collection et _prepareColumns:, $this->addColumn('my_sku', array(…))cela vous aidera à éviter les conflits pour le filtrage ou le tri des colonnes si vous avez un champ skuutilisé dans différentes tables de base de données communes à la collection
Sylvain Rayé
Très bonne réponse! Cependant, cela peut entraîner des problèmes «l'élément avec le même ID existe déjà». Un simple $this->getSelect()->group('main_table.product_id');résout le problème, mais peut-être que le code peut être optimisé, afin que les doublons ne soient pas créés en premier lieu?
Simon
4

Salut Celldweller j'espère que tu vas bien :-)

Vous vous êtes peut-être trompé dans votre explication sur la classe Mage_Core_Model_Resource_Db_Collection_Abstract, vous étendez une collection de ressources et non le modèle car vous ne devez pas étendre un modèle avec une classe de collection si vous voulez respecter la structure Magento. Ai-je raison?

Sur la base de ma correction, je vois différents types d'approche, selon la fréquence à laquelle vous souhaitez obtenir l'attribut de nom de produit. Dans tous les cas, je pense que faire une requête SQL via le Magento Framework est le meilleur moyen et efficace. C'est plus rapide que de faire un Mage::getModel('catalog/product')->load(1234)->getName()pour chaque élément chargé. Donc, en fait, il sera très similaire au code que vous utilisez pour lesku

CODE NON TESTÉ

Vous voulez ces informations chaque fois qu'une collection est chargée

Vous pouvez dans votre classe de collection définir une _beforeLoadméthode comme un code:

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

Vous voulez ces informations UNIQUEMENT pour la grille

Dans votre _prepareCollection, vous devrez ajouter une méthode dans votre collection avec le même code que cela a été fait ci-dessus dans le _beforeLoadpuis vous pouvez préparer la collection en utilisant cette méthode. N'utilisez pas les deux, je veux dire n'utilisez pas ensemble le même code _beforeLoadet les mêmes addProductNameméthodes, n'utilisez qu'une seule d'entre elles. Voici un exemple:

Dans votre grid.php:

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

Dans votre 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;
}
Sylvain Rayé
la source
Ravi de vous relire :-) Merci beaucoup mais je ne peux pas utiliser la méthode joinLeft (). Je suppose que c'est une méthode de modèle de ressource EAV uniquement? Vous aviez raison, j'étais imprécis dans ma question initiale. Je vais le modifier :)
Celldweller
Oh et btw: Bien sûr, je ne veux pas faire un produit-> load () dans une telle situation. Tire-moi si jamais j'ose! ;-) Mon objectif est de tout avoir dans une collection afin de pouvoir trier et filtrer dans la grille. Voir la mise à jour dans mon post initial pour plus de détails.
Celldweller
Remplacez donc joinLeft par join mais vous avez déjà accepté l'autre réponse même si j'ai répondu correctement et que j'ai été le premier à répondre :-(
Sylvain Rayé
Oui, tu as raison. J'étais tellement heureux que ça ait finalement fonctionné, que je n'y ai pas pensé. Je suis très reconnaissant à vous deux. J'espère que vous pouvez me pardonner! Je te dois une bière.
Celldweller
ahah pas de souci. Nous vous rencontrons à Berlin avec plaisir :-)
Sylvain Rayé
4

J'ai eu presque le même problème, mais je ne peux pas ajouter de commentaire, car je n'ai pas 50 points de réputation. J'ai passé beaucoup de temps à essayer de comprendre ce qui ne va pas (j'ai utilisé le code de Sylvain Rayé). Ma collection de produits a été filtrée pour une raison quelconque. J'ai donc trouvé une raison.

Si vous utilisez des outils d'importation (magmi, etc.), ils ne créent souvent pas d'attributs vides à la fois. Par conséquent, l'utilisation de ->where("product_attribute.attribute_id = ?", $productName->getId())produits ne possédant pas cet attribut disparaîtra de la sélection.

La bonne façon utilise joinLeftcomme ça:

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

J'espère que cela aide quelqu'un.

spiil
la source
-2

Afficher l'attribut personnalisé sur la grille du produit.

Veuillez remplacer ce bloc Mage_Adminhtml_Block_Catalog_Product_Grid dans votre extension et copier les fonctions _prepareCollection et _prepareColumns dans le fichier de blocage de votre extension.

Ajoutez le code ci-dessous pour sélectionner l'attribut dans la fonction _prepareCollection de la grille de produits Mage_Adminhtml_Block_Catalog_Product_Grid avant la ligne $ this-> setCollection ($ collection).

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

Et puis ci-dessous le code pour la colonne dans la fonction _prepareColumns de la grille.

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

            ));
        }
Savoo
la source
Changer les fichiers principaux n'est pas une bonne pratique. Pareil pournew SomeModel()
sv3n
nous n'avons pas besoin de changer dans le fichier de base. nous pouvons remplacer ce bloc (Mage_Adminhtml_Block_Catalog_Product_Grid) pour accomplir notre fonctionnalité
Savoo