laravel-airports maintained by flairuk
Laravel Airports — Over 10,000 IATA airport codes (LHR, JFK, DXB, …) for Laravel 12 and 13.
- No database required. Look airports up through a facade backed by an in-memory dataset.
- Typed results. Every lookup returns readonly
Airportobjects in Laravel collections keyed by code. - Validation rule.
new AirportCodeaccepts known codes only. - Optional table. Publish a migration and seed an
airportstable when other tables need to reference airports.
📦 Installation
composer require flairuk/laravel-airports
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 Airports facade automatically.
🚀 Usage
use FLAIRUK\Airports\Facades\Airports;
Airports::find('lhr'); // Airport { id: 4329, code: "LHR", name: "Heathrow", countryCode: "GB" }
Airports::findOrFail('LHR'); // throws ItemNotFoundException for unknown codes
Airports::exists('JFK'); // true
Airports::findById(4329);
Airports::all(); // Collection<string, Airport> keyed by code
Airports::inCountry('GB'); // airports in the UK
Airports::search('heathrow'); // matches on name or exact code
Airports::codes(); // ['AAA', 'AAB', ...]
Select options
Airports::options(); // ['LHR' => 'Heathrow', ...] sorted by name
Airports::options('id'); // [4329 => 'Heathrow', ...]
Validation
use FLAIRUK\Airports\Rules\AirportCode;
$request->validate([
'origin' => ['required', new AirportCode],
'destination' => ['required', new AirportCode, 'different:origin'],
]);
AirportCode ignores case but different does not, so LHR and lhr would pass as different airports. Uppercase both fields first (for example in a form request's prepareForValidation()) when that matters.
Dependency injection
The facade resolves a singleton FLAIRUK\Airports\Airports, which you can type-hint instead.
💾 Database table (optional)
php artisan airports:install # publish config + migration, then ask to migrate and seed
php artisan airports:install --migrate # migrate and seed without asking
php artisan airports:seed # insert / update (safe to re-run)
php artisan airports:seed --prune # also delete rows no longer in the dataset
You can also call the seeder from your own DatabaseSeeder:
$this->call(\FLAIRUK\Airports\Database\AirportsSeeder::class);
Query the table through the bundled Eloquent model:
use FLAIRUK\Airports\Models\Airport;
Airport::code('LHR')->first();
Airport::inCountry('GB')->orderBy('name')->get();
The table name and connection come from AIRPORTS_TABLE and AIRPORTS_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-airports |
flairuk/laravel-airports |
ijeffro\Airports\… namespace |
FLAIRUK\Airports\… |
Facade ijeffro\Airports\AirportsFacade |
FLAIRUK\Airports\Facades\Airports (auto-discovered) |
Airports::getList($sort) (array) |
Airports::all()->sortBy($property, SORT_NATURAL | SORT_FLAG_CASE) (Collection of Airport; properties are camelCase, e.g. countryCode) |
Airports::getOne($id) |
Airports::findById($id) or Airports::find($code) |
Airports::getListForSelect() (keyed by id) |
Airports::options('id') |
php artisan airports:migration |
php artisan airports:install / airports:seed |
Config key airports.table_name |
airports.table |
Row ids and columns (code, name, country_code) are unchanged, so existing tables and foreign keys stay valid.
🧪 Testing
composer test
📄 License
MIT. See LICENSE.