diff --git a/app/Console/Commands/ExtractGeometryForCities.php b/app/Console/Commands/ExtractGeometryForCities.php new file mode 100644 index 00000000..42108fee --- /dev/null +++ b/app/Console/Commands/ExtractGeometryForCities.php @@ -0,0 +1,131 @@ +argument('jsonPath'); + + $json = File::get($jsonPath); + $data = json_decode($json, true); + + $features = $data['features'] ?? null; + if ($features === null) { + $this->error('No features were found'); + return parent::FAILURE; + } + + foreach ($data['features'] as $city) { + + $cityId = $city['properties']['city_id'] ?? null; + if ($cityId === null) + { + $this->info("this city doesn't have id: $city"); + continue; + } + + $coordinates = $city['geometry']['coordinates'] ?? null; + if ($coordinates === null) + { + $this->info("this city doesn't have coordinates: $coordinates"); + continue; + } + + $type = $city['geometry']['type'] ?? null; + if ($type === null) + { + $this->info("This city doesn't have a type: $city"); + continue; + } + + try { + switch ($type) { + + case 'Polygon': + $wktCoords = collect($coordinates[0]) + ->map(fn($pair) => $pair[1] . ' ' . $pair[0]) + ->implode(','); + $wellKnownText = "POLYGON(($wktCoords))"; + break; + + case 'MultiPolygon': + $wktCoords = collect($coordinates) + ->map(function ($polygon) { + $rings = collect($polygon)->map(function ($ring) { + if ($ring[0] !== end($ring)) { + $ring[] = $ring[0]; + } + return collect($ring) + ->map(fn($pair) => $pair[1] . ' ' . $pair[0]) + ->implode(','); + }); + return '((' . $rings->implode('),(') . '))'; + }) + ->implode(','); + + $wellKnownText = "MULTIPOLYGON($wktCoords)"; + break; + + default: + $this->info("$type is not a valid type in city: $city"); + continue 2; + } + } + catch (\Throwable $th) + { + $this->error("Something went wrong: $th"); + continue; + } + + + + $query = City::query() + ->find($cityId); + + if (!$query) { + $this->info("City $cityId not found"); + continue; + } + + try { + $query->update([ + 'geometry' => DB::raw("ST_GeomFromText('$wellKnownText', 4326)") + ]); + } + catch (\Throwable $th) + { + $this->error("Something went wrong: $th"); + } + + + } + + return parent::SUCCESS; + } +} diff --git a/app/Models/City.php b/app/Models/City.php index 0aa06865..fa8cf2ef 100644 --- a/app/Models/City.php +++ b/app/Models/City.php @@ -23,6 +23,10 @@ class City extends Model 'updated_at' ]; + protected $fillable = [ + 'geometry', + ]; + public function province() { return $this->belongsTo('App\Models\Province'); diff --git a/database/migrations/2025_08_18_153617_add_geometry_column_to_cities_table.php b/database/migrations/2025_08_18_153617_add_geometry_column_to_cities_table.php new file mode 100644 index 00000000..4bb50d28 --- /dev/null +++ b/database/migrations/2025_08_18_153617_add_geometry_column_to_cities_table.php @@ -0,0 +1,29 @@ +geometry('geometry')->nullable(); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('cities', function (Blueprint $table) { + $table->dropColumn('geometry'); + }); + } +};