develia/geo-bundle
Laravel geo bundle for geolocation features: resolve countries/regions/cities, work with coordinates and distances, and integrate geo data into your app via simple services and helpers. Designed as a lightweight add-on you can extend for your data source.
Installation Add the bundle to your Laravel project via Composer:
composer require develia/geo-bundle
Register the bundle in config/app.php under the providers array:
Develia\GeoBundle\GeoServiceProvider::class,
Publish Config Publish the default configuration:
php artisan vendor:publish --provider="Develia\GeoBundle\GeoServiceProvider" --tag="config"
This creates config/geo.php with default settings (e.g., API keys, distance units).
First Use Case: Geocoding an Address
Inject the GeoService into a controller or service:
use Develia\GeoBundle\Services\GeoService;
class LocationController extends Controller
{
protected $geoService;
public function __construct(GeoService $geoService)
{
$this->geoService = $geoService;
}
public function getCoordinates()
{
$address = "1600 Amphitheatre Parkway, Mountain View, CA";
$result = $this->geoService->geocode($address);
return response()->json($result);
}
}
Call the endpoint to fetch coordinates for an address.
Geocoding & Reverse Geocoding
$this->geoService->geocode("Eiffel Tower, Paris");
$this->geoService->reverseGeocode(48.8584, 2.2945);
Distance Calculations
Use the distance() method to compute distances between coordinates:
$distance = $this->geoService->distance(
40.7128, -74.0060, // New York
34.0522, -118.2437 // Los Angeles
);
// Returns distance in configured units (e.g., kilometers).
Batch Processing Process multiple addresses/coordinates efficiently:
$addresses = ["Address 1", "Address 2", "Address 3"];
$results = $this->geoService->batchGeocode($addresses);
Caching Results Leverage Laravel’s cache to avoid repeated API calls for the same input:
$this->geoService->geocode("Caching Example", 3600); // Cache for 1 hour.
Service Container Binding
Extend or replace the default GeoService binding in AppServiceProvider:
$this->app->bind(GeoService::class, function ($app) {
return new CustomGeoService($app['config']['geo']);
});
Middleware for Geo-Enriched Requests Attach coordinates to incoming requests (e.g., from IP geolocation):
namespace App\Http\Middleware;
use Closure;
use Develia\GeoBundle\Services\GeoService;
class GeoEnrichMiddleware
{
protected $geoService;
public function __construct(GeoService $geoService)
{
$this->geoService = $geoService;
}
public function handle($request, Closure $next)
{
$ip = $request->ip();
$coordinates = $this->geoService->getCoordinatesByIp($ip);
$request->merge(['lat' => $coordinates['lat'], 'lng' => $coordinates['lng']]);
return $next($request);
}
}
Event Listeners for Geo Updates Trigger events when geodata changes (e.g., after geocoding):
// In EventServiceProvider
protected $listen = [
'Develia\GeoBundle\Events\GeocodeCompleted' => [
'App\Listeners\LogGeocodeResult',
],
];
API Rate Limiting Use Laravel’s rate limiting middleware to manage API calls:
Route::middleware(['throttle:60,1'])->group(function () {
Route::get('/geocode', [GeoController::class, 'geocode']);
});
API Key Management
config/geo.php exposes them in version control..env file:
GEO_API_KEY=your_api_key_here
Then reference it in config/geo.php:
'api_key' => env('GEO_API_KEY'),
Rate Limits & Quotas
config/geo.php logging.Coordinate Precision
$lat = round($lat, 6);
$lng = round($lng, 6);
Time Zone Handling
use Carbon\Carbon;
$localTime = Carbon::parse($apiTime)->timezone('Europe/Madrid');
Enable Logging
Configure logging in config/geo.php:
'logging' => [
'enabled' => true,
'channel' => 'single',
'level' => 'debug',
],
Check logs for API responses/errors:
tail -f storage/logs/laravel.log
Mocking for Testing Use Laravel’s mocking to test without hitting external APIs:
$this->mock(GeoService::class)->shouldReceive('geocode')
->once()
->andReturn(['lat' => 40.7128, 'lng' => -74.0060]);
Handling Invalid Responses Validate API responses before processing:
$result = $this->geoService->geocode($address);
if (!isset($result['lat']) || !isset($result['lng'])) {
throw new \InvalidArgumentException("Invalid geocode response.");
}
Custom Providers Extend the bundle to support additional geocoding providers (e.g., Mapbox, OpenStreetMap):
namespace App\Services;
use Develia\GeoBundle\Contracts\GeoProviderInterface;
class MapboxProvider implements GeoProviderInterface
{
public function geocode($address)
{
// Custom Mapbox logic.
}
}
Register the provider in config/geo.php:
'providers' => [
'primary' => \App\Services\MapboxProvider::class,
],
Database Storage Store geodata in your database for offline access:
$this->geoService->storeGeocode($address, $coordinates);
$storedData = $this->geoService->getStoredGeocode($address);
Webhook Integration Listen for webhook events from geocoding APIs (e.g., for bulk updates):
Route::post('/geo-webhook', function (Request $request) {
$this->geoService->handleWebhook($request->all());
});
How can I help you explore Laravel packages today?