У меня есть коллекция MongoDB с несколькими тысячами записей, которые я хотел бы загрузить как CSV файл.
У меня есть код, который в основном делает следующее: Метод контроллера запрашивает базу данных с использованием Doctrine ODM для всех записей. Возвращенный курсор затем подается в StreamedResponse. В StreamedResponse я петля над курсором и вывод каждой записи в виде строки в CSV.
Следующий код работает, и файл загружается. Только он содержит не более 60 строк. Что может быть причиной того, что он прекращает потоковое воспроизведение в этой точке, а количество курсоров указывает, что есть 2670 результатов?
// Get all available bookings
$cursor = $this
->get('doctrine_mongodb')
->getRepository('FooBundle:Booking')
->getQueryBuilder()
->getQuery()
->execute();
$response = new StreamedResponse(function () use ($cursor) {
$handle = fopen('php://output', 'r+');
$headerPrinted = false;
// Calling $cursor->count() here returns 2670
foreach ($cursor as $result) {
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
}
fclose($handle);
});
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', 'attachment; filename="bookings.csv"');
return $response;
И насколько я вижу, нет кода, который накапливает данные в памяти во время потоковой передачи. Я использую Symfony 2.7, Doctrine MongoDB ODM 1.0.3 и PHP 5.5.9 с memory_limit из 256M.
Как описано в комментарии, проблема связана с недиратируемым объектом на результат от курсора. Чтобы поймать исключение и записать правильные данные, вы можете поймать исключение. Цикл необходимо переписать для исключения исключения. В качестве примера вы можете сделать цикл while следующим образом:
do {
try
{
// this could rise an exception
$result = $cursor->getNext()
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
} catch (\Exception $e)
{
// do nothing and process next element
}
}
while($cursor->hasNext())
Я бы предложил также использовать библиотеку для управления написанием CSV, например:
надеюсь эта помощь
Похоже, что это связано с ограничением вашей памяти в php.ini
ini_set ( 'memory_limit', '16M');
Ударьте вверх и посмотрите, сколько строк вы получаете
Doctrine\ODM\MongoDB\DocumentNotFoundException
. Видимо ссылочный документ был удален без удаления ссылки из объекта бронирования. Я думаю, что решение этой проблемы поможет решить мою проблему. :)