Filtrar coleção de produtos por atributo não plano

14

Eu estou fazendo o seguinte:

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

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

my_attribute não está nas tabelas planas, mas as tabelas planas estão ativadas.

Eu continuo recebendo a coleção completa.

O motivo parece estar em \Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSelect:

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

No $this->getEntity()é uma instância da Mage_Catalog_Model_Resource_Product_Flatqual busca os campos simples - e se nenhum for encontrado, apenas retorna nulo.

O que é uma maneira limpa de adicionar um atributo não plano ao filtro de coleção?

No meu caso, não faz sentido adicionar o atributo à tabela plana.

Alex
fonte
Oi senhor, você é o suficiente para resolver a confusão? WAT significa non-flat attribute? Graças .e não fazem magento Confundindo .Ele já está confundindo
Pratik
Estou falando de atributos que não estão no índice plano. São aqueles com "Usado na lista de produtos" definido como "Não".
28414 Alex

Respostas:

18

Você pode se juntar à mesa necessária.

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

Você também pode querer participar por store_id.

Matthias Zeis
fonte
Acho que ainda teria o problema de não conseguir os produtos de todas as lojas. (sempre que eu não vi esse problema originalmente na minha pergunta). Parece que eu quero desativar totalmente os índices simples.
21413 Alex
Se você precisar de todos os produtos, as mesas planas não serão seus amigos, sim.
Matthias Zeis
Acho que você pode modificar sua pergunta ou aceitar minha resposta (que funciona para a pergunta original).
Matthias Zeis 21/03/2013
awasome .. concept
Amit Bera
15

Um hack (CE 1.6.2.0+) deve passar a condição como uma matriz e, acredite ou não, isso funciona conforme o esperado:

$collection->addFieldToFilter(array(array('attribute' => 'my_attribute', 'eq' => 1)));
ColinM
fonte
Alguma pista por que isso funciona?
1155 Alex
3
Ele funciona porque para eav coleção addFieldToFileré um wrapper para addAttributeToFiltere isso tem uma opção para passar o atributo como uma matriz:if (is_array($attribute)) { $sqlArr = array(); foreach ($attribute as $condition) { $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType); } $conditionSql = '('.implode(') OR (', $sqlArr).')'; }
Marius
@ Marius, isso significa que não é um hack? : P Posso me sentir bem em usá-lo?
Erfan
3
@Erfan. não é um truque. é uma característica.
Marius
Doce. Ainda é meio estranho que a implementação da tabela de produtos (eav / flat) não seja abstraída para coisas tão simples quanto filtrar uma coleção. Isso significa que eu sempre preciso usar addFieldToFilter em vez de addAttributeToFilter no meu código, porque não saberei se ele está usando eav ou flat? Qual é o objetivo de addAttributeToFilter, afinal?
Erfan
6

A razão a resposta de ColinM funciona é devido ao código em app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php's addAttributeToFiltermétodo. Se você usar esse formato de matriz, ele não chama addAttributeToSelect. No modo simples, addAttributeToSelectfalha silenciosamente se o atributo não estiver na tabela plana.

(abaixo está um re-hash da minha resposta em /programming/6271284/can-i-add-other-attributes-to-magentos-flat-product-catalog-table/17021620 - Estou não sei ao certo qual é a etiqueta para isso, mas sei que a consideraria útil)

Eu queria uma solução "limpa" para a coleção de modo plano, selecionando e filtrando atributos não planos, que:

  • não requer que o atributo tenha configurações específicas no administrador (ele pode ser adicionado por um usuário ou oculto no front-end)
  • funciona para o modo plano e não plano

Usei a coleção de produtos associada, mas isso se aplica a qualquer coleção de EAV.

Código com falha:

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

No modo simples, o código acima silenciosamente falha ao selecionar ou filtrar o atributo, se não estiver na tabela plana.

Adicionando ao select:

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

O joinAttributemétodo adiciona uma junção à consulta para o atributo específico solicitado. Ele ainda funciona quando o atributo já está na mesa plana, mas será um pouco menos eficiente do que puramente usando a mesa plana.

Eu usei uma leftassociação lá, para garantir que ela busque produtos, se my_custom_attributenão estiver definida nesses produtos. Altere isso para innerse você estiver interessado apenas nas linhas em que my_custom_attributeestá definido.

Adicionando ao filtro (conforme ColinM acima):

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

O código acima o adicionará ao select e também obedecerá ao seu filtro.

(testado na CE 1.6.2.0)

johnorourke
fonte
4

No Mage_Rssmódulo, eles usaram o método hacky para desativar as tabelas planas. Eles usam o fato de que as tabelas simples estão sempre desativadas no repositório de administradores e, portanto, apenas emulam o repositório de administradores.

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

Depois de iniciar a emulação, você deve redefini-la com emulationModel->stopEnvironmentEmulation()

Alex
fonte
Onde estava essa resposta 3 dias atrás? ; _;
Sg3s
Bem aqui? Desde 20 de março
Alex
1

quando você cria o atributo, ele deve estar no nível Global e filtrável. Desta forma, será utilizável na navegação em layouts. Também exigirá que o atributo seja uma lista suspensa ou multiselecionada. Eu pessoalmente aconselho a não alterar os arquivos principais para atender às suas necessidades neste caso

Sander Mangel
fonte
Eu não quero o atributo no filtro de front-end - eu simplesmente quero fazer uma coleção de filtragem para uso interno.
22413 Alex