Laravel 5.5 multi language application - php

I followed this article on how to make your site multi language.
But I don't understand why I always get an error when I surf to hoemstead.app/lang/en for example.
The error:
Sorry, the page that you're looking for does not exist
My LanguageController
use Config;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
class LanguageController extends Controller
{
public function switchLang($lang)
{
if (array_key_exists($lang, Config::get('languages'))) {
Session::put('applocale', $lang);
}
return Redirect::back();
}
}
My routes:
Route::get('lang/{lang}', ['as'=>'lang.switch', 'uses'=>'LanguageController#switchLang']);
My Language Middleware
use Closure;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Session;
class Language
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Session::has('applocale') AND array_key_exists(Session::get('applocale'), Config::get('languages'))) {
App::setLocale(Session::get('applocale'));
}
return $next($request);
}
}
I've also added this middleware to my Kernel.php file
My Languages.php file in the config folder
return [
'en' => 'English',
'nl' => 'Nederlands',
'fr' => 'Français',
];

Related

Laravel route middleware outputting my log

I'm trying to run some middleware on my routes via my package's service provider before the routes run in my Laravel project but I'm not seeing my var_dump despite running php artisan route:list showing that the BeforeMiddleware is applied. Am I using the wrong middleware?
My service provider:
<?php
namespace Company\FudgeInboundManagementBridge;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Company\FudgeInboundManagementBridge\Http\Middleware\BeforeMiddleware;
class FudgeInboundManagementBridgeServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
$this->registerFiles();
}
/**
* Register files
*/
protected function registerFiles(): void
{
Route::middleware(BeforeMiddleware::class)->group(function () {
$this->loadRoutesFrom(__DIR__.'/routes/fudge-routes.php');
});
$this->publishes([
__DIR__ . '/config/FudgeInboundManagementBridge.php' => config_path('FudgeInboundManagementBridge.php'),
], 'config');
}
}
My middleware:
<?php
namespace Company\FudgeInboundManagementBridge\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class BeforeMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
var_dump('hello from before middleware - bridge');
die;
// return $next($request);
}
}
Seems like it's not triggering?

How to call a method, function or initialize class after an middleware in a controller constructor in Laravel and Lumen?

How to call a method, function or initialize class after an middleware in a controller constructor in Laravel and Lumen?
I try initialize class Translator after middleware('lang'), but class Translator initialized before execute middleware('lang').
Controllers/IndexController.php
<?php
namespace App\Http\Controllers;
use Laravel\Lumen\Routing\Controller;
use App\Helpers\Translator;
class IndexController extends Controller
{
private $transhome;
public function __construct()
{
$this->middleware('lang');
$this->transhome = new Translator('home');
}
public function home()
{
return view('home', [
'transhome' => $this->transhome,
]);
}
}
Middleware/LangMiddleware.php
use Closure;
class LangMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
config(['app.lang' => 'fr']);
return $next($request);
}
}
Another example
After execution we will see: 132
$this->middleware('lang'); the last will be called
Controllers/IndexController.php
<?php
namespace App\Http\Controllers;
use Laravel\Lumen\Routing\Controller;
class IndexController extends Controller
{
public function __construct()
{
echo '1';
$this->middleware('lang');
echo '3';
}
public function home()
{
return view('home');
}
}
Middleware/LangMiddleware.php
use Closure;
class LangMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
echo '2';
return $next($request);
}
}
Actually, this should work because you have the $transhome as private above. Try this with public.
It should work because in the constructor you tell it to set it to a translator.
Have you ever looked with dd() if transhome returns null?

laravel feature tests with locales

