ijeffro / laravel-cities
IATA city codes for Laravel: an in-memory lookup API, validation rule and optional database table.
Requires
- php: ^8.2
- illuminate/console: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- illuminate/validation: ^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5|^12.0|^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 11:04:07 UTC
README
Laravel Cities — More than 9,000 IATA city codes (LON, NYC, PAR, …) for Laravel 12 and 13. In IATA's scheme a city code groups the airports that serve a city, as LON does for Heathrow, Gatwick and Stansted. This package lists the city codes; it does not map them to airports.
- No database required. Look cities up through a facade backed by an in-memory dataset.
- Typed results. Every lookup returns readonly
Cityobjects in Laravel collections keyed by code. - Validation rule.
new CityCodeaccepts known codes only. - Optional table. Publish a migration and seed a
citiestable when other tables need to reference cities.
📦 Installation · 🚀 Usage · 💾 Database table · 🔄 Upgrading
📦 Installation
composer require flairuk/laravel-cities
Requires PHP 8.2 or later with Laravel 12, or PHP 8.3 or later with Laravel 13.
Laravel discovers the service provider and the Cities facade automatically.
🚀 Usage
use FLAIRUK\Cities\Facades\Cities; Cities::find('lon'); // City { id: 4241, code: "LON", name: "London", countryCode: "GB" } Cities::findOrFail('LON'); // throws ItemNotFoundException for unknown codes Cities::exists('NYC'); // true Cities::findById(4241); Cities::all(); // Collection<string, City> keyed by code Cities::inCountry('FR'); // cities in France Cities::search('london'); // matches on name or exact code Cities::codes();
Select options
Cities::options(); // ['LON' => 'London', ...] sorted by name Cities::options('id'); // [4241 => 'London', ...]
Validation
use FLAIRUK\Cities\Rules\CityCode; $request->validate(['city' => ['required', new CityCode]]);
💾 Database table (optional)
php artisan cities:install # publish config + migration, then ask to migrate and seed php artisan cities:install --migrate # migrate and seed without asking php artisan cities:seed # insert / update (safe to re-run) php artisan cities:seed --prune # also delete rows no longer in the dataset
You can also call the seeder from your own DatabaseSeeder:
$this->call(\FLAIRUK\Cities\Database\CitiesSeeder::class);
Query the table through the bundled Eloquent model:
use FLAIRUK\Cities\Models\City; City::code('LON')->first(); City::inCountry('GB')->orderBy('name')->get();
The table name and connection come from CITIES_TABLE and CITIES_DB_CONNECTION, or from the published config.
🔄 Upgrading from dev-master
Version 1.0 is a rewrite. Breaking changes:
| dev-master | 1.0 |
|---|---|
Package ijeffro/laravel-cities |
flairuk/laravel-cities |
ijeffro\Cities\… namespace |
FLAIRUK\Cities\… |
Facade ijeffro\Cities\CitiesFacade |
FLAIRUK\Cities\Facades\Cities (auto-discovered) |
Cities::getList($sort) (array) |
Cities::all()->sortBy($property, SORT_NATURAL | SORT_FLAG_CASE) (Collection of City; properties are camelCase, e.g. countryCode) |
Cities::getOne($id) |
Cities::findById($id) or Cities::find($code) |
Cities::getListForSelect() (keyed by id) |
Cities::options('id') |
php artisan cities:migration |
php artisan cities:install / cities:seed |
Config key cities.table_name |
cities.table |
Field / column iso_3166_3 |
code. It was always an IATA city code, not an ISO 3166 code |
Row ids are unchanged. If you have an existing table, rename the column before re-seeding:
Schema::table('cities', fn (Blueprint $table) => $table->renameColumn('iso_3166_3', 'code'));
🧪 Testing
composer test
📄 License
MIT. See LICENSE.