diff --git a/httpdocs/composer.json b/httpdocs/composer.json index 02ea9a0..954d38e 100644 --- a/httpdocs/composer.json +++ b/httpdocs/composer.json @@ -16,6 +16,7 @@ "lexik/jwt-authentication-bundle": "^3.1", "nelmio/cors-bundle": "^2.5", "phpdocumentor/reflection-docblock": "^5.4", + "phpoffice/phpspreadsheet": "^4.2", "phpstan/phpdoc-parser": "^1.32", "symfony/asset": "7.1.*", "symfony/console": "7.1.*", diff --git a/httpdocs/composer.lock b/httpdocs/composer.lock index ba6925c..c9275b5 100644 --- a/httpdocs/composer.lock +++ b/httpdocs/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1d97e4496ebfcc30dce08cc0102bd47e", + "content-hash": "c2075b4a00e7b723574dd47fae79eef2", "packages": [ { "name": "api-platform/doctrine-common", @@ -1112,6 +1112,85 @@ }, "time": "2025-03-10T10:30:30+00:00" }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, { "name": "doctrine/cache", "version": "2.2.0", @@ -2742,6 +2821,191 @@ ], "time": "2024-07-03T20:49:59+00:00" }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.2" + }, + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^11.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2025-01-27T12:07:53+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, { "name": "nelmio/cors-bundle", "version": "2.5.0", @@ -2979,6 +3243,112 @@ }, "time": "2024-02-23T11:10:43+00:00" }, + { + "name": "phpoffice/phpspreadsheet", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "5f6d7410e5fd72cac1aa67d4f05f4fe664d01ba6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/5f6d7410e5fd72cac1aa67d4f05f4fe664d01ba6", + "reference": "5f6d7410e5fd72cac1aa67d4f05f4fe664d01ba6", + "shasum": "" + }, + "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^8.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1 || ^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0", + "phpstan/phpstan-phpunit": "^1.0 || ^2.0", + "phpunit/phpunit": "^10.5", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/4.2.0" + }, + "time": "2025-04-17T02:41:45+00:00" + }, { "name": "phpstan/phpdoc-parser", "version": "1.32.0", @@ -3226,6 +3596,166 @@ }, "time": "2019-01-08T18:20:26+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, { "name": "psr/link", "version": "2.0.1", @@ -3332,6 +3862,57 @@ }, "time": "2024-09-11T13:17:53+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "symfony/asset", "version": "v7.1.1", diff --git a/httpdocs/import/Import-Template.xlsx b/httpdocs/import/Import-Template.xlsx new file mode 100644 index 0000000..46d8bc3 Binary files /dev/null and b/httpdocs/import/Import-Template.xlsx differ diff --git a/httpdocs/src/Command/Import/ImportExcelCommand.php b/httpdocs/src/Command/Import/ImportExcelCommand.php new file mode 100644 index 0000000..af1be00 --- /dev/null +++ b/httpdocs/src/Command/Import/ImportExcelCommand.php @@ -0,0 +1,359 @@ +params->get('kernel.project_dir') . '/import/Import-Template.xlsx'; + + if (!file_exists($filePath)) { + $io->error('Excel file not found: ' . $filePath); + return Command::FAILURE; + } + + // Starte Transaktion + $this->entityManager->beginTransaction(); + + try { + $io->title('Starting Excel Import'); + + // Lade die Excel-Datei + $spreadsheet = IOFactory::load($filePath); + + // Importiere in der richtigen Reihenfolge (Abhängigkeiten beachten) + $this->importZones($spreadsheet, $io); + $this->entityManager->flush(); // Flush nach Zones + + $this->importLocations($spreadsheet, $io); + $this->entityManager->flush(); // Flush nach Locations + + $this->importShippingCompanies($spreadsheet, $io); + $this->entityManager->flush(); // Flush nach ShippingCompanies + + $this->importVessels($spreadsheet, $io); + $this->entityManager->flush(); // Flush nach Vessels + + $this->importTrips($spreadsheet, $io); + $this->entityManager->flush(); // Finaler Flush + + // Commit Transaktion bei Erfolg + $this->entityManager->commit(); + + $io->success('Excel import completed successfully!'); + return Command::SUCCESS; + + } catch (\Exception $e) { + // Rollback bei Fehler + $this->entityManager->rollback(); + + $io->error('Import failed: ' . $e->getMessage()); + return Command::FAILURE; + } + } + + private function importZones($spreadsheet, SymfonyStyle $io): void + { + $io->section('Importing Zones'); + + $sheet = $spreadsheet->getSheetByName('zones'); + if (!$sheet) { + $io->warning('Sheet "zones" not found'); + return; + } + + $rows = $sheet->toArray(); + $headers = array_shift($rows); + + $count = 0; + foreach ($rows as $row) { + $data = array_combine($headers, $row); + + // Prüfe, ob Zone bereits existiert + $existingZone = $this->entityManager->getRepository(Zone::class) + ->findOneBy(['name' => $data['name']]); + + if (!$existingZone) { + $zone = new Zone($data['name']); + + $this->entityManager->persist($zone); + $count++; + } + } + + $io->success("Imported $count zones"); + } + + private function importLocations($spreadsheet, SymfonyStyle $io): void + { + $io->section('Importing Locations'); + + $sheet = $spreadsheet->getSheetByName('locations'); + if (!$sheet) { + $io->warning('Sheet "locations" not found'); + return; + } + + $rows = $sheet->toArray(); + $headers = array_shift($rows); + + $count = 0; + foreach ($rows as $row) { + $data = array_combine($headers, $row); + + // Prüfe, ob Location bereits existiert + $existingLocation = $this->entityManager->getRepository(Location::class) + ->findOneBy(['name' => $data['name']]); + + if (!$existingLocation) { + // Finde die zugehörige Zone + $zone = $this->entityManager->getRepository(Zone::class) + ->findOneBy(['name' => $data['zone']]); + + if ($zone) { + // Generiere einen Code aus dem Namen (oder verwenden Sie Ihre eigene Logik) + $code = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', $data['name']), 0, 3)); + + $location = new Location($zone, $data['name'], $code); + + $this->entityManager->persist($location); + $count++; + } else { + $io->warning("Zone '{$data['zone']}' not found for location '{$data['name']}'"); + } + } + } + + $io->success("Imported $count locations"); + } + + private function importShippingCompanies($spreadsheet, SymfonyStyle $io): void + { + $io->section('Importing Shipping Companies'); + + $sheet = $spreadsheet->getSheetByName('shipping_companies'); + if (!$sheet) { + $io->warning('Sheet "shipping_companies" not found'); + return; + } + + $rows = $sheet->toArray(); + $headers = array_shift($rows); + + $count = 0; + foreach ($rows as $row) { + $data = array_combine($headers, $row); + + // Prüfe, ob ShippingCompany bereits existiert + $existingCompany = $this->entityManager->getRepository(ShippingCompany::class) + ->findOneBy(['code' => $data['code']]); + + if (!$existingCompany) { + $company = new ShippingCompany($data['name'], $data['code']); + + $this->entityManager->persist($company); + $count++; + } + } + + $io->success("Imported $count shipping companies"); + } + + private function importVessels($spreadsheet, SymfonyStyle $io): void + { + $io->section('Importing Vessels'); + + $sheet = $spreadsheet->getSheetByName('vessel'); + if (!$sheet) { + $io->warning('Sheet "vessel" not found'); + return; + } + + $rows = $sheet->toArray(); + $headers = array_shift($rows); + + $count = 0; + foreach ($rows as $row) { + $data = array_combine($headers, $row); + + // Prüfe, ob Vessel bereits existiert + $existingVessel = $this->entityManager->getRepository(Vessel::class) + ->findOneBy(['code' => $data['code']]); + + if (!$existingVessel) { + // Finde die zugehörige Shipping Company + $company = $this->entityManager->getRepository(ShippingCompany::class) + ->findOneBy(['name' => $data['shipping_company']]); + + if ($company) { + $vessel = new Vessel($company, $data['name'], $data['code']); + + // Setze optionale Felder + if (isset($data['length'])) { + $vessel->setLength((float)$data['length']); + } + if (isset($data['breadth'])) { + $vessel->setBreadth((float)$data['breadth']); + } + if (isset($data['draft'])) { + $vessel->setDraft((float)$data['draft']); + } + if (isset($data['gross_tonnage'])) { + $vessel->setGrossTonnage((float)$data['gross_tonnage']); + } + if (isset($data['imo_np'])) { + $vessel->setImoNo($data['imo_np']); + } + if (isset($data['call_sign'])) { + $vessel->setCallSign($data['call_sign']); + } + + $this->entityManager->persist($vessel); + $count++; + } else { + $io->warning("Shipping company '{$data['shipping_company']}' not found for vessel '{$data['name']}'"); + } + } + } + + $io->success("Imported $count vessels"); + } + + private function importTrips($spreadsheet, SymfonyStyle $io): void + { + $io->section('Importing Trips'); + + $sheet = $spreadsheet->getSheetByName('trip'); + if (!$sheet) { + $io->warning('Sheet "trip" not found'); + return; + } + + $rows = $sheet->toArray(); + $headers = array_shift($rows); + + $count = 0; + foreach ($rows as $row) { + $data = array_combine($headers, $row); + + // Finde das zugehörige Vessel + $vessel = $this->entityManager->getRepository(Vessel::class) + ->findOneBy(['name' => $data['vessel']]); + + if (!$vessel) { + $io->warning("Vessel '{$data['vessel']}' not found for trip ID {$data['id']}"); + continue; + } + + // Finde die Start-Location + $startLocation = $this->entityManager->getRepository(Location::class) + ->findOneBy(['name' => $data['start_location']]); + + if (!$startLocation) { + $io->warning("Start location '{$data['start_location']}' not found for trip ID {$data['id']}"); + continue; + } + + // Finde die End-Location + $endLocation = $this->entityManager->getRepository(Location::class) + ->findOneBy(['name' => $data['end_location']]); + + if (!$endLocation) { + $io->warning("End location '{$data['end_location']}' not found for trip ID {$data['id']}"); + continue; + } + + // Konvertiere Excel-Dates und kombiniere mit Zeit + if (is_numeric($data['start_date'])) { + $startDate = Date::excelToDateTimeObject($data['start_date']); + } else { + $startDate = new \DateTime($data['start_date']); + } + + if (is_numeric($data['start_time'])) { + $startTime = Date::excelToDateTimeObject($data['start_time']); + } else { + $startTime = new \DateTime($data['start_time']); + } + + // Kombiniere Datum und Zeit für Start + $startDate->setTime( + (int)$startTime->format('H'), + (int)$startTime->format('i'), + (int)$startTime->format('s') + ); + $startDateImmutable = DateTimeImmutable::createFromMutable($startDate); + + // Konvertiere Excel-Dates und kombiniere mit Zeit für Ende + if (is_numeric($data['end_date'])) { + $endDate = Date::excelToDateTimeObject($data['end_date']); + } else { + $endDate = new \DateTime($data['end_date']); + } + + if (is_numeric($data['end_time'])) { + $endTime = Date::excelToDateTimeObject($data['end_time']); + } else { + $endTime = new \DateTime($data['end_time']); + } + + // Kombiniere Datum und Zeit für Ende + $endDate->setTime( + (int)$endTime->format('H'), + (int)$endTime->format('i'), + (int)$endTime->format('s') + ); + $endDateImmutable = DateTimeImmutable::createFromMutable($endDate); + + // Prüfe, ob Trip bereits existiert (basierend auf Vessel und Datum) + $existingTrip = $this->entityManager->getRepository(Trip::class) + ->findOneBy([ + 'vessel' => $vessel, + 'startDate' => $startDateImmutable, + 'startLocation' => $startLocation + ]); + + if (!$existingTrip) { + $trip = new Trip($vessel, $startLocation, $endLocation, $startDateImmutable, $endDateImmutable); + $trip->setCompleted(); + $this->entityManager->persist($trip); + $count++; + } + } + + $io->success("Imported $count trips"); + } +} \ No newline at end of file