-
Notifications
You must be signed in to change notification settings - Fork 0
Laravel Integration
Rumen Damyanov edited this page Jul 31, 2025
·
1 revision
Complete guide to integrating php-geolocation with Laravel applications.
- Installation & Setup
- Service Provider Configuration
- Middleware Integration
- Controller Examples
- Blade Template Integration
- Artisan Commands
- Testing in Laravel
composer require rumenx/geolocationCreate a custom service provider for advanced configuration:
php artisan make:provider GeolocationServiceProvider<?php
// app/Providers/GeolocationServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Rumenx\Geolocation\Geolocation;
class GeolocationServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('geolocation', function ($app) {
$countryToLanguage = config('geolocation.country_to_language', [
'US' => ['en'], 'CA' => ['en', 'fr'], 'GB' => ['en'],
'DE' => ['de'], 'FR' => ['fr'], 'ES' => ['es'],
'JP' => ['ja'], 'BR' => ['pt'],
]);
$cookieName = config('geolocation.language_cookie', 'app_language');
return new Geolocation(request()->server(), $countryToLanguage, $cookieName);
});
}
public function provides()
{
return ['geolocation'];
}
}Register in config/app.php:
'providers' => [
// Other providers...
App\Providers\GeolocationServiceProvider::class,
],Create config/geolocation.php:
<?php
// config/geolocation.php
return [
/*
|--------------------------------------------------------------------------
| Country to Language Mapping
|--------------------------------------------------------------------------
*/
'country_to_language' => [
'US' => ['en'],
'CA' => ['en', 'fr'],
'GB' => ['en'],
'AU' => ['en'],
'DE' => ['de'],
'AT' => ['de'],
'CH' => ['de', 'fr'],
'FR' => ['fr'],
'BE' => ['fr', 'nl'],
'ES' => ['es'],
'MX' => ['es'],
'AR' => ['es'],
'BR' => ['pt'],
'JP' => ['ja'],
'CN' => ['zh'],
'RU' => ['ru'],
'IT' => ['it'],
'NL' => ['nl'],
'SE' => ['sv'],
'NO' => ['no'],
'DK' => ['da'],
'FI' => ['fi'],
],
/*
|--------------------------------------------------------------------------
| Available Languages
|--------------------------------------------------------------------------
*/
'available_languages' => ['en', 'fr', 'de', 'es'],
/*
|--------------------------------------------------------------------------
| Language Cookie Settings
|--------------------------------------------------------------------------
*/
'language_cookie' => 'app_language',
'cookie_duration' => 86400 * 30, // 30 days
/*
|--------------------------------------------------------------------------
| Default Language
|--------------------------------------------------------------------------
*/
'default_language' => 'en',
/*
|--------------------------------------------------------------------------
| Development Simulation
|--------------------------------------------------------------------------
*/
'enable_simulation' => env('APP_DEBUG', false),
'simulation_country' => env('GEO_SIMULATE_COUNTRY'),
];Create a Facade for easier access:
<?php
// app/Facades/Geolocation.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Geolocation extends Facade
{
protected static function getFacadeAccessor()
{
return 'geolocation';
}
}Register in config/app.php:
'aliases' => [
// Other aliases...
'Geolocation' => App\Facades\Geolocation::class,
],use App\Facades\Geolocation;
// In controllers
$country = Geolocation::getCountryCode();
$language = Geolocation::getLanguageForCountry($country);php artisan make:middleware GeolocationMiddleware<?php
// app/Http/Middleware/GeolocationMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Rumenx\Geolocation\Geolocation;
class GeolocationMiddleware
{
public function handle(Request $request, Closure $next)
{
$countryToLanguage = config('geolocation.country_to_language');
$cookieName = config('geolocation.language_cookie');
$geo = new Geolocation($request->server(), $countryToLanguage, $cookieName);
// Store geolocation data in request
$request->merge([
'geo_country' => $geo->getCountryCode(),
'geo_language' => $geo->getLanguageForCountry($geo->getCountryCode()),
'geo_info' => $geo->getGeoInfo()
]);
// Set language cookie if needed
if ($geo->shouldSetLanguage()) {
$language = $geo->getLanguageForCountry($geo->getCountryCode());
if ($language) {
cookie()->queue(
$cookieName,
$language,
config('geolocation.cookie_duration', 43200)
);
}
}
return $next($request);
}
}<?php
// app/Http/Middleware/LanguageDetectionMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Rumenx\Geolocation\Geolocation;
class LanguageDetectionMiddleware
{
public function handle(Request $request, Closure $next)
{
$language = $this->detectLanguage($request);
// Set Laravel locale
App::setLocale($language);
// Add to request
$request->merge(['detected_language' => $language]);
return $next($request);
}
private function detectLanguage(Request $request): string
{
$availableLanguages = config('geolocation.available_languages', ['en']);
$defaultLanguage = config('geolocation.default_language', 'en');
// 1. Check URL parameter
if ($request->has('lang') && in_array($request->lang, $availableLanguages)) {
return $request->lang;
}
// 2. Check existing cookie
$cookieName = config('geolocation.language_cookie');
if ($request->hasCookie($cookieName)) {
$cookieLanguage = $request->cookie($cookieName);
if (in_array($cookieLanguage, $availableLanguages)) {
return $cookieLanguage;
}
}
// 3. Check geolocation
$countryToLanguage = config('geolocation.country_to_language');
$geo = new Geolocation($request->server(), $countryToLanguage, $cookieName);
$country = $geo->getCountryCode();
$language = $geo->getLanguageForCountry($country, $availableLanguages);
return $language ?: $defaultLanguage;
}
}In app/Http/Kernel.php:
protected $middleware = [
// Other middleware...
\App\Http\Middleware\GeolocationMiddleware::class,
];
protected $middlewareGroups = [
'web' => [
// Other middleware...
\App\Http\Middleware\LanguageDetectionMiddleware::class,
],
];
protected $routeMiddleware = [
// Other middleware...
'geo' => \App\Http\Middleware\GeolocationMiddleware::class,
'lang' => \App\Http\Middleware\LanguageDetectionMiddleware::class,
];<?php
// app/Http/Controllers/HomeController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Rumenx\Geolocation\Geolocation;
class HomeController extends Controller
{
public function index(Request $request)
{
$countryToLanguage = config('geolocation.country_to_language');
$geo = new Geolocation($request->server(), $countryToLanguage);
$data = [
'country' => $geo->getCountryCode(),
'language' => $geo->getLanguageForCountry($geo->getCountryCode()),
'geoInfo' => $geo->getGeoInfo(),
];
return view('home', $data);
}
}<?php
// app/Http/Controllers/Api/GeolocationController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Rumenx\Geolocation\Geolocation;
class GeolocationController extends Controller
{
public function detect(Request $request): JsonResponse
{
try {
$countryToLanguage = config('geolocation.country_to_language');
$geo = new Geolocation($request->server(), $countryToLanguage);
$data = [
'country_code' => $geo->getCountryCode(),
'language' => $geo->getLanguageForCountry($geo->getCountryCode()),
'ip' => $geo->getIp(),
'is_development' => $geo->isLocalDevelopment(),
];
return response()->json([
'success' => true,
'data' => $data
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Geolocation detection failed',
'error' => $e->getMessage()
], 500);
}
}
public function info(Request $request): JsonResponse
{
$geo = new Geolocation($request->server());
$info = $geo->getGeoInfo();
return response()->json([
'success' => true,
'data' => $info
]);
}
}<?php
// app/Http/Controllers/LocalizationController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Rumenx\Geolocation\Geolocation;
class LocalizationController extends Controller
{
public function setLanguage(Request $request, string $language): RedirectResponse
{
$availableLanguages = config('geolocation.available_languages', ['en']);
if (!in_array($language, $availableLanguages)) {
abort(404);
}
$cookieName = config('geolocation.language_cookie');
$duration = config('geolocation.cookie_duration', 43200);
return redirect()->back()
->withCookie(cookie($cookieName, $language, $duration));
}
public function autoDetect(Request $request): RedirectResponse
{
$countryToLanguage = config('geolocation.country_to_language');
$cookieName = config('geolocation.language_cookie');
$geo = new Geolocation($request->server(), $countryToLanguage, $cookieName);
$country = $geo->getCountryCode();
$language = $geo->getLanguageForCountry($country);
$duration = config('geolocation.cookie_duration', 43200);
if ($language) {
return redirect()->back()
->withCookie(cookie($cookieName, $language, $duration))
->with('message', "Language set to {$language} based on your location");
}
return redirect()->back()
->with('message', 'Could not detect language from location');
}
}// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\View;
use Rumenx\Geolocation\Geolocation;
public function boot()
{
View::composer('*', function ($view) {
if (request()->server()) {
$countryToLanguage = config('geolocation.country_to_language');
$geo = new Geolocation(request()->server(), $countryToLanguage);
$view->with([
'geoCountry' => $geo->getCountryCode(),
'geoLanguage' => $geo->getLanguageForCountry($geo->getCountryCode()),
'isLocalDev' => $geo->isLocalDevelopment(),
]);
}
});
}// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Blade;
public function boot()
{
Blade::directive('country', function ($expression) {
return "<?php
\$geo = new \Rumenx\Geolocation\Geolocation(request()->server());
echo \$geo->getCountryCode();
?>";
});
Blade::directive('ifCountry', function ($expression) {
return "<?php
\$geo = new \Rumenx\Geolocation\Geolocation(request()->server());
if (\$geo->getCountryCode() === {$expression}):
?>";
});
Blade::directive('endifCountry', function () {
return "<?php endif; ?>";
});
}{{-- resources/views/home.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Welcome from {{ $geoCountry ?? 'Unknown' }}!</h1>
@if($geoCountry === 'US')
<p>🇺🇸 Welcome to our US visitors!</p>
<p>Currency: USD | Timezone: America/New_York</p>
@elseif($geoCountry === 'DE')
<p>🇩🇪 Willkommen in Deutschland!</p>
<p>Currency: EUR | Timezone: Europe/Berlin</p>
@elseif($geoCountry === 'FR')
<p>🇫🇷 Bienvenue en France!</p>
<p>Currency: EUR | Timezone: Europe/Paris</p>
@endif
@if($isLocalDev)
<div class="alert alert-info">
<strong>Development Mode:</strong>
Geolocation simulation is active
</div>
@endif
</div>
@endsection{{-- resources/views/components/language-switcher.blade.php --}}
<div class="language-switcher">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button"
data-bs-toggle="dropdown">
{{ strtoupper(app()->getLocale()) }}
</button>
<ul class="dropdown-menu">
@foreach(config('geolocation.available_languages') as $lang)
<li>
<a class="dropdown-item {{ app()->getLocale() === $lang ? 'active' : '' }}"
href="{{ route('language.set', $lang) }}">
{{ strtoupper($lang) }}
</a>
</li>
@endforeach
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="{{ route('language.auto') }}">
🌍 Auto-detect
</a>
</li>
</ul>
</div>
</div>php artisan make:command GeolocationTestCommand<?php
// app/Console/Commands/GeolocationTestCommand.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Rumenx\Geolocation\Geolocation;
class GeolocationTestCommand extends Command
{
protected $signature = 'geo:test {country?}';
protected $description = 'Test geolocation functionality';
public function handle()
{
$country = $this->argument('country');
if ($country) {
$this->testCountrySimulation($country);
} else {
$this->testCurrentLocation();
}
}
private function testCurrentLocation()
{
$this->info('Testing current geolocation...');
$countryToLanguage = config('geolocation.country_to_language');
$geo = new Geolocation($_SERVER, $countryToLanguage);
$this->table(
['Property', 'Value'],
[
['Country', $geo->getCountryCode() ?: 'Not detected'],
['Language', $geo->getLanguageForCountry($geo->getCountryCode()) ?: 'Not detected'],
['IP', $geo->getIp()],
['Development Mode', $geo->isLocalDevelopment() ? 'Yes' : 'No'],
]
);
}
private function testCountrySimulation(string $country)
{
$this->info("Testing simulation for country: {$country}");
$countryToLanguage = config('geolocation.country_to_language');
$geo = Geolocation::simulate($country, $countryToLanguage);
$info = $geo->getGeoInfo();
$this->table(
['Property', 'Value'],
collect($info)->map(function ($value, $key) {
return [$key, is_array($value) ? json_encode($value) : $value];
})->toArray()
);
}
}<?php
// app/Console/Commands/GeolocationClearCommand.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class GeolocationClearCommand extends Command
{
protected $signature = 'geo:clear';
protected $description = 'Clear geolocation cookies and cache';
public function handle()
{
$cookieName = config('geolocation.language_cookie');
$this->info("Clearing geolocation data...");
$this->line("Cookie name: {$cookieName}");
// Instructions for manual clearing
$this->warn("To clear cookies, add this to your application:");
$this->line("Cookie::queue(Cookie::forget('{$cookieName}'));");
$this->info("Geolocation cache cleared!");
}
}<?php
// tests/Feature/GeolocationTest.php
namespace Tests\Feature;
use Tests\TestCase;
use Rumenx\Geolocation\Geolocation;
use Illuminate\Foundation\Testing\RefreshDatabase;
class GeolocationTest extends TestCase
{
public function test_homepage_shows_geolocation_data()
{
$response = $this->get('/');
$response->assertStatus(200);
$response->assertViewHas(['country', 'language', 'geoInfo']);
}
public function test_api_geolocation_endpoint()
{
$response = $this->getJson('/api/geolocation/detect');
$response->assertStatus(200)
->assertJsonStructure([
'success',
'data' => [
'country_code',
'language',
'ip',
'is_development'
]
]);
}
public function test_language_detection_middleware()
{
// Test with simulated German visitor
$this->withServerVariables([
'HTTP_CF_IPCOUNTRY' => 'DE'
]);
$response = $this->get('/');
$this->assertEquals('de', app()->getLocale());
}
public function test_country_simulation()
{
$geo = Geolocation::simulate('FR');
$this->assertEquals('FR', $geo->getCountryCode());
$this->assertContains(
$geo->getLanguageForCountry('FR'),
['fr', 'fr-FR']
);
}
}<?php
// tests/Unit/GeolocationServiceTest.php
namespace Tests\Unit;
use Tests\TestCase;
use Rumenx\Geolocation\Geolocation;
class GeolocationServiceTest extends TestCase
{
public function test_service_provider_binding()
{
$geo = app('geolocation');
$this->assertInstanceOf(Geolocation::class, $geo);
}
public function test_facade_access()
{
$country = \App\Facades\Geolocation::getCountryCode();
$this->assertIsString($country);
}
public function test_config_loading()
{
$languages = config('geolocation.available_languages');
$mapping = config('geolocation.country_to_language');
$this->assertIsArray($languages);
$this->assertIsArray($mapping);
}
}// routes/web.php
use App\Http\Controllers\LocalizationController;
use App\Http\Controllers\Api\GeolocationController;
// Language routes
Route::get('/language/{language}', [LocalizationController::class, 'setLanguage'])
->name('language.set');
Route::get('/language/auto-detect', [LocalizationController::class, 'autoDetect'])
->name('language.auto');
// API routes
Route::prefix('api')->group(function () {
Route::get('/geolocation/detect', [GeolocationController::class, 'detect']);
Route::get('/geolocation/info', [GeolocationController::class, 'info']);
});- 🎭 Local Development Simulation - Testing with different countries
- 🌍 Language Negotiation - Advanced language handling
- ⚙️ Configuration - Advanced configuration options
- 🔧 Troubleshooting - Common issues and solutions
Previous: Basic Usage | Next: Symfony Integration