Filtrar la colección de productos por atributo no plano


14

Estoy haciendo lo siguiente:

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

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

my_attribute no está en las tablas planas, pero las tablas planas están habilitadas.

Sigo recibiendo la colección completa.

La razón parece estar en \Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSelect:

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

No $this->getEntity()es una instancia de la Mage_Catalog_Model_Resource_Product_Flatque se obtienen los campos planos, y si no se encuentra ninguno, solo devuelve nulo.

¿Cuál es una forma limpia de agregar un atributo no plano al filtro de colección?

En mi caso no tiene sentido agregar el atributo a la tabla plana.


Hola señor, ¿ES SU TIPO? ¿Se le ocurrió resolver la confusión? ¿A qué se refiere WAT non-flat attribute? Gracias. Y no hagáis magento confuso. Ya es confuso
Pratik

Estoy hablando de atributos que no están en el índice plano. Estos son aquellos con "Usado en el listado de productos" establecido en "No".
Alex

Respuestas:


18

Puedes unirte a la mesa necesaria tú mismo.

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

Es posible que desee unirse por store_id, también.


Creo que todavía tendría el problema de que no obtengo los productos de todas las tiendas. (siempre que no vi originalmente este problema en mi pregunta). Parece que quiero deshabilitar completamente los índices planos.
Alex

Si necesita todos los productos, entonces las mesas planas no serán sus amigos, sí.
Matthias Zeis

Supongo que es posible que desee modificar su pregunta o aceptar mi respuesta (que funciona para la pregunta original), entonces.
Matthias Zeis

impresionante .. concepto
Amit Bera

15

Un truco (CE 1.6.2.0+) es pasar la condición como una matriz y creerlo o no, esto funciona según lo previsto:

$collection->addFieldToFilter(array(array('attribute' => 'my_attribute', 'eq' => 1)));

¿Alguna pista de por qué funciona?
Alex

3
Funciona porque la colección eav addFieldToFileres un contenedor addAttributeToFiltery tiene una opción para pasar el atributo como una matriz:if (is_array($attribute)) { $sqlArr = array(); foreach ($attribute as $condition) { $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType); } $conditionSql = '('.implode(') OR (', $sqlArr).')'; }
Marius

@ Mario, ¿eso significa que no es un truco? : P ¿Puedo sentirme bien al usarlo?
Erfan

3
@Erfan. No es un truco. Es una característica.
Marius

Dulce. Todavía es un poco extraño que la implementación de la tabla de productos (eav / flat) no se abstraiga para cosas tan simples como filtrar una colección. ¿Esto significa que siempre necesito usar addFieldToFilter en lugar de addAttributeToFilter en mi código, porque no sabré si está usando eav o flat? ¿Cuál es el punto de addAttributeToFilter de todos modos?
Erfan

6

La razón por la que la respuesta de ColinM funciona se debe al código app/code/core/Mage/Catalog/Model/Resource/Product/Collection.phpdel addAttributeToFiltermétodo. Si usa este formato de matriz, no llama addAttributeToSelect. En modo plano, addAttributeToSelectfalla silenciosamente si el atributo no está en la tabla plana.

(a continuación se muestra un resumen de mi respuesta en /programming/6271284/can-i-add-other-attributes-to-magentos-flat-product-catalog-table/17021620 - Estoy no estoy seguro de cuál es la etiqueta para eso, pero sé que lo habría encontrado útil)

Quería una solución "limpia" para seleccionar y filtrar colecciones en modo plano en atributos no planos, que:

  • no requiere que el atributo tenga configuraciones específicas en admin (puede ser agregado por un usuario u oculto en el front-end)
  • funciona tanto en modo plano como no plano

Utilicé la colección de productos asociada, pero esto se aplica a cualquier colección de EAV.

Código de falla:

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

En modo plano, el código anterior no puede seleccionar o filtrar silenciosamente el atributo si no está en la tabla plana.

Agregando a la selección:

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

los joinAttribute método agrega una unión a la consulta para el atributo específico solicitado. Todavía funciona cuando el atributo ya está en la tabla plana, pero será un poco menos eficiente que usar la tabla plana.

He usado una leftcombinación allí, para asegurarme de que obtenga productos si my_custom_attributeno está configurado en esos productos. Cambie eso innersi solo le interesan las filas donde my_custom_attributeestá configurado.

Agregando al filtro (según ColinM arriba):

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

El código anterior lo agregará a la selección y obedecerá su filtro.

(probado en CE 1.6.2.0)


4

En el Mage_Rssmódulo utilizaron el método hacky para deshabilitar las tablas planas. Utilizan el hecho de que las tablas planas siempre están apagadas en la tienda de administración y, por lo tanto, simplemente emulan la tienda de administración.

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

Después de comenzar la emulación, debe restablecerla con emulationModel->stopEnvironmentEmulation()


¿Dónde estaba esta respuesta hace 3 días? ; _;
sg3s

¿Aquí mismo? 20. Desde mar
Alex

1

cuando crea el atributo, debe estar en el nivel Global y ser filtrable. De esta manera será utilizable en la navegación en capas. También requerirá que el atributo sea desplegable o multiseleccionado. Yo personalmente recomendaría no cambiar los archivos principales para satisfacer sus necesidades en este caso


No quiero el atributo en el filtro de interfaz; simplemente quiero hacer un filtrado de colección para uso interno.
Alex
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.