É possível iterar sobre as coleções do Magento com paginação nativamente?

21

O que quero dizer com isso é - existe uma maneira de fazer:

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

De tal maneira que, mesmo que a coleção tivesse 100 mil linhas, ela carregaria apenas uma página de linhas por vez no MySQL e as paginaria magicamente para você nos bastidores.

Ao olhar para Varien_Data_Collection_Db::load()ele, não parece possível, mas só queria verificar. Parece algo que deve ser uma necessidade comum.

kalenjordan
fonte

Respostas:

18

Você realmente deveria usar

Mage::getSingleton('core/resource_iterator')

para esse fim, pois existe apenas pelos motivos de desempenho mencionados.

Caso contrário, você pode usar uma solução um pouco menos elegante usando um loop com setPageSize- há um bom exemplo aqui, /programming/3786826/how-to-loop-a-magento-collection

Ben Lessani - Sonassi
fonte
1
O senhor é um cavalheiro e um estudioso.
kalenjordan
+1 para setPageSizeporque é semântico.
philwinkle
Outra coisa que percebi é que a core/resource_iteratorsolução realmente não pagina a consulta mysql. Carrega todo o conjunto de resultados de uma só vez, mas, em seguida, fornece uma linha de cada vez para lidar com seu código PHP. Portanto, evita falhas de memória no PHP, mas em algum momento acionará o tamanho máximo do pacote mysql, se o conjunto de resultados for muito grande. Eu acho que estou indo para tentar construir um resource_iterator Chunked abstrata agradável usandosetPageSize()
kalenjordan
Sim, eu meio que omiti isso em busca de pontos de mwoar! Ele realmente visa o carregamento de um único produto em comparação a uma coleção paginada. Mas deve servir de base para a construção.
precisa saber é o seguinte
Eu implementei um iterador em lote genérico que agrupa as consultas no MySQL, mas também fornece um retorno de chamada de item de coleção individual. Curioso o que você pensa: gist.github.com/kalenjordan/5483065
kalenjordan
5

Concordo com Ben Lessani que você deve usar o core/iteratormodelo de recursos para carregar grandes coleções uma linha por vez, se possível .

No entanto, existem limitações. Conforme explicado em " addAttributeToSelect não está funcionando com core / resource_iterator? ", Ele não funciona bem com modelos EAV se você precisar incluir valores das tabelas de valores de atributos.

E o exemplo vinculado do StackOverflow na verdade não é tão bom porque repete a mesma consulta com LIMITexpressões diferentes . Para consultas complexas, isso pode ser um problema de desempenho, mas ainda mais importante, você receberá duplicatas se novas linhas forem adicionadas.

Uma maneira melhor de lidar com coleções em blocos é primeiro carregar todos os IDs e depois usá-los como um filtro para a coleção paginada real.

Exemplo simples para produtos:

$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
fonte