@@ -48,9 +48,11 @@ class ImportService extends SuperService {
4848 private ?int $ viewId = null ;
4949 private array $ columns = [];
5050 private bool $ createUnknownColumns = true ;
51+ private ?int $ idColumnIndex = null ;
5152 private int $ countMatchingColumns = 0 ;
5253 private int $ countCreatedColumns = 0 ;
5354 private int $ countInsertedRows = 0 ;
55+ private int $ countUpdatedRows = 0 ;
5456 private int $ countErrors = 0 ;
5557 private int $ countParsingErrors = 0 ;
5658
@@ -136,14 +138,19 @@ private function getPreviewData(Worksheet $worksheet): array {
136138 $ column = $ this ->columns [$ colIndex ];
137139 $ columns [] = $ column ;
138140 } else {
139- $ columns [] = [
141+ $ column = [
140142 'title ' => $ title ,
141143 'type ' => $ this ->rawColumnDataTypes [$ colIndex ]['type ' ],
142144 'subtype ' => $ this ->rawColumnDataTypes [$ colIndex ]['subtype ' ] ?? null ,
143145 'numberDecimals ' => $ this ->rawColumnDataTypes [$ colIndex ]['number_decimals ' ] ?? 0 ,
144146 'numberPrefix ' => $ this ->rawColumnDataTypes [$ colIndex ]['number_prefix ' ] ?? '' ,
145147 'numberSuffix ' => $ this ->rawColumnDataTypes [$ colIndex ]['number_suffix ' ] ?? '' ,
146148 ];
149+ if (mb_strtolower ($ title ) === Column::META_ID_TITLE ) {
150+ $ column ['id ' ] = Column::TYPE_META_ID ;
151+ }
152+
153+ $ columns [] = $ column ;
147154 }
148155 }
149156
@@ -304,6 +311,7 @@ public function import(?int $tableId, ?int $viewId, string $path, bool $createMi
304311 'matching_columns_count ' => $ this ->countMatchingColumns ,
305312 'created_columns_count ' => $ this ->countCreatedColumns ,
306313 'inserted_rows_count ' => $ this ->countInsertedRows ,
314+ 'updated_rows_count ' => $ this ->countUpdatedRows ,
307315 'errors_parsing_count ' => $ this ->countParsingErrors ,
308316 'errors_count ' => $ this ->countErrors ,
309317 ];
@@ -334,7 +342,7 @@ private function loop(Worksheet $worksheet): void {
334342
335343 foreach ($ worksheet ->getRowIterator (2 ) as $ row ) {
336344 // parse row data
337- $ this ->createRow ($ row );
345+ $ this ->upsertRow ($ row );
338346 }
339347 }
340348
@@ -367,25 +375,46 @@ private function parseValueByColumnType(string $value, Column $column): string {
367375 * @throws MultipleObjectsReturnedException
368376 * @throws NotFoundError
369377 */
370- private function createRow (Row $ row ): void {
378+ private function upsertRow (Row $ row ): void {
371379 $ cellIterator = $ row ->getCellIterator ();
372380 $ cellIterator ->setIterateOnlyExistingCells (false );
373381
374382 try {
375383 $ i = -1 ;
376384 $ data = [];
377385 $ hasData = false ;
386+ $ id = null ;
378387 foreach ($ cellIterator as $ cell ) {
379388 $ i ++;
380389
390+ if ($ this ->idColumnIndex !== null && $ i === $ this ->idColumnIndex ) {
391+ // if this is the ID column, we need to get the ID from the cell
392+ if ($ cell && $ cell ->getValue () !== null ) {
393+ $ id = $ cell ->getValue ();
394+ }
395+ if ($ id !== null && !is_numeric ($ id )) {
396+ $ this ->logger ->warning ('ID column value is not numeric: ' . $ id );
397+ $ this ->countErrors ++;
398+ return ;
399+ }
400+ $ id = (int )$ id ;
401+ continue ;
402+ }
403+
404+ $ columnKey = $ i ;
405+ if ($ this ->idColumnIndex !== null && $ i > $ this ->idColumnIndex ) {
406+ // if we have an ID column, we need to adjust the index
407+ $ columnKey = $ i - 1 ;
408+ }
409+
381410 // only add the dataset if column is known
382- if (!isset ($ this ->columns [$ i ]) || $ this ->columns [$ i ] === '' ) {
411+ if (!isset ($ this ->columns [$ columnKey ]) || $ this ->columns [$ columnKey ] === '' ) {
383412 $ this ->logger ->debug ('Column unknown while fetching rows data for importing. ' );
384413 continue ;
385414 }
386415
387416 /** @var Column $column */
388- $ column = $ this ->columns [$ i ];
417+ $ column = $ this ->columns [$ columnKey ];
389418
390419 // if cell is empty
391420 if (!$ cell || $ cell ->getValue () === null ) {
@@ -426,26 +455,36 @@ private function createRow(Row $row): void {
426455 ];
427456 }
428457
429- if ($ hasData ) {
430- $ this ->rowService ->create ($ this ->tableId , $ this ->viewId , $ data );
431- $ this ->countInsertedRows ++;
432- } else {
458+ if (!$ hasData ) {
433459 $ this ->logger ->debug ('Skipped empty row ' . $ row ->getRowIndex () . ' during import ' );
460+ return ;
461+ }
462+
463+ if ($ id ) {
464+ try {
465+ $ this ->rowService ->updateSet ($ id , $ this ->viewId , $ data , $ this ->userId );
466+ $ this ->countUpdatedRows ++;
467+ return ;
468+ } catch (\Throwable $ e ) {
469+ $ this ->logger ->warning ('Error while updating row for import. ' , ['row_id ' => $ id , 'exception ' => $ e ]);
470+ }
434471 }
472+
473+ $ this ->rowService ->create ($ this ->tableId , $ this ->viewId , $ data );
474+ $ this ->countInsertedRows ++;
435475 } catch (PermissionError $ e ) {
436- $ this ->logger ->error ('Could not create row while importing, no permission. ' , ['exception ' => $ e ]);
476+ $ this ->logger ->error ('Could not create/update row while importing, no permission. ' , ['exception ' => $ e ]);
437477 $ this ->countErrors ++;
438478 } catch (InternalError $ e ) {
439- $ this ->logger ->error ('Error while creating new row for import. ' , ['exception ' => $ e ]);
479+ $ this ->logger ->error ('Error while creating/updating new row for import. ' , ['exception ' => $ e ]);
440480 $ this ->countErrors ++;
441481 } catch (NotFoundError $ e ) {
442482 $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e ]);
443- throw new NotFoundError (get_class ($ this ) . ' - ' . __FUNCTION__ . ': ' . $ e ->getMessage ());
483+ throw new NotFoundError (get_class ($ this ) . ' - ' . __FUNCTION__ . ': ' . $ e ->getMessage (), 0 , $ e );
444484 } catch (\Throwable $ e ) {
445485 $ this ->countErrors ++;
446- $ this ->logger ->error ('Error while creating new row for import. ' , ['exception ' => $ e ]);
486+ $ this ->logger ->error ('Error while creating/updating new row for import. ' , ['exception ' => $ e ]);
447487 }
448-
449488 }
450489
451490 private function valueToDateTimeImmutable (mixed $ value ): ?\DateTimeImmutable {
@@ -502,9 +541,23 @@ private function getColumns(Row $firstRow, Row $secondRow): void {
502541 if ($ cell && $ cell ->getValue () !== null && $ cell ->getValue () !== '' ) {
503542 $ title = $ cell ->getValue ();
504543
544+ if (!$ this ->columnsConfig && mb_strtolower ($ title ) === Column::META_ID_TITLE ) {
545+ $ this ->idColumnIndex = $ index ;
546+ $ secondRowCellIterator ->next ();
547+ $ index ++;
548+ continue ;
549+ }
505550 if (isset ($ this ->columnsConfig [$ index ]) && $ this ->columnsConfig [$ index ]['action ' ] === 'exist ' && $ this ->columnsConfig [$ index ]['existColumn ' ]) {
506551 $ title = $ this ->columnsConfig [$ index ]['existColumn ' ]['label ' ];
507552 $ countMatchingColumnsFromConfig ++;
553+
554+ // no need to create the ID (Meta) column as it used for update
555+ if ($ this ->columnsConfig [$ index ]['existColumn ' ]['id ' ] === Column::TYPE_META_ID ) {
556+ $ this ->idColumnIndex = $ index ;
557+ $ secondRowCellIterator ->next ();
558+ $ index ++;
559+ continue ;
560+ }
508561 }
509562 if (isset ($ this ->columnsConfig [$ index ]) && $ this ->columnsConfig [$ index ]['action ' ] === 'new ' && $ this ->createUnknownColumns ) {
510563 $ column = $ this ->columnService ->create (
0 commit comments