2012-06-15 8 views
9

¿Cómo se puede filtrar la Colección Solicitar Magento ventas por atributo1 = valor1 Y (atributo2 = valor2 O Attribute3 = valor2)? Puedo escribir DONDE {} y {COND1 COND2} o {} COND3, pero no puedo grupo Y ({{O} COND2 COND3})Filtrado Magento Colecciones por COND1 Y (O COND2 COND3)

En primer lugar, esto no es un duplicado yo sepa , He visto this y funciona muy bien en la versión 1.3.2, pero no en Enterprise Edition 1.11.1. Esto es lo que trato de hacer ... obtener los pedidos de Magento que se crearon o actualizaron en un rango de fechas definido que tiene un estado de 'procesamiento'. Aquí está el código que funciona en las versiones anteriores, pero no en la mía:

$orderIds = Mage::getModel('sales/order')->getCollection() 
    ->addFieldToFilter('status', 'processing') 
    ->addFieldToFilter(array(
     array(
      'attribute' => 'created_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
     array(
      'attribute' => 'updated_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
    )); 

Este es el SQL que está generando, y el error resultante:

SELECT `main_table`.* FROM `sales_flat_order` AS `main_table` 
WHERE (status = 'processing') AND (Array = '') 

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Array' in 'where clause' 

En la excavación a través del código, he encontrado la función addFieldToFilter en lib/Varien/datos/Colección/db.php

/** 
* Add field filter to collection 
* 
* @see self::_getConditionSql for $condition 
* @param string $field 
* @param null|string|array $condition 
* @return Mage_Eav_Model_Entity_Collection_Abstract 
*/ 
public function addFieldToFilter($field, $condition=null) 
{ 
    $field = $this->_getMappedField($field); 
    $this->_select->where($this->_getConditionSql($field, $condition), 
     null, Varien_Db_Select::TYPE_CONDITION); 
    return $this; 
} 

// ********************************************** 
// ** Different from addFieldToFilter in 1.3.2 ** 
// ********************************************** 

/** 
* Add field filter to collection 
* 
* If $attribute is an array will add OR condition with following format: 
* array(
*  array('attribute'=>'firstname', 'like'=>'test%'), 
*  array('attribute'=>'lastname', 'like'=>'test%'), 
*) 
* 
* @see self::_getConditionSql for $condition 
* @param string|array $attribute 
* @param null|string|array $condition 
* @return Mage_Eav_Model_Entity_Collection_Abstract 
*/ 
public function addFieldToFilter($field, $condition=null) 
{ 
    $field = $this->_getMappedField($field); 
    $this->_select->where($this->_getConditionSql($field, $condition)); 
    return $this; 
}  

parece que addFieldToFilter utilizado para aceptar el primer parámetro como una matriz, pero sin w debe ser una cadena ... Interesante, así que he intentado lo siguiente con cero suerte ...

$orderIds = Mage::getModel('sales/order')->getCollection() 
    ->addFieldToFilter('status', 'processing') 
    ->addFieldToFilter('attribute', array(
     array(
      'attribute' => 'created_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
     array(
      'attribute' => 'updated_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
    )); 
SELECT `main_table`.* FROM `sales_flat_order` AS `main_table` 
WHERE (status = 'processing') 
AND ((
    (attribute >= '2012-06-13 17:52:01' AND attribute <= '2012-06-15 17:52:01') 
OR (attribute >= '2012-06-13 17:52:01' AND attribute <= '2012-06-15 17:52:01') 
)) 

sé que puedo hacerlo mediante la manipulación del SQL, pero realmente quiero saber cómo hacerlo "el modo Magento" si hay uno ...

Por cierto, también he intentado usar addAttributeToFilter y el mensaje de error es "No se puede determinar el nombre del campo".


ACTUALIZACIÓN

me encontré con dos funciones en Mage_Sales_Model_Resource_Order_Collection que parecen semi-prometedor, pero siguen siendo no del todo lo que quiero.

/** 
* Add field search filter to collection as OR condition 
* 
* @see self::_getConditionSql for $condition 
* 
* @param string $field 
* @param null|string|array $condition 
* @return Mage_Sales_Model_Resource_Order_Collection 
*/ 
public function addFieldToSearchFilter($field, $condition = null) 
{ 
    $field = $this->_getMappedField($field); 
    $this->_select->orWhere($this->_getConditionSql($field, $condition)); 
    return $this; 
} 

/** 
* Specify collection select filter by attribute value 
* 
* @param array $attributes 
* @param array|integer|string|null $condition 
* @return Mage_Sales_Model_Resource_Order_Collection 
*/ 
public function addAttributeToSearchFilter($attributes, $condition = null) 
{ 
    if (is_array($attributes) && !empty($attributes)) { 
     $this->_addAddressFields(); 

     $toFilterData = array(); 
     foreach ($attributes as $attribute) { 
      $this->addFieldToSearchFilter($this->_attributeToField($attribute['attribute']), $attribute); 
     } 
    } else { 
     $this->addAttributeToFilter($attributes, $condition); 
    } 

    return $this; 
} 

Cuando se actualiza el código consigo muy cerca al resultado deseado, sin embargo lo que realmente quiero es tener CONDITION1 Y (CONDITION2 O Condition3)

$orderIds = Mage::getModel('sales/order')->getCollection() 
    ->addFieldToFilter('status', 'processing') 
    ->addAttributeToSearchFilter(array(
     array(
      'attribute' => 'created_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
     array(
      'attribute' => 'updated_at', 
      'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'), 
      'to' => $toDate->toString('yyyy-MM-dd HH:mm:ss'), 
     ), 
    )); 

SELECT `main_table`.*, 
     `billing_o_a`.`firstname`, 
     `billing_o_a`.`lastname`, 
     `billing_o_a`.`telephone`, 
     `billing_o_a`.`postcode`, 
     `shipping_o_a`.`firstname`, 
     `shipping_o_a`.`lastname`, 
     `shipping_o_a`.`telephone`, 
     `shipping_o_a`.`postcode` 
FROM `sales_flat_order` AS `main_table` 
LEFT JOIN `sales_flat_order_address` AS `billing_o_a` 
    ON (main_table.entity_id = billing_o_a.parent_id AND billing_o_a.address_type = 'billing') 
LEFT JOIN `sales_flat_order_address` AS `shipping_o_a` 
    ON (main_table.entity_id = shipping_o_a.parent_id AND shipping_o_a.address_type = 'shipping') 
WHERE (status = 'processing') 
OR (created_at >= '2012-06-16 16:43:38' AND created_at <= '2012-06-18 16:43:38') 
OR (updated_at >= '2012-06-16 16:43:38' AND updated_at <= '2012-06-18 16:43:38') 
+0

no creo que se puede hacer eso, como 'ventas/order' mapas a un piso ta ble. Use getSelect() en la colección en su lugar. – nevvermind

+0

@nevvermind ¿Por qué debería importar si es una mesa plana o no? – nachito

+1

No debería. http://stackoverflow.com/a/5245895/394589 – nevvermind

Respuesta

0

Aquí es el solución que preferiría no usar, que modifica la instrucción SELECT mediante los métodos Zend_Db.

$orderIds = Mage::getModel('sales/order')->getCollection() 
    ->getSelect(); 
$adapter = $orderIds->getAdapter(); 
$quotedFrom = $adapter->quote(
    $fromDate->toString('yyyy-MM-dd HH:mm:ss') 
); 
$quotedTo = $adapter->quote(
    $toDate->toString('yyyy-MM-dd HH:mm:ss') 
); 
$orderIds 
    ->where('status = ?', 'processing') 
    ->where(
     vsprintf(
      '(created_at >= %s AND created_at <= %s)' 
      . ' OR (updated_at >= %s AND updated_at <= %s)', 
      array(
       $quotedFrom, $quotedTo, 
       $quotedFrom, $quotedTo, 
      ) 
     ) 
    ); 
2

Tenga en cuenta que las colecciones FLAT TABLE y EAV utilizan una sintaxis diferente.

añadiendo o condiciones EAV colecciones

Tenga en cuenta que al especificar o condiciones para el mismo atributo de la sintaxis es diferente a continuación, si desea utilizar dos atributos diferentes.

Utilice $collection->load(true) para probar y ver el filtro especificado como SQL (me resulta más fácil de entender de esa manera).

Para colecciones EAV, utilice addAttributeToFilter() o addFieldToFilter(), pero el primero puede tomar un tercer argumento opcional $joinType.

Cómo agregar un filtro OR para UN atributo en colecciones EAV: el código de atributo es el primer argumento y las condiciones son el segundo.

Ej: $col->addFieldToFilter('name', array(array('like' => 'M%'), array('like' => '%O'))); // (get items whose name starts with M OR ends with O)

cómo agregar un filtro para O atributos diferentes en colecciones EAV: sólo pasan un argumento, una serie de condiciones con atributos.

añadiendo o condiciones a las colecciones de mesa plana

especificando una o filtro con un solo atributo en una colección de mesa plana es el mismo que en una colección EAV.

Ej: $col->addFieldToFilter('name', array(array('like' => 'M%'), array('like' => '%O'))); // get items whose name start with M OR end with O

para unir múltiples atributos en una o condición la sintaxis es diferente de colecciones EAV (Nota: esto se rompe en Magento 1.6)

Ej: $col->addFieldToFilter(array('weight', 'name'), array(array('in' => array(1,3)), array('like' => 'M%')));

El primer atributo se asigna a la primera condición, el segundo atributo se asigna a la segunda condición, etc.

Dado que esto se rompe en 1.6 nos queda la posibilidad de especificar equ condiciones Ality para múltiples atributos utilizando addFilter()

Ej: $col->addFilter('weight', 1, 'or')->addFilter('weight', 2, 'or')->addFilter('sku', 'ABC', 'or'); // weight is 1 or 2 or sku is ABC

siempre se puede utilizar $collection->getSelect()->orWhere(…), también, pero hay que tener cuidado con la compatibilidad entre RDBMS

Nota: se trata de una profundidad de thwo cosas he publicado hace años en Tumblr:
http://tweetorials.tumblr.com/post/10844018716/eav-collection-or-filters
http://tweetorials.tumblr.com/post/11102525164/flat-table-collection-or-filters

Cuestiones relacionadas