Not all PHP developers are fans of Laravel. Well that’s probably because most of them haven’t worked with it. I’ve been working with the framework for more than a year now. Sure there were some teething troubles initially. But the framework has now grown on me.
When it comes to large-scale applications especially, development and management is simplified. And you’ve always got fellow developers helping you out with hurdles along the way.
So, looking at how Laravel tips and tricks can help others, I decided to write this post on a recent piece of code I recently wrote.
Handling Country Specific URLs
Many-a-times, e-stores or websites across the web, service different countries or regions. Possibly to provide users with a more personalized experience. For example, websites might change their language, currency, or filter products based on the country the visitor is from.
In such a case, there is a need to handle country specific URLs. So, if you take the case of Amazon, there’s Amazon.com, Amazon.es, Amazon.de, and so on, that serve content in different languages. There could also be a case that a person browsing from Spain might search for Amazon.com, but would have to be redirected to the more relevant, Amazon.es.
Such a situation is pretty common, and if you had a similar requirement when working with Laravel, here’s what you would need to do.
Do note, the below code has been tested on Laravel 5.3 and 5.2.
So first we need to start by creating a country table in the database to store the country name and country shortcode. This information will be used to handle the URLs.
Create Migration for Country Table
Start by migrating to your project folder; in your command prompt type:
php artisan make:migration country_table
This will create a migration file in database/migration/ folder. Next, open county_table migration file and enter the following:
(Note: the Schema used here is only for demonstration purpose and you need to make the necessary changes according to your database architecture)
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; class CountryTable extends Migration { /** * Run the migrations. */ public function up() { Schema::create('country', function (Blueprint $table) { $table->increments('id'); $table->string('country_name'); $table->string('country_shortcode')->unique(); // the country shortcode that will be used in the URL $table->tinyinteger('is_active'); // to enable or disable a country(1 for enable , 0 for disable) }); } /** * Reverse the migrations. */ public function down() { Schema::drop('country'); } }
Create Country Model
php artisan make:model Country
Open the model file which is created in App folder and make necessary changes:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Country extends Model { /** * The table associated with the model. * * @var string */ protected $table = 'country'; }
Create Seeder File for Country Table
php artisan make:seeder CountrySeeder
Open the CountrySeeder file present in database/seeds/ folder and enter the following:
<?php use Illuminate\Database\Seeder; class CountrySeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('country')->insert([ [ 'country_name' => 'India', 'country_shortcode' => 'in', 'is_active' => 1, ], [ 'country_name' => 'United States', 'country_shortcode' => 'us', 'is_active' => 1, ], [ 'country_name' => 'United Kingdom', 'country_shortcode' => 'uk', 'is_active' => 1, ], ]); } }
The above code will create entries in country table for India, United States and United Kingdom. You will need to add countries as per your requirements.
Include the following line under run() function in database/seeds/DatabaseSeeder.php file:
$this->call(CountrySeeder::class);
Migrate Refresh Tables and Seed them
This will delete all tables and create them once again along with the country table and will seed it with the seeder data.
Note: Do NOT use refresh on a production site, as it will wipe out all your data!
php artisan migrate:refresh --seed
Create Country Middleware
The middleware will check for the validity of the country in the URL and if valid, will set the corresponding country in a country session or if invalid will redirect to ‘/’ router.
php artisan make:middleware CountryMiddleware
This will create Country middleware file in app/http/middleware folder. Open the folder and then enter in the following code.
<?php namespace App\Http\Middleware; use App\Country; //country model use Closure; use Request; use Route; class CountryMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return mixed */ public function handle($request, Closure $next) { $countryShortcode = $request->route('country'); //get country part from url $country = Country::where('country_shortcode', '=', $countryShortcode)->where('is_active', '=', 1)->first(); if ($country === null) { return redirect('/'); } $request->session()->put('country', $country); $request->session()->save(); return $next($request); } }
In certain cases you would need to redirect a page to a particular country. For example, suppose you want to redirect a person on login to a country specific page based on his location.
In such a case what you can do, is set a redirect_to_country (choose your variable name) session while the action is performed (in our example- login) and check the value of the session in country middleware.
Modify the handle function as shown bellow:
<?php public function handle($request, Closure $next) { $countryShortcode = $request->route('country'); $routeName = $request->route()->getName(); $routeParameters = $request->route()->parameters(); if ($request->session()->has('redirect_to_country')) { $redirectTo = $request->session()->get('redirect_to_country'); if ($country === $redirectTo) { $request->session()->forget('redirect_to_country'); } else { $routeParameters['country'] = $redirectTo; return redirect()->route($routeName, $routeParameters); } } $country = Country::where('country_shortcode', '=', $countryShortcode)->where('is_active', '=', 1)->first(); if ($country === null) { return redirect('/'); } $request->session()->put('country', $country); $request->session()->save(); return $next($request); }
You need to now register your Middleware in app/Http/Kernel.php. Within Kernel.php, add a ‘country’ middleware group in $middlewareGroups as shown below
protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', 'bindings', ], 'country' =>[ 'web', \App\Http\Middleware\CountryMiddleware::class ], ];
Since we are using sessions in our Middleware, we are dependent on the following middleware classes:
\Illuminate\Session\Middleware\StartSession::class
\Illuminate\View\Middleware\ShareErrorsFromSession::class
The above middlewares are already included in ‘web’ middleware group. Hence we simply include ‘web’ middleware group in our ‘country’ middleware group just before our country middleware class.
Route through the Middleware
Now, to finally handle the URLs, add the following line in your route file.
- for Laravel 5.1, 5.2 routes.php file is found in app/Http/ folder
- for Laravel 5.3 add the routes to routes/web.php file
Route::group(['prefix' => '{country}', 'middleware' => 'country'], function () { Route::get('/test', function ($country, Illuminate\Http\Request $request) { return $request->session()->get('country'); }); });
Testing the Code
Now that all changes have been made, you can check if all is okay by testing your code. Here’s what you can do, try fetching http://domain/in/test , this should return details of India from the session.
Also try http://domain/gg/test; since ‘gg’ is an invalid code, you should be redirected to http://domain (where domain is the ‘domain name:port’ of your Laravel project (e.g. localhost:8080))
Well and that is it!
Do let me know if this code helped…. or if you have any doubts in our comments!
Stay tuned for more such Laravel tips and tricks from me!
5 Responses
Great tutorial, will implement and revert back thanks
I have tried your code and receiving class Country not found
hi,
if i define any route inside middleware flash message not working. please help me.
Ex.- return redirect()->back()->with(‘success’,’Contact saved Successfully’); not working.
Hi Can u do me one favor like, I want to display different pages for different location basis with their iso code . Is with different location based
As exmple : https:// example.com/in/page_name
Very good article. I’m experiencing many of these issues as well..