I have a simple problem here.
Here's my code
route
Route::post('change-language', 'LanguageController#changeLanguage')->name('changeLanguage')->middleware('localization');
localization middlewware
public function handle($request, Closure $next)
{
if (session()->has('locale') && \App\Language::get('lang')->pluck('lang')->contains(Route::getFacadeRoot()->current()->parameter('locale'))) {
$lang = Route::getFacadeRoot()->current()->parameter('locale');
App::setLocale($lang);
session()->put('locale', $lang);
return $next($request);
}elseif(session()->has('locale') && !\App\Language::get('lang')->pluck('lang')->contains(Route::getFacadeRoot()->current()->parameter('locale'))){
$lang = 'id';
App::setLocale($lang);
session()->put('locale', $lang);
return $next($request);
}
}
changeLanguage functtion
public function changeLanguage(Request $req)
{
return redirect()->back();
}
As you can see in localization middleware, I change the language based on the route url. when I change the return of changeLocalization something like return redirect($req->lang) it work like a charm. but i want to redirect back to previous route. Is it possible to add or overriding the route paramater in back() function ?
The changeLanguage function should be responsible for actually changing the language and not just redirecting
Here's an example of how I do it
routes/web.php
Route::get('lang/{locale}', 'LocaleController#update')
->name('locale')
->where('locale', '(en|fr|ar)');
// Further filter in route regex (accepts only English, French and Arabic)
LocaleController.php
<?php
namespace Caddy\Http\Controllers;
class LocaleController extends Controller
{
public function update($locale)
{
// Check if the $locale passed is in the array config/app.php => locales
if (in_array($locale, config('app.locales'))) {
// Put the $locale in session with the same name as key
session(['locale' => $locale]);
}
// redirect back
return back();
}
}
Locale.php middleware
<?php
namespace Caddy\Http\Middleware;
use Closure;
class Locale
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$session_locale = session('locale');
if (in_array($session_locale, config('app.locales'))) {
// Keep the locale if already in session
$locale = $session_locale;
} else {
// Fallback to English if not defined
$locale = config('app.locale');
}
app()->setLocale($locale);
return $next($request);
}
}
Apply the middleware globally
Http\Kernel.php
protected $middlewareGroups = [
'web' => [
\Caddy\Http\Middleware\Locale::class,
],
Here's my config/app.php
'locale' => 'en',
'locales' => ['en', 'fr', 'ar'],
Testing
Go to domain.tld/about
Page is in English
Change the URL to domain.tld/lang/fr
You're redirected back to /about and page is in French
Hope this helps
Related
I use this guide: https://mydnic.be/post/how-to-build-an-efficient-and-seo-friendly-multilingual-architecture-in-laravel-v2
I have these routes and middleware:
$locale = request()->segment(1);
Route::middleware('localized')->prefix($locale)->group(function() {
Route::get('/contacts', 'ContactController#index');
Route::get('/page/{page}', 'PageController#index');
});
And middleware localized from Kernel.php -> routeMiddleware:
public function handle(Request $request, Closure $next)
{
if (!array_key_exists($request->segment(1), config('translatable.locales'))) {
$segments = $request->segments();
$segments = Arr::prepend($segments, config('app.fallback_locale'));
if($request->session()->has('language')) {
$segments[0] = session('language');
}
return redirect()->to(implode('/', $segments));
}
return $next($request);
}
When I access to: site.test/contacts he redirect me on locale: site.com/en/contacts
When I access to site.test/page/test I got 404 not found, If I access to: site.com/en/page/test then page working. Problem with redirect on locale with route model binding.
In Controller Page I have:
public function index(Page $page)
{
return view('page', compact('page'));
}
In translatable.php:
'locales' => [
'de' => 'Deutsch',
'en' => 'English',
],
In AppServiceProvider:
public function boot()
{
if(array_key_exists(request()->segment(1), config('translatable.locales'))) {
app()->setLocale(request()->segment(1));
}
}
I was able to work around this but this cost us access to the session, which you checked for to know if the session has "language" if yes, then prepend locale value should be set to the language value in the session. Below is what I did;
In Routes File
$locale = request()->segment(1);
Route::prefix($locale)->group(function() {
Route::get('/contacts', function(){
echo "hello contact";
});
Route::get('/page/{page}', function(Request $request, $page){
return "hello Page {$page}";
});
});
In MiddleWare File I did
public function handle(Request $request, Closure $next)
{
if (!array_key_exists($request->segment(1), config('translatable.locales'))) {
$segments = $request->segments();
$segments = Arr::prepend($segments, config('app.fallback_locale'));
// Remove the session check as we don't have access to session yet
/*if($request->session()->has('language')) {
$segments[0] = session('language');
}*/
return redirect()->to(implode('/', $segments));
}
return $next($request);
}
Now in Kennel.php File for Middleware, Add your middleware class in the $middleware array
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
...
\App\Http\Middleware\Localized::class, //This is the Localized Middlewere class
];
Then try access site.test/page/1000 ... it will be redirected to site.test/{app.fallback_locale}/page/1000. In my case site.test/en/page/1000
UPDATE
After reading through this issue on git for laravel, I then thought of adding the session before the Localized middle class and it worked. I'm not sure if this is good practice but it got the job done.
In MiddleWare File I did
public function handle(Request $request, Closure $next)
{
if (!array_key_exists($request->segment(1), config('translatable.locales'))) {
$segments = $request->segments();
$segments = Arr::prepend($segments, config('app.fallback_locale'));
// We can have session back on
if($request->session()->has('language')) {
$segments[0] = session('language');
}
return redirect()->to(implode('/', $segments));
}
return $next($request);
}
Now in Kennel.php File for Middleware, Add Session middleware before Localized Middleware class
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
...
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\Localized::class, //This is the Localized Middlewere class
];
I have a view (resources/view/front/auth/profile.blade.php) and my route in file web.php is:
Route::get('/profile/{user}','UserController#edit')
->name('profile')
->middleware('profilecheck');
My problem is that when a user logs in and gets redirected to their own profile page (http://exmaple.com/profile/2), he/she can change the URL to http://exmaple.com/profile/3 and see other users' profile.
I want to use a middleware to check authenticated users id with URL parameter {user}. The $user->id will passed to the {user}, but I have no idea how.
Middleware UserProfile.php:
<?php
namespace App\Http\Middleware;
use App\User;
use Closure;
class UserProfile
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
// $request->user()->id
// Auth::user()->id
return $next($request);
}
}
You can protect the route simply by removing the user id from the URL, but getting it through the authentication session instead.
So, your route signature should goes from:
Route::get('/profile/{user}', 'UserController#edit')->name('profile');
To this:
Route::get('/profile', 'UserController#edit')->name('profile');
So, in your controller, instead of getting the user id from the request:
public function edit(Request $request)
{
$user = User::findOrFail($request->id);
// ...
}
You could get the logged-in User through the Auth facade:
use Illuminate\Support\Facades\Auth;
public function edit(Request $request)
{
$user = Auth::user();
// ...
}
or just the auth() helper:
public function edit(Request $request)
{
$user = auth()->user();
// ...
}
This way, you are masking the URL to avoid a malicious user of doing things that he/she shouldn't.
You need to do something like this.
Your route
Route::get('/profile', [
'uses' => 'UserController#profile',
'middleware' => 'profilecheck'
]);
Your middleware
class CheckUserMiddleware
{
public function handle($request, Closure $next)
{
if(!auth()->user()) {
return redirect()->route('login');
}
return $next($request);
}
}
// Controller
public function index()
{
if (Auth::check() && Auth::user()->role->id == 2) {
return view('author.setting.settings');
} else {
Toastr::info('you are not authorized to access', 'Info');
return redirect()->route('login');
}
}
// Route
Route::group(['as'=>'user.','prefix'=>'user','namespace'=>'Author','middleware'=>['auth','user']], function (){
Route::get('/setting','SettingsController#index')->name('settings.settings');
});
I have a table of posts with language column "lang" , i want to display in view only the posts with the language stored in session.
But what i keep getting always is only the posts with the default language (Fr)
Controller :
public function index(Request $request)
{
if ($request->session()->has('en')) {
$posts = Post::where('lang','=','En')
->with('author','tags','category','comments')
->latestFirst()
->filter(request()->only(['term', 'year', 'month']))
}
elseif ($request->session()->has('ar')) {
$posts = Post::where('lang','=','Ar')
->with('author','tags','category','comments')
->latestFirst()
->filter(request()->only(['term', 'year', 'month']))
}
else {
$posts = Post::where('lang','=','Fr')
->with('author','tags','category','comments')
->latestFirst()
->filter(request()->only(['term', 'year', 'month']))
}
return view("blog.index", compact('posts'));
}
Get the current locale from the app instance and fallback to Fr since it's the default
public function index(Request $request)
{
$locale = ucfirst(app()->getLocale());
$posts = Post::where('lang', $locale)
->with('author', 'tags', 'category', 'comments')
->latestFirst()
->filter(request()->only(['term', 'year', 'month']));
return view("blog.index", compact('posts'));
}
Hope this helps
That's because there is no session value with the key 'Ar' or 'En'.
You have 2 options. Through a middleware or in a trait that you can use in controller classes where needed.
Beware that if you use this option that I'm going to publish, it's a problem for search robots to pick it up as the URL is exactly the same. For my project that didn't matter, but it could for yours. If yo don't wan this, you will have to opt to add it to your routes (https://yourweb.site/en/your_urls)
If you opt to use the middleware, to change the language you have to add in any route ?lang=en or ?lang=fr only once after which your session will remember the choice.
The middleware
namespace App\Http\Middleware;
use Closure;
class Language
{
/**
* The availables languages.
*
* #array $languages
*/
protected $languages = ['en', 'ar', 'fr'];
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->session()->has('lang'))
{
$request->session()->put('lang', $request->getPreferredLanguage($this->languages));
}
if ($request->has('lang'))
{
$request->session()->put('lang', $request->get('lang'));
}
app()->setLocale($request->session()->get('lang'));
return $next($request);
}
}
If a new visitor arrives, he or she will be served in the preferred language, in your case French. Any choice to another language is now preserved as session('lang') anywhere in your code.
$posts = Post::where('lang','=', session('lang', 'fr')->...
I set locale in middleware using session variable and it is working perfectly except 404 page. As I understood, neither session variables nor middleware works in exception handler. Here is my code:
Route:
Route::get('setlocale/{locale}', function ($locale) {
if (in_array($locale, \Config::get('app.locales'))) {
Session::put('locale', $locale);
}
return redirect()->back();
})->name('lang.switch');
Middleware:
class Language
{
public function handle($request, Closure $next)
{
$raw_locale = Session::get('locale');
if (in_array($raw_locale, Config::get('app.locales'))) {
$locale = $raw_locale;
} else $locale = Config::get('app.locale');
App::setLocale($locale);
return $next($request);
}
}
Any ideas?
If i go to http://www.yourdomain.com/admin/login i see my login page.
If i go to http://www.yourdomain.com/admin/example i have the redirect to http://www.yourdomain.com/login without the admin.
My web routes:
Auth::routes();
Route::prefix('admin')->group(function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
When i put some url with the /admin before and user isn't logged, i want to redirect to /admin/login.
Thanks.
More info:
App/http/Controllers/Auth/AdminLoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
class AdminLoginController extends Controller
{
protected $loginPath = 'admin/login';
public function __construct()
{
$this->middleware('guest:admin', ['except' => ['logout']]);
}
public function showLoginForm()
{
return view('backend.public.pages.login');
}
public function login(Request $request)
{
//validate the form data
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:6'
]);
//attempt to log the user in
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)){
//if successful, then redirect to their intended location
return redirect()->intended(route('admin.dashboard'));
}
return redirect()->back()->withInput($request->only('email','remember'));
}
public function logout()
{
Auth::guard('admin')->logout();
return redirect('/');
}
}
App\Http\Middleware\AdminAuthenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
Create an middleware
php artisan make:middleware AuthAdmin
Check for guest in the handle method of the middleware
public function handle($request, Closure $next)
{
if (Auth::guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('admin/login');
}
}
return $next($request);
}
Add a key to the middleware in app/Http/Kernel.php in $routeMiddleware array
'auth_admin' => \App\Http\Middleware\AuthAdmin::class
Attach the auth_admin middleware to the group
Route::group(['prefix' => 'admin', 'middleware' => 'auth_admin'], function() {
// Your admin routes except login
});
write bellow code in your route.php file
Route::group(array('prefix' => 'admin'), function() {
Route::controller('login', 'AdminloginController');
});
Route::group(array('before' => 'admin_ajax', 'prefix' => 'admin'), function()
{
//route for pages which are render after login
});
Route::get('/admin', function() {
return View::make('admin.loginform');
});
And Write bellow code in your filter.php file
Route::filter('admin_ajax', function() {
if (!Auth::admin()->check()) {
return Redirect::to('admin/login');
} else {
}
});
And if you are using laravel 5.4
Route::get('/manage', function () {
return redirect('manage/login');
});
Route::group(['prefix' => 'manage'], function() {
//login bypass for the below listed controllers
Route::resource('login', 'AdminLoginController#showLoginForm');
Route::post('dologin', 'AdminLoginController#login');
});
All you can do is add the auth middleware like this :
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
But by default this will redirect to /login, if you want to override this you have two chocies depending on if you have other type of users that uses the /login route or not !!
If NO ONE uses /login route
1- You need to modify App\Http\Middleware\Authenticate::handle() method and change /login to admin/login.
2- Then you need to add $loginPath property to your \App\Http\Controllers\Auth\AuthController class.
Authenticate
namespace App\Http\Middleware;
class Authenticate {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
AuthController
namespace App\Http\Controllers\Auth;
class AuthController extends Controller
{
protected $loginPath = 'admin/login'; // <--- here
// ... other properties, constructor, traits, etc
}
If there is someone using /login route
You must create you own middleware and do what it takes for auth checking in the handle method with redirecting to your admin/liging route :)
In this case :
Add the following line in $routeMiddleware property at app/Http/Kernel.php file
'adminAuth' => \App\Http\Middleware\YourNewMiddleware::class,
Don't forget to add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'adminAuth'], function()
{
// your admin routes
});
Make an another middleware for admin. follow the step
Make a file named AdminAuthenticate in app/Http/Middleware location and copy the content of Authenticate in New file
change the Class name as AdminAuthenticate
Change the content of handle function as show below
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/admin/login');
}
}
return $next($request);
}
Add the following line in $routeMiddleware array at app/Http/Kernel.php file
'AdminAuth' => \App\Http\Middleware\AdminAuthenticate::class,
Now everything is okay. just add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'AdminAuth'], function()
{
// all admin routes
});
Or you can add new middleware to constructor function of every admin controller as like below
$this->middleware('AdminAuth');