¿Es posible iterar sobre las colecciones de Magento con paginación de forma nativa?

21

Lo que quiero decir con eso es: ¿hay alguna manera de hacerlo?

$collection = $model->getCollection();
foreach ($collection as $item) { 
    $item->doStuff();
}

De tal manera que incluso si la colección tuviera 100k filas, solo cargaría una página de filas a la vez desde MySQL y mágicamente las paginaría detrás de escena.

De su análisis Varien_Data_Collection_Db::load()no parece como que es posible, pero sólo quería comprobar. Esto parece algo que debería ser una necesidad común.

kalenjordan
fuente

Respuestas:

18

Realmente deberías usar

Mage::getSingleton('core/resource_iterator')

para este propósito, ya que existe únicamente por las razones de rendimiento que mencionó.

De lo contrario, puede usar una solución un poco menos elegante usando un bucle con setPageSize: hay un buen ejemplo aquí, /programming/3786826/how-to-loop-a-magento-collection

Ben Lessani - Sonassi
fuente
1
Usted, señor, es un caballero y un erudito.
kalenjordan
+1 porque setPageSizeporque es semántico.
philwinkle
Otra cosa que me di cuenta es que la core/resource_iteratorsolución en realidad no pagina la consulta mysql. Carga todo el conjunto de resultados a la vez, pero luego le da una fila a la vez para tratar en su código PHP. Por lo tanto, evita fallas de memoria dentro de PHP, pero en algún momento activará el tamaño máximo de paquetes mysql, si el conjunto de resultados es muy grande. Creo que voy a tratar de construir un buen resumen de recursos en pedazos usandosetPageSize()
kalenjordan"
¡Sí, lo omití en la búsqueda de puntos de mwoar! Realmente está dirigido a la carga de un solo producto versus una colección paginada. Pero debería servir como base para construir.
Ben Lessani - Sonassi
Implementé un iterador por lotes genérico que agrupa las consultas a MySQL pero también proporciona una devolución de llamada de elemento de colección individual. Curioso lo que piensas: gist.github.com/kalenjordan/5483065
kalenjordan
5

Estoy de acuerdo con Ben Lessani que se debe utilizar el core/iteratormodelo de recursos para cargar grandes colecciones de una fila a la vez , si es posible .

Sin embargo, hay limitaciones. Como se explica en " addAttributeToSelect no funciona con core / resource_iterator? ", No funciona bien con los modelos EAV si necesita incluir valores de las tablas de valores de atributos.

Y el ejemplo vinculado de StackOverflow en realidad no es tan bueno porque repite la misma consulta con diferentes LIMITexpresiones. Para consultas complejas, esto podría ser un problema de rendimiento, pero aún más importante, obtendrá duplicados si se agregan nuevas filas en el medio.

Una mejor manera de manejar colecciones en trozos es cargar primero todos los identificadores, luego usar estos identificadores como filtro para la recopilación paginada real.

Ejemplo simple para productos:

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

$page = 1;
do {
    $collection = Mage::getModel('catalog/product')
        ->getCollection()
        ->addIdFilter($ids)
        ->setPageSize(100)
        ->setCurPage($page);

    $results = $collection->load();

    // do stuff ......

    $page++;

} while ($results->count());
Fabian Schmengler
fuente