From 5b7d7861aa60d57de4c2148fad195e57102d1c62 Mon Sep 17 00:00:00 2001 From: Samuele Mancuso Date: Mon, 8 Jun 2026 11:41:00 +0200 Subject: [PATCH 1/5] perf(import): read each CSV batch in a single pass; add getTotalRows() getRows() called league/csv fetchOne($offset+$i) in a loop, and fetchOne re-scans the file from the start on every call, making imports O(n^2) (~12.5M line-parses for 5000 rows). Read each batch once via Statement::offset()->limit(). Add getTotalRows() so the UI can compute import progress. --- src/Importer/CSVImporter.php | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Importer/CSVImporter.php b/src/Importer/CSVImporter.php index b98496869..904464f54 100644 --- a/src/Importer/CSVImporter.php +++ b/src/Importer/CSVImporter.php @@ -21,6 +21,7 @@ namespace Importer; use League\Csv\Reader; +use League\Csv\Statement; /** * Classe dedicata alla gestione dell'importazione da file CSV. @@ -96,17 +97,24 @@ public function getHeader() return array_shift($first_row); } + /** + * Numero totale di record presenti nel file CSV (intestazione inclusa). + * Usato dalla UI per calcolare la percentuale di avanzamento dell'importazione. + */ + public function getTotalRows() + { + return count($this->csv); + } + public function getRows($offset, $length) { $rows = []; - for ($i = 0; $i < $length; ++$i) { - // Lettura di una singola riga alla volta - $row = $this->csv->fetchOne($offset + $i); - if (empty($row)) { - break; - } - // Aggiunta all'insieme dei record + // Lettura del blocco in un'unica passata sequenziale. + // NB: chiamare fetchOne($offset + $i) in un ciclo è O(n²), perché league/csv + // ri-scorre il file dall'inizio ad ogni chiamata; Statement lo scorre una sola volta. + $statement = Statement::create()->offset((int) $offset)->limit((int) $length); + foreach ($statement->process($this->csv) as $row) { $rows[] = \Filter::parse($row); } @@ -170,8 +178,10 @@ public function importRows($offset, $length, $update_record = true, $add_record $validated_records[] = $record; } - $batch_size = 100; $import_failed = 0; + + // Autocommit per riga (volutamente NON in un'unica transazione per batch): così i lock + // restano brevissimi e un import lento/abbandonato non blocca l'intera applicazione. foreach ($validated_records as $index => $record) { $row = $validated_rows[$index]; From e515ba2d4d7ce0510209b859edef8da2d67aa00b Mon Sep 17 00:00:00 2001 From: Samuele Mancuso Date: Mon, 8 Jun 2026 11:41:00 +0200 Subject: [PATCH 2/5] perf(import): reduce import batch size from 500 to 100 rows Shorter per-request work (less risk of proxy/PHP timeouts on large files) and more frequent progress updates. --- modules/import/actions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/import/actions.php b/modules/import/actions.php index 8304e25c5..a60ecf83c 100755 --- a/modules/import/actions.php +++ b/modules/import/actions.php @@ -88,7 +88,8 @@ $fields = (array) post('fields'); $page = post('page'); - $limit = 500; + // Batch piccolo: richieste brevi (margine sui timeout/504) e progress più fluida + $limit = 100; // Inizializzazione del lettore CSV $filepath = base_dir().'/files/'.$record->directory.'/'.$record->filename; From bd828c9557042046f4be6642a57e8ee25a254410 Mon Sep 17 00:00:00 2001 From: Samuele Mancuso Date: Mon, 8 Jun 2026 11:41:00 +0200 Subject: [PATCH 3/5] feat(import): progress bar overlay and human-readable error messages Replace the full-screen spinner with a progress overlay that updates after each batch (processed/total rows + percentage). Show the actual server error instead of '[object Object]' when an import request fails. --- modules/import/edit.php | 54 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/modules/import/edit.php b/modules/import/edit.php index ad9a7b874..05ca9fd33 100755 --- a/modules/import/edit.php +++ b/modules/import/edit.php @@ -234,10 +234,34 @@ '; + // Totale record del CSV (intestazione inclusa): serve alla progress bar lato client + $totale_record = $csv->getTotalRows(); + + echo ' +'; + echo '