Можно ли перебирать коллекции Magento с разбиением на страницы изначально?
Что я имею в виду под этим - есть ли способ сделать:
$collection = $model->getCollection();
foreach ($collection as $item) {
$item->doStuff();
}
Таким образом, что даже если бы в коллекции было 100 тысяч строк, она загружала бы только страницу строк за раз из MySQL и волшебным образом разбивала их на страницы для вас за кулисами.
Глядя на Varien_Data_Collection_Db::load()
, кажется, что это невозможно, но я просто хотел проверить. Это похоже на то, что должно быть общей потребностью.
2 answers
Вам действительно следует использовать
Mage::getSingleton('core/resource_iterator')
Для этой цели, поскольку она существует исключительно по причинам производительности, о которых вы упомянули.
В противном случае вы можете использовать несколько менее элегантное решение, используя цикл с setPageSize
- здесь есть хороший пример, https://stackoverflow.com/questions/3786826/how-to-loop-a-magento-collection
Я согласен с Бен Лессани, что вам следует использовать модель ресурсов core/iterator
для загрузки больших коллекций по одной строке за раз , если это возможно.
Однако существуют ограничения. Как объяснено в "addattributetoselect не работает с core/resource_iterator?" это плохо работает с моделями EAV, если вам нужно включить значения из таблиц значений атрибутов.
И связанный пример из StackOverflow на самом деле не так хорош, потому что он повторяет то же самое запрос с различными выражениями LIMIT
. Для сложных запросов это может быть проблемой с производительностью, но что еще более важно, вы получите дубликаты, если между ними будут добавлены новые строки.
Лучший способ обработки коллекций по частям - сначала загрузить все идентификаторы, а затем использовать эти идентификаторы в качестве фильтра для фактической выгружаемой коллекции.
Простой пример для продуктов:
$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());