Filtrer la collection de produits par attribut non plat

14

Je fais ce qui suit:

$productCollection = Mage::getModel('catalog/product')
    ->getCollection();

$productCollection
    ->addAttributeToFilter('my_attribute', 1);

my_attribute n'est pas dans les tables plates, mais les tables plates sont activées.

Je reçois toujours la collection complète.

La raison semble être \Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSelect:

$columns = $this->getEntity()->getAttributeForSelect($attributeCode);

Non $this->getEntity()est une instance Mage_Catalog_Model_Resource_Product_Flatqui récupère les champs plats - et si aucun n'est trouvé, renvoie simplement null.

Qu'est-ce qu'un moyen propre d'ajouter un attribut non plat au filtre de collection?

Dans mon cas, cela n'a pas de sens, d'ajouter l'attribut à la table plate.

Alex
la source
Salut monsieur ÊTES-VOUS GENRE De vouloir résoudre la confusion ?? WAT signifie par non-flat attribute? Merci .et ne pas rendre magento déroutant. C'est déjà déroutant
Pratik
Je parle d'attributs qui ne sont pas dans l'index plat. Ce sont ceux avec "Utilisé dans la liste des produits" réglé sur "Non".
Alex

Réponses:

18

Vous pouvez rejoindre vous-même la table nécessaire.

$productCollection = Mage::getModel('catalog/product')
->getCollection();

$table = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'my_attribute')->getBackend()->getTable();
$attributeId = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'my_attribute')->getAttributeId();

$productCollection->getSelect()->join(array('attributeTable' => $table), 'e.entity_id = attributeTable.entity_id', array('my_attribute' => 'attributeTable.value'))
                            ->where("attributeTable.attribute_id = ?", $attributeId)
                            ->where("attributeTable.value = ?", 1);

Vous voudrez peut-être aussi rejoindre par store_id.

