2011-04-15 12 views
6

Las funciones de clasificación de la colección Magento (por ejemplo, Mage_Eav_Model_Entity_Collection_Abstract::addAttributeToSort) funcionan agregando una cláusula ORDER BY a la declaración de selección de SQL. Sin embargo, hay ocasiones en que ya se ha cargado una colección y es necesario ordenar la colección.ordena la colección Magento DESPUÉS de la carga

Es ciertamente posible utilizar la función toArray($fields) y luego las funciones de clasificación de arreglos de PHP (ya sean nativas o definidas por el usuario), sin embargo, esto es un poco torpe. También significa que los objetos en la colección se convierten en filas "tontas" de valores sin magic getters/setters que pueden/son implementados con algoritmos, etc.

Me pregunto si hay más elegantes/Magento- esque métodos de clasificación de la colección.

Gracias,
Jonathan

+0

Así que básicamente lo que se está preguntando es si ya tiene una colección ordenada por uno de los atributos de nuevo quiere ordenar por otro atributo ..? –

+0

@SubeshPokhrel sí, pero ese no es el problema clave. La cuestión clave es ordenar la colección por un atributo DESPUÉS de que se hayan completado los $ _items internos de la colección (es decir, después de la ejecución de SQL) –

+0

¿Por qué no agrega otra consulta de ordenamiento a la colección para poder clasificar por dos atributos y usted obtener colección ordenada con dos atributos ..? O me estoy perdiendo el punto entero. –

Respuesta

2

Otra solución que funciona:

class Aligent_Navigation_Block_Dropdown extends Mage_Catalog_Block_Product_List { 

public function getProductsByShortDesc(){ 
    $data = $this->getLoadedProductCollection()->getItems(); //an array of objects 
    usort($data,array('Aligent_Navigation_Block_Dropdown','sortByShortDesc')); 
    return $data; 
} 

public static function sortByShortDesc($a, $b) 
{ 
    if($a->getShortDescription() == $b->getShortDescription()){ return 0 ; } 
    return ($a->getShortDescription() < $b->getShortDescription()) ? -1 : 1; 
} 
} 
+0

El único problema con esta solución es si tiene varias páginas, entonces esto ordenaría solo los elementos en esta página –

11

No hay manera correcta de hacerlo. Pero creo que es posible con el uso de Reflection. Puede recuperar la propiedad $ _items del objeto de colección, ordenarlos y volver a establecerlos en la colección.

function sortCollection(Varien_Data_Collection $collection, callable $sorter) { 
    $collectionReflection = new ReflectionObject($collection); 
    $itemsPropertyReflection = $collectionReflection->getProperty('_items'); 
    $itemsPropertyReflection->setAccessible(true); // Make it accessible 

    $collectionItems = $itemsPropertyReflection->getValue($collection); 

    usort($collectionItems, $sorter); 

    $itemsPropertyReflection->setValue($collection, $collectionItems); 

    $itemsPropertyReflection->setAccessible(false); // Return restriction back 

    return $collection; 
} 
+0

parece interesante, lo comprobaré, gracias Ivan –

+3

Confirmo que es posible Ivan, mi compañero solo usa tu fragmento con éxito. Lo único es que en lugar de '$ collection-> getProperty ('_ items');' tenía que usar '$ collectionReflection-> getProperty ('_ items');', un pequeño error tipográfico, supongo.Otra cosa que creo que vale la pena contar es que, como estamos hablando de Magento, y por lo tanto de las Clases, '$ yourSortingCallback' tiene que ser una matriz de 2 elementos, el primero es el nombre de la clase donde se define el método, y el segundo es el nombre del método, es decir: 'usort ($ collectionItems, array ('The_Class', 'The_Method'));'. De todos modos, ambos estamos muy agradecidos, – OSdave

+0

@OSdave, sí, había un tipo. $ yourSortingCallback call back puede ser incluso una función anónima. –

4

Aquí hay un consejo; El método clear de una colección desactivó su indicador de carga, le permite cambiar el género o los filtros y ejecutar la nueva consulta.

Lo descubrí accidentalmente al responder load only configurable products.

+0

¡es increíble, muy útil! –

+0

y, por supuesto, significa que también puede agregarAttributeToSelect(), que era justo con lo que estaba luchando, gracias :-) – benz001

0

La solución anterior funciona bien, pero es mucho más lento y más intensa que la adición de la clase a la propia consulta.

Si tiene una gran colección, usará una gran cantidad de memoria ya que necesita cargar un objeto (u objetos) para cada resultado y almacenarlos todos.

El uso de la colección de Magento sólo cargará una fila a la vez de la base de datos que va a ser mucho más eficiente que la solución anterior :-)

1

El método de @Ivan Chepurnyi funcionó, pero devuelve un objeto ReflectionObject, en mi caso, necesitaba una Varien_Data_Collection.
Aquí es lo que hice en lugar

$collectionItems = $collection->getItems(); 
usort($collectionItems, array($this, '_sortItems')); 
$newCollection = new Varien_Data_Collection(); 

foreach ($collectionItems as $item) { 
    $newCollection->addItem($item); 
} 

var_dump($newCollection); 

Y en caso de aquí es el método de clasificación

public function _sortItems($a, $b) 
{ 
    $columnId = "your_column_that_you_need_to_sort"; 
    $dir  = "desc"; 

    $al = strtolower($a->getData($columnId)); 
    $bl = strtolower($b->getData($columnId)); 

    if ($al == $bl) { 
     return 0; 
    } 

    if ($dir == 'asc') { 
     return ($al < $bl) ? -1 : 1; 
    } else { 
     return ($al > $bl) ? -1 : 1; 
    } 
} 
Cuestiones relacionadas