roundly-consulting/geolocation-for-laravel
A Laravel package for adding geolocation and location-aware features to your app. Resolve coordinates, calculate distances, and build proximity-based queries and search results with a simple, framework-friendly API.
This is a Roundly package for keeping a local MaxMind (GeoLite2/GeoIP2) database current inside a Laravel app. The release notes confirm the core flow: an UpdateDatabaseAction downloads a MaxMind archive, stages it in a temp directory, then promotes it into place.
composer require roundly/... (pull in ^2.0.4; it now requires roundly/enums ^1.1.0, roundly/http-client-rate-limits ^1.1.0, and roundly/package-toolkit ^1.3.0).php artisan vendor:publish --tag=...) and set your MaxMind account ID, license key, and edition IDs (e.g. GeoLite2-City, GeoLite2-Country) — the enums package supplies the edition identifiers, so prefer those constants over raw strings..mmdb from the configured path. Nothing else in your codebase needs to know about the download.Start by reading the config file and the UpdateDatabaseAction — between them you'll see every knob (paths, editions, rate limits, staging directory) the package exposes.
Schedule the update, don't call it inline. Put the update command on the scheduler (daily is fine; MaxMind only publishes weekly). Trigger your own cache warm-up or event listener afterwards if you derive data (timezones, currency, etc.) from the DB.
Treat the database as a deployable artifact. Many teams run the update during deployment rather than on a cron: build the .mmdb once, deploy it with the release, and skip per-host downloads. This avoids burning your MaxMind download quota across a fleet and keeps every host on the same data version.
Respect the download quota. MaxMind enforces a per-account downloads-per-24h limit, which is exactly why the package leans on http-client-rate-limits. Keep the limiter store shared (Redis/database) across hosts, not array, or each host will happily exceed the quota independently.
Tests: fake the HTTP layer, and now the filesystem staging. Use Http::fake() with a small fixture archive so tests never hit MaxMind. As of 2.0.4, UpdateDatabaseAction lets you stage its download in a directory the test chooses — pass a Storage::fake()/temp path per test so parallel test runs and leftover archives don't collide. Previously this was only controllable globally via TMPDIR, which made isolation painful.
Integration tip: wrap the update in your own small service or command if you need to notify, log to a specific channel, or fan out to multiple editions in one job. Don't subclass the action for cosmetics — compose around it.
Handle the "first run" case explicitly. On a fresh host there is no DB yet; make sure your geo lookup path degrades gracefully (null result / fallback) rather than throwing until the first successful update has run.
TMPDIR / the sys_temp_dir ini setting. On restricted shared hosting, containers with a read-only or tiny /tmp, or CI runners, the archive extraction fails before anything else does. Point TMPDIR at a disk with room for the compressed archive plus the extracted .mmdb.sys_temp_dir isn't always honoured. If PHP is configured oddly or TMPDIR is exported in a different process context (cron vs FPM vs queue worker), you'll get inconsistent staging locations. Verify with the same user and SAPI that runs the command.enums ^1.1.0, http-client-rate-limits ^1.1.0, package-toolkit ^1.3.0, dev testing ^1.2.1) and the staging directory became injectable. No config changes, no migration, no behaviour change for hosts using TMPDIR/sys_temp_dir. If you pin roundly/enums or package-toolkit below these floors, the update will fail to resolve — bump them together..mmdb. It's large, changes weekly, and will bloat your repo history. Store it on a persistent disk or build artifact store.How can I help you explore Laravel packages today?