Apakah mungkin untuk mengulangi koleksi Magento dengan pagination secara asli?

21

Yang saya maksud dengan itu - apakah ada cara untuk melakukannya:

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

Sedemikian rupa sehingga bahkan jika koleksi memiliki 100 ribu baris, itu hanya akan memuat satu halaman baris pada satu waktu dari MySQL dan secara ajaib paginasi mereka untuk Anda di belakang layar.

Dari melihat Varien_Data_Collection_Db::load()itu sepertinya tidak mungkin, tetapi hanya ingin memeriksanya. Ini sepertinya sesuatu yang harus menjadi kebutuhan bersama.

kalenjordan
sumber

Jawaban:

18

Anda harus benar-benar menggunakannya

Mage::getSingleton('core/resource_iterator')

untuk tujuan ini, karena ada semata-mata karena alasan kinerja yang Anda sebutkan.

Jika tidak, Anda dapat menggunakan solusi yang sedikit kurang elegan menggunakan loop dengan setPageSize- ada contoh yang baik di sini, /programming/3786826/how-to-loop-a-magento-collection

Ben Lessani - Sonassi
sumber
1
ANDA SIR, adalah seorang pria dan sarjana.
kalenjordan
+1 untuk setPageSizekarena semantik.
philwinkle
Hal lain yang saya sadari adalah bahwa core/resource_iteratorsolusi tersebut sebenarnya tidak memberi peringkat pada permintaan mysql. Ini memuat seluruh hasil yang ditetapkan sekaligus, tetapi kemudian memberi Anda satu baris pada satu waktu untuk berurusan dengan kode PHP Anda. Jadi itu menghindari kesalahan memori dalam PHP, tetapi pada beberapa titik itu akan memicu ukuran paket mysql max, jika hasil yang ditetapkan sangat besar. Saya pikir saya akan mencoba dan membangun resource_iterator chunked abstrak yang bagus menggunakansetPageSize()
kalenjordan
Ya, saya agak lupa bahwa dalam mengejar poin mwoar! Ini benar-benar ditujukan untuk memuat produk tunggal versus koleksi paginasi. Tetapi harus berfungsi sebagai dasar untuk membangun.
Ben Lessani - Sonassi
Saya menerapkan iterator bets umum yang batch permintaan untuk MySQL tetapi juga menyediakan callback item koleksi individual. Ingin tahu apa yang Anda pikirkan: gist.github.com/kalenjordan/5483065
kalenjordan
5

Saya setuju dengan Ben Lessani bahwa Anda harus menggunakan core/iteratormodel sumber daya untuk memuat koleksi besar satu baris setiap kali jika memungkinkan .

Namun, ada batasannya. Seperti dijelaskan dalam " addAttributeToSelect tidak bekerja dengan core / resource_iterator? " Itu tidak berfungsi dengan baik dengan model EAV jika Anda perlu memasukkan nilai dari tabel nilai atribut.

Dan contoh yang ditautkan dari StackOverflow sebenarnya tidak begitu bagus karena mengulangi permintaan yang sama dengan LIMITekspresi yang berbeda . Untuk kueri kompleks, ini mungkin masalah kinerja, tetapi yang lebih penting, Anda akan mendapatkan duplikat jika baris baru ditambahkan di antaranya.

Cara yang lebih baik untuk menangani koleksi dalam potongan adalah dengan terlebih dahulu memuat semua id, kemudian gunakan id ini sebagai filter untuk koleksi halaman yang sebenarnya.

Contoh sederhana untuk produk:

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