pharaonic/laravel-locations
Laravel Locations is a lightweight package that adds country, state, and city data to Laravel apps, with models, migrations, and helpers for seeding and querying locations. It makes address forms, regional filters, and location-aware features easier to build.
composer require pharaonic/laravel-locations, then publish the package assets: php artisan vendor:publish --provider="Pharaonic\Laravel\Locations\LocationsServiceProvider". Publish tags vary by version — run php artisan vendor:publish without a tag first and pick the locations-* entries you need (config, migrations, seeders).php artisan migrate, then seed the location dataset. This is the step people miss: the package ships data, not just schema, so an empty countries/states/cities table is the usual "it installed but returns nothing" symptom.src/Models directory and its config file — that tells you the exact model namespaces, table names, and whether optional datasets (currencies, timezones, languages) are enabled.Country::all() for the first select and lazy-load children by country_id / state_id.Country, State, City as normal Eloquent models: $country->states, $state->cities, and belongsTo back up the chain. Store country_id, state_id, city_id on your own tables and reference them with foreign keys rather than storing free-text names./locations/states/{country}, /locations/cities/{state}) that return id + display name, and cache them aggressively — the data is effectively static. Cache::remember("states.{$countryId}", ...) removes the query cost from every form render.->with('city.state.country'); the three-level chain is an easy N+1 otherwise.exists:countries,id (or the model's table from config) in FormRequests, and validate the parent-child consistency yourself — exists won't catch a city that doesn't belong to the submitted state.name_en.LocationRepository in front of the package models. When the package changes model namespaces or adds datasets, you patch one class instead of every controller.insert, upsert, or updateOrInsert before re-running it on a populated database, or you may duplicate rows instead of fixing them.State::where('iso2', 'XX')->first() silently returns an arbitrary row when two exist. Use firstOrFail plus a unique index on (country_id, iso2) if you add your own lookups.db:seed can exhaust memory or hit the default 60s timeout. Seed via a dedicated command, raise memory_limit, and consider disabling datasets you don't use in the config before migrating.countries/states/cities tables, the package migrations will conflict. Configure table names or migrate before installing your own.^1.5 and treat any 1.6.x as needing a re-seed review. Data patches like 1.5.7 are low-risk but invisible without an operational step, so add "re-seed locations" to your release checklist.How can I help you explore Laravel packages today?