jcf/geocode
| Install | |
|---|---|
composer require jcf/geocode |
|
| Latest Version: | 3.0.0 |
| PHP: | ^8.1 |
| License: | MIT |
| Last Updated: | Aug 18, 2026 |
| Links: | GitHub · Packagist |
Google Geocoding API for Laravel
A simple Laravel service provider for the Google Maps Geocoding API.
3.x supports Laravel 9–13 (PHP 8.1+). For 2.x (Laravel 9–13, PHP 8.0+), use ^2.0. For legacy Laravel 4–8, use 1.5.0 (final 1.x security release).
Installation
composer require jcf/geocode:^3.0
The service provider and Geocode facade are auto-discovered.
Optionally publish the config:
php artisan vendor:publish --tag=geocode-config
Configuration
Add to your .env:
GEOCODE_API_KEY=<your_google_api_key>
GEOCODE_LANGUAGE=en # optional: pt-BR, es, de, it, fr, en-GB, …
# HTTP (optional)
GEOCODE_TIMEOUT=10
GEOCODE_RETRY_TIMES=2
GEOCODE_RETRY_SLEEP=100
# Cache (optional, disabled by default)
GEOCODE_CACHE_ENABLED=false
GEOCODE_CACHE_STORE=redis
GEOCODE_CACHE_TTL=86400
# Batch throttle (optional, 0 = no throttle)
GEOCODE_THROTTLE_PER_SECOND=0
Supported languages for the Google Maps Geocoding API.
The API key remains optional in config; when omitted, Google typically responds with REQUEST_DENIED and the package returns null.
Usage
Geocoding (address → coordinates)
use Jcf\Geocode\Facades\Geocode;
$result = Geocode::address('1 Infinite Loop');
if ($result) {
echo $result->latitude;
echo $result->longitude;
echo $result->formattedAddress;
echo $result->locationType;
echo $result->postalCode; // ?string — null when absent
}
Reverse geocoding (coordinates → address)
$result = Geocode::latLng(40.7637931, -73.9722014);
if ($result) {
echo $result->formattedAddress;
}
Place ID lookup
$result = Geocode::placeId('ChIJdd4hrwug2EcRmSrV3Vo6llI');
Rich Result fields
When Google returns them, Result also exposes:
$result->placeId; // ?string
$result->types; // ?array<int, string>
$result->viewport; // ?object
$result->bounds; // ?object
$result->partialMatch; // ?bool
$result->plusCode; // ?object
$result->raw; // first Google result object
All properties are readonly.
Batch
Geocode many addresses or coordinate pairs concurrently via Laravel's Http::pool:
$results = Geocode::addresses(['Address A', 'Address B', 'Address C']);
// array<int, Result|null>
$results = Geocode::latLngs([
['lat' => 37.331741, 'lng' => -122.0303329],
['lat' => 40.7637931, 'lng' => -73.9722014],
]);
When GEOCODE_THROTTLE_PER_SECOND is greater than zero, requests are sent in batches of that size with a one-second pause between batches.
Cache
Enable caching to avoid repeat calls to Google for the same query:
// .env
GEOCODE_CACHE_ENABLED=true
GEOCODE_CACHE_STORE=redis
GEOCODE_CACHE_TTL=86400
Cache keys include the query parameters and the configured default language. Cached hits skip HTTP and are marked in GeocodingPerformed events (cached: true).
Fluent builder
Chain Google API parameters before executing a lookup:
$result = Geocode::query()
->region('br')
->language('pt-BR')
->components(['country' => 'BR'])
->bounds([
'southwest' => ['lat' => -23.6, 'lng' => -46.7],
'northeast' => ['lat' => -23.5, 'lng' => -46.6],
])
->address('Av Paulista');
The builder supports address(), latLng(), and placeId().
Events
Every lookup (including cache hits and batch items) dispatches Jcf\Geocode\Events\GeocodingPerformed:
use Illuminate\Support\Facades\Event;
use Jcf\Geocode\Events\GeocodingPerformed;
Event::listen(GeocodingPerformed::class, function (GeocodingPerformed $event) {
// $event->params — query parameters sent to Google
// $event->result — Result|null
// $event->durationMs
// $event->status — Google status or cached equivalent
// $event->cached — true when served from cache
});
Debug logging is also written to the default log channel (Geocoding performed).
Errors
- Google non-OK status (
ZERO_RESULTS,REQUEST_DENIED,OVER_QUERY_LIMIT, …) →null - HTTP / connection failure →
Jcf\Geocode\Exceptions\GeocodingFailedException
use Jcf\Geocode\Exceptions\GeocodingFailedException;
try {
$result = Geocode::address($address);
} catch (GeocodingFailedException $e) {
// transport / HTTP failure
}
Testing
In your application or feature tests, fake outbound HTTP with Laravel's Http facade. The package calls https://maps.googleapis.com/maps/api/geocode/json.
Geocoding
use Illuminate\Support\Facades\Http;
use Jcf\Geocode\Facades\Geocode;
Http::fake([
'maps.googleapis.com/*' => Http::response([
'status' => 'OK',
'results' => [[
'formatted_address' => '1 Infinite Loop, Cupertino, CA 95014, USA',
'geometry' => [
'location' => ['lat' => 37.331741, 'lng' => -122.0303329],
'location_type' => 'ROOFTOP',
],
'address_components' => [],
]],
], 200),
]);
$result = Geocode::address('1 Infinite Loop');
$this->assertNotNull($result);
$this->assertSame(37.331741, $result->latitude);
Http::assertSentCount(1);
Reverse geocoding
Http::fake([
'maps.googleapis.com/*' => Http::response([
'status' => 'OK',
'results' => [[
'formatted_address' => '767 5th Avenue, New York, NY 10153, USA',
'geometry' => [
'location' => ['lat' => 40.7637931, 'lng' => -73.9722014],
'location_type' => 'ROOFTOP',
],
'address_components' => [],
]],
], 200),
]);
$result = Geocode::latLng(40.7637931, -73.9722014);
$this->assertNotNull($result);
Batch
Http::fake([
'maps.googleapis.com/*' => Http::response([
'status' => 'OK',
'results' => [[
'formatted_address' => '1 Infinite Loop, Cupertino, CA 95014, USA',
'geometry' => [
'location' => ['lat' => 37.331741, 'lng' => -122.0303329],
'location_type' => 'ROOFTOP',
],
'address_components' => [],
]],
], 200),
]);
$results = Geocode::addresses(['A', 'B', 'C']);
$this->assertCount(3, $results);
Http::assertSentCount(3);
Cache
use Illuminate\Support\Facades\Cache;
config([
'geocode.cache.enabled' => true,
'geocode.cache.store' => 'array',
'cache.default' => 'array',
'cache.stores.array' => ['driver' => 'array'],
]);
Cache::store('array')->clear();
Http::fake([
'maps.googleapis.com/*' => Http::response([
'status' => 'OK',
'results' => [[
'formatted_address' => '1 Infinite Loop, Cupertino, CA 95014, USA',
'geometry' => [
'location' => ['lat' => 37.331741, 'lng' => -122.0303329],
'location_type' => 'ROOFTOP',
],
'address_components' => [],
]],
], 200),
]);
Geocode::address('1 Infinite Loop');
Geocode::address('1 Infinite Loop');
Http::assertSentCount(1); // second lookup served from cache
Package development
composer test
composer format # Laravel Pint
composer analyse # PHPStan level 8
Upgrading
Changelog
See CHANGELOG.md.
Credits
- João Carlos
- Property access on results inspired by #17 from @Niellles
- All contributors
License
MIT
Related Packages
Geocoder package for PHP that offers a user friendly interface for Geocoder serv...
Rinvex Addressable is a polymorphic Laravel package, for addressbook management....
Geo-address api for laravel. Get latitude and longitude from location