Installation:
composer require toin0u/geocoder-laravel
For Laravel 5.5+, auto-discovery handles the service provider registration. For older versions, add Geocoder\Laravel\Providers\GeocoderService::class to config/app.php.
Publish Config (if customization is needed):
php artisan vendor:publish --provider="Geocoder\Laravel\Providers\GeocoderService" --tag="config"
First Use Case: Geocode an address:
$addresses = app('geocoder')->geocode('Los Angeles, CA')->get();
config/geocoder.php (default providers, cache settings, adapter).app('geocoder') or Geocoder::geocode() in your code.GoogleMaps and GeoPlugin in a Chain. Add/remove as needed.Basic Geocoding:
// Geocode an address
$addresses = app('geocoder')->geocode('1600 Amphitheatre Parkway')->get();
// Reverse geocode (lat, long)
$address = app('geocoder')->reverse(37.422, -122.084)->first();
Localized Queries:
// Set locale globally
$results = app('geocoder')->locale('fr')->geocode('Paris')->get();
// Per-query locale
$query = GeocodeQuery::create('Bologna')->withLocale('it');
$results = app('geocoder')->geocodeQuery($query)->get();
Provider-Specific Queries:
// Use a specific provider (e.g., GoogleMaps)
$results = app('geocoder')->using('google_maps')->geocode('Berlin')->get();
Caching:
$results = app('geocoder')->doNotCache()->geocode('New York')->get();
config/geocoder.php (default: 9999999 seconds).Dependency Injection:
use Geocoder\Laravel\ProviderAndDumperAggregator as Geocoder;
class AddressController {
public function __construct(private Geocoder $geocoder) {}
public function show() {
$addresses = $this->geocoder->geocode('San Francisco')->get();
}
}
Testing:
Leverage Laravel’s Http::fake() for mocking API calls:
use Illuminate\Support\Facades\Http;
Http::fake();
$addresses = app('geocoder')->geocode('Test Address')->get();
Http::assertSent(function ($request) {
return $request->url() === 'https://maps.googleapis.com/...';
});
Queueing Long-Running Geocodes: Dispatch a job for heavy geocoding tasks (e.g., bulk IP geolocation):
GeocodeJob::dispatch('8.8.8.8')->onQueue('geocode');
Form Validation: Use Laravel’s validation rules to ensure geocodable addresses:
$request->validate([
'address' => 'required|geocodable', // Custom rule
]);
Database Storage: Store geocoded results in a model:
$address = app('geocoder')->geocode($request->address)->first();
Location::create([
'latitude' => $address->getLatitude(),
'longitude' => $address->getLongitude(),
'formatted' => $address->getStreet(),
]);
Laravel 13 Cache Serialization:
__PHP_Incomplete_Class errors if cache.serializable_classes is not configured.'auto_register_serializable_classes' => false,
in config/geocoder.php. Alternatively, disable caching per query or set cache.duration to 0.HTTPS Requirement for GoogleMaps:
HTTPS is enabled in your config or environment.'https' => true in your GoogleMaps provider config.Rate Limits:
3600 seconds).Provider Order in Chain:
Chain is prioritized. If it fails, subsequent providers are tried.'providers' => [
Chain::class => [
GeoPlugin::class => [], // Cheaper, but less accurate
GoogleMaps::class => [env('GOOGLE_MAPS_API_KEY')],
],
],
Locale-Specific Caching:
Log API Responses: Add middleware to log geocoder requests/responses:
app('geocoder')->getHttpClient()->getEmitter()->attach(
new \Geocoder\HttpAdapter\Log\LogEmitter()
);
Validate API Keys:
$results = app('geocoder')->using('google_maps')->geocode('Test');
// Check for exceptions or empty results
Check Cache Keys:
$cacheKey = app('geocoder')->getCache()->getPrefix() . ':geocode:Los Angeles, CA';
Provider-Specific Errors:
Geocoder\Exception\UnsupportedProvider):
try {
$results = app('geocoder')->using('nonexistent_provider')->geocode('Test');
} catch (\Geocoder\Exception\UnsupportedProvider $e) {
Log::error('Unsupported provider: ' . $e->getProvider());
}
Custom Providers:
Chain with a custom provider (e.g., Mapbox):
'providers' => [
Chain::class => [
// Existing providers...
\Geocoder\Provider\Mapbox::class => [env('MAPBOX_API_KEY')],
],
],
Adapter Customization:
LaravelHttpClient with a custom PSR-18 client (e.g., Guzzle with retries):
'adapter' => [\Http\Client\Curl\Client::class => [
null,
null,
[CURLOPT_TIMEOUT => 10, CURLOPT_RETRYDELAY => 5],
]],
Post-Processing Results:
app()->bindAfter('geocoder', function ($geocoder) {
return new class($geocoder) {
public function __construct(private $geocoder) {}
public function geocode($query) {
$results = $this->geocoder->geocode($query)->get();
return collect($results)->map(function ($address) {
return (object) array_merge(
$address->toArray(),
['custom_field' => 'value']
);
});
}
};
});
Bulk Geocoding:
$addresses = ['NYC', 'LA', 'Chicago'];
foreach ($addresses as $address) {
GeocodeJob::dispatch($address)->onQueue('geocode');
}
Fallback Logic:
$results = app('geocoder')->geocode('Rare Address')->get();
if ($results->isEmpty()) {
$results = app('geocoder')->using('geo_plugin')->geocode('Rare Address')->get();
}
How can I help you explore Laravel packages today?