Skip to content

Laravel Integration

Rumen Damyanov edited this page Jul 31, 2025 · 1 revision

Laravel Integration Guide

Complete guide to integrating php-geolocation with Laravel applications.

Table of Contents

Installation & Setup

Install Package

composer require rumenx/geolocation

Service Provider (Optional)

Create 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,
],

Configuration File

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'),
];

Service Provider Configuration

Facade (Optional)

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,
],

Usage with Facade

use App\Facades\Geolocation;

// In controllers
$country = Geolocation::getCountryCode();
$language = Geolocation::getLanguageForCountry($country);

Middleware Integration

Create Geolocation Middleware

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);
    }
}

Language Detection Middleware

<?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;
    }
}

Register Middleware

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,
];

Controller Examples

Basic Controller Usage

<?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);
    }
}

API Controller

<?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
        ]);
    }
}

Localization Controller

<?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');
    }
}

Blade Template Integration

Service Injection

// 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(),
            ]);
        }
    });
}

Blade Directives

// 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; ?>";
    });
}

Template Examples

{{-- 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

Language Switcher Component

{{-- 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>

Artisan Commands

Geolocation Test Command

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()
        );
    }
}

Cache Clear Command

<?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!");
    }
}

Testing in Laravel

Feature Tests

<?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']
        );
    }
}

Unit Tests

<?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 Example

// 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']);
});

Next Steps


Previous: Basic Usage | Next: Symfony Integration

Clone this wiki locally