I am new to Laravel and I am having an issue to write a test function that asserts that the HTTP response of my welcome page is 200 knowing that I have EN and FR locales defined, meaning that the test should test both localhost:8000/en and localhost:8000/fr.
This is my exampletest.php:
<?php
namespace Tests\Feature;
use App\Http\Middleware\SetLanguage;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testBasicTest()
{
$response = $this->get('/');
$response->assertStatus(301);
}
public function test_getRedirected_DefaultedEnglish_WelcomePage()
{
$response = $this->get('/en');
$response->assertStatus(200);
}
public function test_getRedirected_French_WelcomePage()
{
$response = $this->get('/fr');
$response->assertStatus(200);
}
}
I don't like writing the code twice for both /en and /fr.
This is my web.php:
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
Route::redirect('/', 'en', 301);
Route::group(['prefix' => '{lang}', 'where' => ['lang' => '[a-zA-Z]{2}'], 'middleware' => 'setlanguage'], function() {
Auth::routes();
Route::get('/','App\Http\Controllers\welcomeController#index')->name('welcome');
});
And i have written my localization middleware below:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
class SetLanguage
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
App::setLocale($request->lang);
return $next($request);
}
}
I would appreciate your help on the above. I believe the test should be dynamic.
Thank you in advance..
I don't think there's any way around repeating yourself if you want to test multiple locales. But there's no requirement to put each test in a separate method. This may work, but I've never done testing on multiple locales in my applications.
public function provideLocales(): array
{
return [
"english" => ["en"],
"francais" => ["fr"],
];
}
/**
* #dataProvider provideLocales
*/
public function testWelcomePage($locale): void
{
$this->app->setLocale($locale);
$this->get(route("welcome"))
->assertStatus(200);
}
You could take this further and actually check that the localized content is being served correctly.
public function provideLocales(): array
{
return [
"english" => ["en", "welcome"],
"francais" => ["fr", "bienvenue"],
];
}
/**
* #dataProvider provideLocales
*/
public function testWelcomePageContents($locale, $text): void
{
$this->app->setLocale($locale);
$this->get(route("welcome"))
->assertStatus(200)
->assertSeeText($text);
}

Request a url in Middleware but get Class 'App\Http\Middleware\Request' not found

I use Request::path() in \routes\web.php as follow and visit '/home/test/test1' worked well, i.e., the path is shown in the website.
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/home/test/test1', function(){
echo Request::path();
});
However, when I did it in \app\Http\Middleware, the error "Class 'App\Http\Middleware\Request' not found" showed up.
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAuth
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$path = Request::path();
return $next($request);
}
}
You missed in your Middleware file:
use Illuminate\Http\Request;
Change your Middleware code to:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Closure;
class CheckAuth
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$path = $request->path();
return $next($request);
}
}
That should fix it.
Reference: https://laravel.com/docs/5.8/requests#request-path-and-method
Actually you missed to add the reference in the middleware file. So add use Illuminate\Http\Request; at below the namespace. Then Error should be fixed.

Laravel | Middleware binding not accessible in controller

I have a middleware which just grabs the sub domain and binds it to the Store model.
<?php
namespace App\Http\Middleware;
use Closure;
use App\Models\Store;
class SubDomain
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
$sub_domain = array_first(explode('.', $request->getHost()));
app()->bind(Store::class, function () use ($sub_domain) {
return Store::query()->where('sub_domain', $sub_domain)->firstOrFail();
});
return $next($request);
}
}
However, when I am inside of a controller I am trying to extend it so I can always do $this->store->id or something alike however, the Store isn't getting found.
<?php
namespace App\Http\Controllers;
use App\Models\Store;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/**
* #var Store
*/
protected $store;
/**
* Controller constructor.
*
* #param Store $store
*/
public function __construct(Store $store)
{
$this->store = $store;
}
}
The store is always just a basic model with no data.
This is my route:
Route::group(['middleware' => ['auth', 'sub_domain'], 'prefix' => 'admin'], function () {
Route::get('/dashboard', 'Admin\DashboardController#index');
});
And I have registered the sub_domain middleware inside of the Kernel.
The service container and model do not work how you are expecting in your code. So try with the following code snippet inside the controller's method. You may get what you are looking for.
$store = app(Store::class);
dd($store);
You want to bind an instance of a model so use app()->instance(Store::class, $store)
ref: https://laravel.com/docs/5.7/container#binding

Categories