Matthias Zeis
la source
Je pense que j'aurais toujours le problème de ne pas obtenir les produits de tous les magasins. (chaque fois que je n'ai pas vu ce problème à l'origine dans ma question). On dirait que je veux désactiver complètement les indices plats.
Alex
Si vous avez besoin de tous les produits, les tables plates ne seront pas vos amis, oui.
Matthias Zeis
Je suppose que vous voudrez peut-être modifier votre question ou accepter ma réponse (qui fonctionne pour la question d'origine), alors.
Matthias Zeis
génial .. concept
Amit Bera
15

Un hack (CE 1.6.2.0+) consiste à passer la condition sous forme de tableau et à croire que cela fonctionne ou non comme prévu:

$collection->addFieldToFilter(array(array('attribute' => 'my_attribute', 'eq' => 1)));
ColinM
la source
Un indice pourquoi cela fonctionne?
Alex
3
Cela fonctionne parce que pour la collection eav addFieldToFilerest un wrapper pour addAttributeToFilteret cela a une option pour passer l'attribut comme un tableau:if (is_array($attribute)) { $sqlArr = array(); foreach ($attribute as $condition) { $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType); } $conditionSql = '('.implode(') OR (', $sqlArr).')'; }
Marius
@Marius, cela signifie-t-il que ce n'est pas un hack? : P Puis-je me sentir bien de l'utiliser?
Erfan
3
@Erfan. ce n'est pas un hack. c'est une fonctionnalité.
Marius
Sucré. Il est encore un peu étrange que l'implémentation de la table de produits (eav / flat) ne soit pas abstraite pour des choses aussi simples que le filtrage d'une collection. Est-ce à dire que je dois toujours utiliser addFieldToFilter au lieu d'addAttributeToFilter dans mon code, car je ne sais pas s'il utilise eav ou flat? Quel est l'intérêt de addAttributeToFilter de toute façon?
Erfan
6

La raison pour laquelle la réponse de ColinM fonctionne est due au code dans app/code/core/Mage/Catalog/Model/Resource/Product/Collection.phpla addAttributeToFilterméthode de. Si vous utilisez ce format de tableau, il n'appelle pas addAttributeToSelect. En mode plat, addAttributeToSelectéchoue silencieusement si l'attribut n'est pas dans la table plate.

(ci-dessous est un nouveau hachage de ma réponse sur /programming/6271284/can-i-add-other-attributes-to-magentos-flat-product-catalog-table/17021620 - je suis Je ne sais pas quelle est l'étiquette pour cela, mais sachez que j'aurais trouvé cela utile)

Je voulais une solution "propre" pour la sélection et le filtrage de collection en mode plat sur des attributs non plats, qui:

  • ne nécessite pas que l'attribut ait des paramètres spécifiques dans admin (il peut être ajouté par un utilisateur ou masqué sur le front-end)
  • fonctionne aussi bien en mode plat qu'en mode non plat

J'ai utilisé la collection de produits associée, mais cela s'applique à toute collection EAV.

Code défaillant:

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->addAttributeToSelect( 'my_custom_attribute' )
    ->addAttributeToFilter( 'my_custom_attribute', 3 )
;

En mode plat, le code ci-dessus ne parvient pas à sélectionner ou filtrer silencieusement l'attribut s'il ne se trouve pas dans la table plate.

Ajout à la sélection:

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->joinAttribute( 'my_custom_attribute', 'catalog_product/my_custom_attribute', 'entity_id', null, 'left' )
    ->addAttributeToSelect( 'my_custom_attribute' )
;

le joinAttribute méthode ajoute une jointure à la requête pour l'attribut spécifique demandé. Cela fonctionne toujours lorsque l'attribut est déjà dans la table plate, mais sera légèrement moins efficace que l'utilisation pure de la table plate.

J'ai utilisé une leftjointure là-bas, pour m'assurer qu'elle récupère les produits si elle my_custom_attributen'est pas définie sur ces produits. Modifiez cela innersi vous n'êtes intéressé que par les lignes où my_custom_attributeest défini.

Ajout au filtre (selon ColinM ci-dessus):

$_product = Mage::getModel('catalog/product')->loadByAttribute( 'sku', 'ABC123' );
$coll = $_product->getTypeInstance()->getAssociatedProductCollection()
    ->addAttributeToFilter( array( array( 'attribute' => 'my_custom_attribute', 'eq' => 3 ) ) )
;

Le code ci-dessus l'ajoutera à la sélection et obéira à votre filtre.

(testé dans CE 1.6.2.0)

johnorourke
la source
4

Dans le Mage_Rssmodule, ils ont utilisé la méthode a hacky pour désactiver les tables plates. Ils utilisent le fait que les tables plates sont toujours désactivées dans le magasin d'administration et émulent donc simplement le magasin d'administration.

class Mage_Rss_Helper_Data {

[...]

/**
 * Disable using of flat catalog and/or product model to prevent limiting results to single store. Probably won't
 * work inside a controller.
 *
 * @return null
 */
public function disableFlat()
{
    /* @var $flatHelper Mage_Catalog_Helper_Product_Flat */
    $flatHelper = Mage::helper('catalog/product_flat');
    if ($flatHelper->isEnabled()) {
        /* @var $emulationModel Mage_Core_Model_App_Emulation */
        $emulationModel = Mage::getModel('core/app_emulation');
        // Emulate admin environment to disable using flat model - otherwise we won't get global stats
        // for all stores
        $emulationModel->startEnvironmentEmulation(0, Mage_Core_Model_App_Area::AREA_ADMINHTML);
    }
}

Après avoir démarré l'émulation, vous devez la réinitialiser avec emulationModel->stopEnvironmentEmulation()

Alex
la source
Où était cette réponse il y a 3 jours? ; _;
sg3s
Ici? Depuis le 20 mars
Alex
1

lorsque vous créez l'attribut, il doit être au niveau global et filtrable. De cette façon, il sera utilisable dans la navigation en couches. Il faudra également que l'attribut soit une liste déroulante ou une sélection multiple. Je conseillerais personnellement de ne pas modifier les fichiers de base pour répondre à vos besoins dans ce cas

Sander Mangel
la source
Je ne veux pas l'attribut dans le filtre frontal - je veux simplement faire un filtrage de collection pour un usage interne.
Alex