Installation
composer require damienharper/navigation-bundle
Add to config/app.php under providers:
DamienHarper\NavigationBundle\NavigationBundle::class,
Publish Config
php artisan vendor:publish --provider="DamienHarper\NavigationBundle\NavigationBundle" --tag="config"
This generates config/navigation.php with default provider settings (Google Maps, OpenRouteService, etc.).
First Use Case: Distance Matrix
Inject the NavigationService into a controller or service:
use DamienHarper\NavigationBundle\Service\NavigationService;
public function __construct(private NavigationService $navigation)
{
}
public function getDistance()
{
$result = $this->navigation->distanceMatrix(
'provider_name', // e.g., 'google'
['origin' => 'New York', 'destination' => 'Boston']
);
return response()->json($result);
}
Provider Abstraction Use the bundle’s unified interface to switch providers without changing business logic:
// Fetch routes from OpenRouteService
$routes = $this->navigation->route(
'openroute',
['coordinates' => [[40.7128, -74.0060], [34.0522, -118.2437]]]
);
Caching Responses Leverage Laravel’s cache to avoid repeated API calls for static data:
$cachedDistance = Cache::remember('distance_matrix_ny_boston', now()->addHours(1), function () {
return $this->navigation->distanceMatrix('google', [...]);
});
Error Handling Wrap provider calls in try-catch blocks to handle API-specific errors:
try {
$result = $this->navigation->geocode('google', ['address' => '1600 Amphitheatre Parkway']);
} catch (\DamienHarper\NavigationBundle\Exception\ProviderException $e) {
Log::error('Geocode failed: ' . $e->getMessage());
return response()->json(['error' => 'Service unavailable'], 503);
}
Configuration Management Dynamically override provider settings per request:
$this->navigation->setProviderConfig('google', [
'api_key' => config('services.google.maps_api_key'),
'region' => 'us'
]);
Service Container Binding
Bind custom providers by extending the bundle’s ProviderInterface:
$this->app->bind(\DamienHarper\NavigationBundle\Service\ProviderInterface::class, CustomProvider::class);
Queueing Long-Running Requests Offload heavy computations (e.g., multi-stop route calculations) to queues:
Route::post('/calculate-route', function () {
dispatch(new CalculateRouteJob($request->all()));
});
Testing
Mock the NavigationService in tests:
$mock = Mockery::mock(NavigationService::class);
$mock->shouldReceive('distanceMatrix')
->once()
->andReturn(['distance' => 100, 'duration' => 3000]);
$this->app->instance(NavigationService::class, $mock);
Deprecated Providers
The bundle supports multiple providers, but some (e.g., older versions of OpenRouteService) may lack documentation or active maintenance. Verify provider compatibility in config/navigation.php.
Rate Limiting Free-tier APIs (e.g., Google Maps) enforce strict rate limits. Implement exponential backoff for retries:
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
try {
$result = $this->navigation->geocode('google', [...]);
} catch (TooManyRequestsHttpException $e) {
sleep(10); // Wait before retry
retry();
}
Coordinate Validation Always validate input coordinates to avoid malformed requests:
if (!is_array($coordinates) || count($coordinates) < 2) {
throw new \InvalidArgumentException('Invalid coordinates format');
}
Configuration Overrides
Avoid hardcoding provider credentials. Use Laravel’s .env or encrypted config:
GOOGLE_MAPS_API_KEY=your_key_here
Then reference in config/navigation.php:
'providers' => [
'google' => [
'api_key' => env('GOOGLE_MAPS_API_KEY'),
],
],
Enable API Debugging
Set debug: true in config/navigation.php to log raw API responses:
'debug' => env('APP_DEBUG', false),
Check HTTP Clients
The bundle uses Symfony’s HttpClient. Inspect requests/responses with:
$this->navigation->getHttpClient()->getOptions();
Custom Providers
Extend DamienHarper\NavigationBundle\Service\ProviderInterface to add support for new services (e.g., Mapbox, HERE Maps):
class MapboxProvider implements ProviderInterface {
public function distanceMatrix(array $params) { ... }
// Implement other required methods
}
Middleware for API Keys Add middleware to validate API keys before hitting provider endpoints:
$this->app->middleware([
\DamienHarper\NavigationBundle\Http\Middleware\ValidateApiKey::class,
]);
Event Listeners
Listen for provider events (e.g., navigation.request.sent) to log or transform requests:
Event::listen('navigation.request.sent', function ($event) {
Log::debug('Navigation request sent to ' . $event->getProvider(), ['params' => $event->getParams()]);
});
Fallback Providers Implement a fallback chain for when primary providers fail:
$this->navigation->setFallbackProviders(['openroute', 'mapbox']);
How can I help you explore Laravel packages today?