From b6ffeea8ad74e47481901b59a51dd706f69e63b8 Mon Sep 17 00:00:00 2001 From: josh Date: Fri, 3 Apr 2026 13:39:03 +1000 Subject: [PATCH] Add countries and regions --- app/Models/Country.php | 20 ++++ app/Models/Region.php | 22 +++++ ...26_04_03_033246_create_countries_table.php | 77 ++++++++++++++++ ...2026_04_03_033256_create_regions_table.php | 91 +++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 app/Models/Country.php create mode 100644 app/Models/Region.php create mode 100644 database/migrations/2026_04_03_033246_create_countries_table.php create mode 100644 database/migrations/2026_04_03_033256_create_regions_table.php diff --git a/app/Models/Country.php b/app/Models/Country.php new file mode 100644 index 0000000..229331e --- /dev/null +++ b/app/Models/Country.php @@ -0,0 +1,20 @@ +hasMany(Region::class); + } +} diff --git a/app/Models/Region.php b/app/Models/Region.php new file mode 100644 index 0000000..4cb6ee2 --- /dev/null +++ b/app/Models/Region.php @@ -0,0 +1,22 @@ +belongsTo(Country::class); + } +} diff --git a/database/migrations/2026_04_03_033246_create_countries_table.php b/database/migrations/2026_04_03_033246_create_countries_table.php new file mode 100644 index 0000000..dcfb862 --- /dev/null +++ b/database/migrations/2026_04_03_033246_create_countries_table.php @@ -0,0 +1,77 @@ +id(); + $table->string('code', 2)->unique(); + $table->string('name'); + $table->string('continent', 2); + $table->timestamps(); + }); + + $this->importCsv(); + } + + public function down(): void + { + Schema::dropIfExists('countries'); + } + + private function importCsv(): void + { + $path = storage_path('app/private/seed_data/countries.csv'); + + if (! file_exists($path)) { + throw new \RuntimeException("Countries CSV not found at: {$path}"); + } + + $handle = fopen($path, 'rb'); + + if ($handle === false) { + throw new \RuntimeException("Failed to open countries CSV at: {$path}"); + } + + // Skip header row + fgetcsv($handle); + + $batch = []; + $batchSize = 500; + $now = now()->toDateTimeString(); + + while (($row = fgetcsv($handle)) !== false) { + if (count($row) < 4) { + continue; + } + + // id, code, name, continent, wikipedia_link, keywords + [, $code, $name, $continent] = $row; + + $batch[] = [ + 'code' => trim($code), + 'name' => trim($name), + 'continent' => trim($continent), + 'created_at' => $now, + 'updated_at' => $now, + ]; + + if (count($batch) >= $batchSize) { + DB::table('countries')->insert($batch); + $batch = []; + } + } + + fclose($handle); + + if (! empty($batch)) { + DB::table('countries')->insert($batch); + } + } +}; diff --git a/database/migrations/2026_04_03_033256_create_regions_table.php b/database/migrations/2026_04_03_033256_create_regions_table.php new file mode 100644 index 0000000..8346274 --- /dev/null +++ b/database/migrations/2026_04_03_033256_create_regions_table.php @@ -0,0 +1,91 @@ +id(); + $table->string('name'); + $table->foreignId('country_id')->constrained('countries'); + $table->string('code'); + $table->string('local_code'); + $table->string('continent', 2); + $table->timestamps(); + }); + + $this->importCsv(); + } + + public function down(): void + { + Schema::dropIfExists('regions'); + } + + private function importCsv(): void + { + $path = storage_path('app/private/seed_data/regions.csv'); + + if (! file_exists($path)) { + throw new \RuntimeException("Regions CSV not found at: {$path}"); + } + + $handle = fopen($path, 'rb'); + + if ($handle === false) { + throw new \RuntimeException("Failed to open regions CSV at: {$path}"); + } + + // Skip header row + fgetcsv($handle); + + // Build a lookup map of country code -> id to resolve the foreign key + $countryMap = DB::table('countries')->pluck('id', 'code')->all(); + + $batch = []; + $batchSize = 500; + $now = now()->toDateTimeString(); + + while (($row = fgetcsv($handle)) !== false) { + if (count($row) < 6) { + continue; + } + + // id, code, local_code, name, continent, iso_country, wikipedia_link, keywords + [, $code, $localCode, $name, $continent, $isoCountry] = $row; + + $isoCountry = trim($isoCountry); + + if (! isset($countryMap[$isoCountry])) { + // Skip regions whose country wasn't imported (shouldn't happen with a complete dataset) + continue; + } + + $batch[] = [ + 'code' => trim($code), + 'local_code' => trim($localCode), + 'name' => trim($name), + 'continent' => trim($continent), + 'country_id' => $countryMap[$isoCountry], + 'created_at' => $now, + 'updated_at' => $now, + ]; + + if (count($batch) >= $batchSize) { + DB::table('regions')->insert($batch); + $batch = []; + } + } + + fclose($handle); + + if (! empty($batch)) { + DB::table('regions')->insert($batch); + } + } +};