
Generar i descarregar un csv de forma eficient a Drupal
Hi ha diverses estratègies per fer-ho, però sovint els programadors es fan alguna funció per agafar les dades de la base de dades, una altra per generar el csv, i potser alguna altra per servir-lo al client.
Al principi tot va bé, però donat que el volum de dades acostuma a créixer amb el temps arriba un moment que se'ls hi omple la memòria o els hi salten els timeouts, etc. I ens demanen als de sistemes que augmentem els recursos quan tot és culpa d'una mala estratègia.
Una solució és partir la tasca, generar el fitxer en bach i després oferir el resultat per descarregar.
Però i si hi hagués una solució millor? I si al mateix temps que llegim la base de dades anem generant el csv al mateix temps que ho servim al client?
Provem-ho amb la ajuda dels generators:
Ens creem un generator per llegir la bbdd:
public function getInvoices(string $startDate, string $endDate): Iterator {
$results = $this->connection->select('invoices', 'i')
->fields('i')
->condition('date', [$startDate, $endDate], 'BETWEEN')
->execute();
while (($record = $results->fetchObject())) {
yield $record;
}
}
Tot seguit al nostre controller, escrivim el csv directament a la sortida:
public function __invoke($from, $to): Response {
$headers = [
'Content-Disposition' => sprintf('attachment; filename="invoices-%s-%s.csv"', $from, $to),
'Content-Type' => 'text/csv',
'Cache-Control' => 'max-age=0',
];
$invoices = $this->invoices->getInvoices($from, $to);
return new StreamedResponse(function () use ($invoices) {
$output = fopen('php://output', 'w');
$fields = [
'date',
'quantity',
'net',
'discount',
'invoice_number',
'invoice_item',
];
// Afegim BOM UTF-8 per compatibilitat amb Excel
fwrite($output, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($output, $fields, ';');
foreach ($invoices as $invoice) {
$row = array_map(fn($field) => $invoice->{$field}, $fields);
fputcsv($output, $row, ';');
}
fclose($output);
}, Response::HTTP_OK, $headers);
}
I voilà, el csv se'ns comença a descarregar instantàniament i el servidor quasi ni s'entera.
- Inicia sessió o registra't per fer comentaris
Comentaris