Display data in view based on session - php

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')->...

Related

Laravel all() method on Model returning null within Collection

I am not sure, what is going on here. I have a collection of Model ID's but want to fallback on using all if specific ID's are omitted.
So I have this code:
use App\Models\Post;
function list($ids = [])
{
$posts = collect($ids)->whenEmpty(function ($posts) {
return Post::all()->pluck('id');
})->each(function ($item, $key) {
$post = Post::findOrFail($item);
});
}
Works fine if I pass in specific IDs via $ids. But when I leave it blank Post::all()->pluck('id'); inside of whenEmpty() returns empty. But if I call Post::all()->pluck('id'); outside the collection it works just fine. So I thought it might be some sort of scoping issue since its inside a closure, but changing it to:
use App\Models\Post;
function list($ids = [])
{
$posts = collect($ids)->whenEmpty(function ($posts) {
return \App\Models\Post::all()->pluck('id');
})->each(function ($item, $key) {
dd($item);
});
}
Is still showing up as "" If I dd() the whole collection its just:
[
0 => ""
]
So even providing the whole namespace isn't working. What am I missing here?
Here it's one approach more
function list(array $ids = [])
{
if(empty($ids)) $posts = Post::all();
else $posts = collect($ids)->map(function($id) {
return Post::findOrFail($id);
});
$posts->each(...); /* collection */
}
if you want to use whenEmpty()
function list(array $ids = [])
{
collect($ids)->map(function($id) {
return Post::findOrFail($id);
})->whenEmpty(function($posts){
return $posts = Post::all();
})->each(...);
}
I know this might not directly answer your question (because I would do this in a different way) but maybe it's helpful for you or others in the same situation.
What I would do is using a Request class to validate the introduced IDs like this:
use Illuminate\Validation\Rules\Exists;
class PostsRequests extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'ids' => ['array'],
'ids.*' => ['numeric', new Exists('posts','id')],
];
}
/**
* Handle a passed validation attempt.
*
* #return void
*/
public function passedValidation()
{
$this->ids = $this->validated()['ids'];
}
}
This way you make sure all the IDs introduced in the array exist in the posts table. Otherwise, the request fails.
Now that you know all the IDs are valid, you can simply check if the array is empty or not:
class PostController extends Controller
{
public function list(PostsRequests $request)
{
$posts = empty($request->ids) ? Post::all() : Post::whereIn('id', $request->ids])->get();
}
}
UPDATE
Since the array of IDs is not coming from a request, you can use a Validator in the controller itself:
use Illuminate\Validation\Rules\Exists;
use Illuminate\Support\Facades\Validator;
class PostController extends Controller
{
public function list(array $ids)
{
Validator::make($ids, [
'*' => ['numeric', new Exists('posts','id')],
])->validate();
$posts = empty($ids) ? Post::all() : Post::whereIn('id', $ids])->get();
}
}

Laravel route locale middleware not working with model binding

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

is it possible to overriding a parameter within back() function

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

how can Prevent access another page with 3 type users in Laravel

i have problem with laravel cus im begginer but i work with php languge very well
and my Question:
I created a table for users in my database and create column for type
There are 3 user types in my table:
customers - Workers - Factories
How can i use middlewarre or anything else Prevent access to other pages
public function Signupuser(Request $request){
$email=$request['email'];
$username=$request['username'];
$tell=$request['mobilenumber'];
$pass=bcrypt($request['password']);
$status_reg=$request['status_register'];
$usertable=new UserTable();
$usertable->username=$username;
$usertable->email=$email;
$usertable->Password=$pass;
$usertable->Tell=$tell;
$usertable->StatusReg=$status_reg;
$usertable->save();
Auth::login($usertable);
if($status_reg=='factory'){
return redirect()->route('FactoryDashboard');
}
if($status_reg=='worker'){
return redirect()->route('WorkerDashboard');
}
if($status_reg=='customer'){
return redirect()->route('CustomerDashboard');
}
}
public function signinuser(Request $request){
$email=$request['email'];
$pass=$request['pass'];
if (Auth::attempt(['email'=>$email,'password'=>$pass])){
$status = Auth::user()->StatusReg;
return $status;
}
else{
return "nokey";
}
}
i used with one middleware but this middleware dosent work
<?php
namespace App\Http\Middleware;
use App\UserTable;
use Closure;
class WorkerMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->user() && $request->user()->StatusReg !='worker'){
return redirect('homepage');
}
return $next($request);
}
}
please help guys
Your scenario is usually dealt with by using the Authorization service of Laravel.
For example, you could add the following to your app\Providers\AuthServiceProvider.php file:
Gate::define('factory', function ($user) {
return $user->StatusReg == 'factory';
});
Gate::define('worker', function ($user) {
return $user->StatusReg == 'worker';
});
Gate::define('customer', function ($user) {
return $user->StatusReg == 'customer';
});
And then you can use it in your application like the following:
if (Gate::allows('worker')) {
//...
}
if (Gate::denies('customer')) {
//...
}
There are plenty more usage examples in the docs:
https://laravel.com/docs/5.6/authorization

Check another columns on login with default auth on Laravel 5

This is my first attempt at using a php framework, so I decided to go with Laravel 5.
But I have a problem: I want to check the user status at login, so only enabled == 1 users get to login. I checked AuthenticatesAndRegistersUsers.php, and followed some functions on Guard.php, but I could not understand where does it check the actual columns, and where I should place my check for the column is_enabled.
Some people probably won't agree with me, but I'd make my own Auth Controller. The default one is too obscure. If you want you can remove everything that comes with laravel with php artisan fresh, this will remove the Auth Controller and a bunch of other things.
It is quite simple to make your own, the login method would look something like this:
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
$remember = $request->get('remember') == 'on' ? true : false;
if(\Auth::attempt($credentials, $remember)) {
$enabled = \Auth::user()->enabled;
if(!$enabled) {
\Auth::logout();
return redirect()->withMessage('User not enabled to login');
}
}
}
Check the docs for other authentication functions:
http://laravel.com/docs/5.0/authentication
You can also check the user in the DB before attempting:
$enabled = User::where('email', '=', $email)->first()->enabled;
if($enabled && \Auth::attempt($credentials, $remember)) {
... redirect to logged in page.
As per reference from this link, let say if there is another column approved that need to be checked during login, then following function need to be added in loginController
public function credentials(Request $request)
{
$credentials = $request->only($this->username(), 'password');
$credentials = array_add($credentials, 'approved', '1');
return $credentials;
}
You could use the authenticated method in the default LoginController. This method is called whenever a user passed the configured authentication guard.
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
// custom logic
if ($user->isDisabled()) {
$logoutResponse = $this->logout($request);
if ($logoutResponse instanceof RedirectResponse) {
$logoutResponse->withErrors(__('users.Your account has been deactivated'));
}
return $logoutResponse;
}
// end custom logic
return null;
}
By inspecting the AuthenticatesUsers trait form Laravel, it is made clear that the return value of this method is used in an if statement so it is fine to just return null when we want the default behavior:
/**
* Send the response after the user was authenticated.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
if ($response = $this->authenticated($request, $this->guard()->user())) {
return $response;
}
return $request->wantsJson()
? new Response('', 204)
: redirect()->intended($this->redirectPath());
}

Categories