Czy można iterować natywnie po kolekcjach Magento z paginacją?

21

Rozumiem przez to - czy istnieje sposób na:

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

W taki sposób, że nawet jeśli kolekcja ma 100 tys. Wierszy, ładuje tylko stronę wierszy naraz z MySQL i magicznie dzieli je na strony za kulisami.

Patrząc na Varien_Data_Collection_Db::load()to nie wydaje się możliwe, ale po prostu chciałem to sprawdzić. To wydaje się być czymś, co powinno być powszechną potrzebą.

kalenjordan
źródło

Odpowiedzi:

18

Powinieneś naprawdę użyć

Mage::getSingleton('core/resource_iterator')

w tym celu, ponieważ istnieje on wyłącznie ze względów wydajnościowych, o których wspomniałeś.

W przeciwnym razie możesz użyć nieco mniej eleganckiego rozwiązania za pomocą pętli z setPageSize- jest tutaj dobry przykład, /programming/3786826/how-to-loop-a-magento-collection

Ben Lessani - Sonassi
źródło
1
YOU SIR, jesteś dżentelmenem i uczonym.
kalenjordan
+1 dla, setPageSizeponieważ jest semantyczna.
philwinkle 16.04.13
Zrozumiałem też, że core/resource_iteratorrozwiązanie faktycznie nie dzieli stronicowania zapytania mysql. Ładuje cały zestaw wyników naraz, ale następnie daje ci wiersz do zrobienia w kodzie PHP. Dzięki temu unika się błędów pamięci w PHP, ale w pewnym momencie wyzwoli maksymalne rozmiary pakietów mysql, jeśli zestaw wyników jest bardzo duży. Myślę, że spróbuję zbudować ładny abstrakcyjny setPageSize()
fragmentaryczny zasobnik_iteratora
Tak, w pewnym sensie pominąłem to w pogoni za punktami mwoar! Jego celem jest ładowanie pojedynczego produktu w porównaniu do stronicowanej kolekcji. Ale powinien służyć jako baza do budowania.
Ben Lessani - Sonassi
Zaimplementowałem ogólny iterator wsadowy, który grupuje zapytania do MySQL, ale zapewnia także wywołanie zwrotne pojedynczego elementu kolekcji. Ciekawe, co myślisz: gist.github.com/kalenjordan/5483065
kalenjordan
5

Zgadzam się z Benem Lessani , że należy używać core/iteratormodelu zasobów, aby ładować duże kolekcje jeden wiersz na raz, jeśli to możliwe .

Istnieją jednak ograniczenia. Jak wyjaśniono w „ addAttributeToSelect nie działa z core / resource_iterator? ”, Nie działa dobrze z modelami EAV, jeśli chcesz dołączyć wartości z tabel wartości atrybutów.

A połączony przykład StackOverflow nie jest tak dobry, ponieważ powtarza to samo zapytanie z różnymi LIMITwyrażeniami. W przypadku złożonych zapytań może to być problem z wydajnością, ale co ważniejsze, otrzymasz duplikaty, jeśli pomiędzy nimi zostaną dodane nowe wiersze.

Lepszym sposobem obsługi kolekcji w porcjach jest najpierw załadowanie wszystkich identyfikatorów, a następnie użycie tych identyfikatorów jako filtrów dla faktycznej kolekcji stronicowanej.

Prosty przykład dla produktów:

$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
źródło