Can't get session variables in AppServiceProvider - php

I would like to share some variables from session in all views in Laravel 8. According to documentation I call View::share() method in AppServiceProvider:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
// Variables shared in all views.
View::share('showModal', session('showModal'));
}
}
The problem is that although the session showModal key is really set, I can't get it in AppServiceProvider::boot(). If I call session('showModal') in the controller on in view I can see the correct value. Only AppServieProvider returns null.
Can somebody explain please what is wrong with this code?

Well, alternatively, you could set up a middleware to be responsible for updating your session variable before the call in view.
Below is something I implemented for setting/retrieving the user permissions before the call in view.
STEP 1
Generate the middleware: php artisan make:middleware GetPermissions
You will find the middleware in App\Http\Middleware directory.
STEP 2
Add your logic for setting your session variable in the new middleware's handle method.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class GetPermissions
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$request->session()->put("permissions", optional(auth()->user(), function ($user) {
return $user->permissions()->pluck("name")->toArray();
}) ?? []);
return $next($request);
}
}
STEP 3
Register your middleware in the protected $middlewareGroups array of App\Http\Kernel.php class file.
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// ...
protected $middlewareGroups = [
'web' => [
// ...
\App\Http\Middleware\GetPermissions::class,
],
// ...
}
With that setup, every time a request is made, the latest values of your session variable will be set.
You will then have access to latest session variable value in your helperfiles, controllers as whereas views.
Demo for accessing it in views:
{{session("permissions")}}

Related

Add middleware to controller in __construct in Laravel

I am trying to assign a middleware in __construct of a controller based on Laravel docs but it throws the follwing error:
BadMethodCallException
Method App\Http\Controllers\MyController::middlware does not exist.
that is my controller class:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class MyController extends Controller
{
public function __construct()
{
$this->middleware('myauth');
}
/** something */
public function index()
{
return view('test.hi', ['name' => 'Moh']);
}
}
And here is the middleware code:
<?php
namespace App\Http\Middleware;
use Closure;
class myauth
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
echo time().'<br>';
return $next($request);
}
}
Laravel version: 6.5.2
Where am I doing wrong?
Middleware can be specified within controller's constructor
public function __construct() {
$this->middleware('auth');
}
For whole controller:
$this->middleware('auth');
Only for a particular action:
$this->middleware('auth')->only('index');
For whole controller except particular action:
$this->middleware('auth')->except('store');
The function is middleware, you have a typo, missing an e.
Firstly ask to you, Your error is middlware name is incoorect you missed e after that check the below middleware process.
Laravel Middleware - Middleware acts as a middleman between a request and a response.
Firstly goto project folder and open cmd and use this command
php artisan make:middleware MiddlewareName
after that go to App\Http\kernel.php and add one lines on $routeMiddleware
'user_block' => \App\Http\Middleware\MiddlewareName::class
After that goto your middleware
In handle function (write your own middleware code)
In routes use your middleware -
Route::group(['middleware' => ['user_block']],
function () {
Route::get('/logout', array('uses' => 'Auth\LoginController#logout'));
});
If you used this middleware in specific controller in __construct in any controller just write a line
namespace App\Http\Controllers;
use App\User;
class UserController extends Controller {
public function __construct() {
$this->middleware('user_block');
}
}
If you want this middleware for just one action in the controller you can add this middleware to the route :
Route::get('/login', 'LoginController#login')->middleware('user_block');
If you used this middleware in specific controller in specific 1-2 function just write this line in __construct functiono in controller
public function __construct()
{
$this->middleware('user_block')->only(['login','register']);
}

Extending Laravel base controller

I am a newbie in Laravel framework and I want to extend a base controller which in turn extends controller. However, I discovered that when I do that, my controller no longer recognises my session variables.
Here is my code
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends PermissionController
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
dd(session('userdata')['user_urls']);
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
And this is my PermissionController code
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PermissionController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct(Request $request) {
if(!session('userdata')['user_urls']->contains($request->path())){
dd(session('userdata')['user_urls']);
}
}
}
But I realize that my session('userdata')['user_urls'] becomes null at the PermissionController. But if I make FeeController to extend Controller, my session variables are intact.
I need to use the session variables for some control at the permission controller.
I am running Laravel 5.3 on a MAC OSX and PHP 7
I have figured out the problem. Actually, PermissionController is not registered in the web middleware group so that session is not persisting in the PermissionController. So the solution to your question is just make a trait named as Permission instead of the controller and use it in FeesContorller.
trait Permission{
public function permission(Request $request) {
if($request->session()->get('name') != null){
echo "Hello World";
}
}
}
And FeesController like this:
class FeesController extends Controller
{
use Permission;
public function index(Request $request)
{
$this->permission($request); // the method of the trait.
echo "\n".$request->session()->get('name');
}
}
Output:
If the name attribute is set in session then :
Hello World
Passion Infinite
Otherwise
No Output // null
I have solved the same problem with middleware. I have created a middleware that takes care of the authorization of requests by checking the session to ensure that the controller action being accessed is available in session.
This is the middleware
namespace App\Http\Middleware;
use Closure;
class PermissionMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$currentAction = \Route::currentRouteAction();
list($nothing,$route_action) = explode('App\Http\Controllers\\', $currentAction);
$user_actions=session('userdata')['user_urls'];
if((empty($user_actions))||!$user_actions->contains($route_action)){
return redirect('denied');
}
return $next($request);
}
}
This is the controller
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$data['title']='New Fee';
return view('settings.fee.create',$data);
}
So, instead of using the routes (cos of some other reasons), I used the controller actions.
So, once a user logs in, all the controller actions he can access are loaded into session. When he tries to perform any action, the middleware, does the check to ensure he is allowed to perform that action. Otherwise, he is routed away.
So, I either add 'permission' to the routes middleware or call
$this->middleware('permission')
on the controller's construct method.
That is working for me now.
Thank you everybody for your contributions.

Laravel: How to access session value in AppServiceProvider?

Is there any way available to access Session values in AppServiceProvider? I would like to share session value globally in all views.
You can't read session directly from a service provider: in Laravel the session is handled by StartSession middleware that executes after all the service providers boot phase
If you want to share a session variable with all view, you can use a view composer from your service provider:
public function boot()
{
view()->composer('*', function ($view)
{
$view->with('your_var', \Session::get('var') );
});
}
The callback passed as the second argument to the composer will be called when the view will be rendered, so the StartSession will be already executed at that point
Add new web middleware ShareDataForView
in \app\Http\Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\Illuminate\Session\Middleware\StartSession::class,
// I will always ShareDataForView after StartSession
\App\Http\Middleware\ShareDataForView::class,
...
and write your code in method "handle" of app\Http\Middleware\ShareDataForView.php, for example:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Closure;
use Log, Exception, View;
class ShareDataForView
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
$bank = NULL;
if ( $user ){
$bank = $user->bank;
}
View::share('user', $user);
session()->put(['bank' => $bank]);
return $next($request);
}
}
The following works for me on Laravel 5.2, is it causing errors on your app?
AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
\Session::put('lang', 'en_US');
view()->share('lang', \Session::get('lang', 'de_DE'));
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
home.blade.php
<h1>{{$lang}}</h1>
Shows "en_US" in the browser.

Auth::check returns false in AppServiceProvider

I have tried injecting the Guard contract into the constructor, I have tried moving around. But when a user is logged in - Auth::check() returns false.
In other files (Except 1 global middleware) Auth::check() works correctly.
In the middleware - moving Auth Check to the top helped alleviate the issue. In this case - it isn't working.
Additional information: This app has been upgraded from 4.2 . Previously it used Confide.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
if(Auth::check())
{
$user = Auth::user();
$messages=Message::where('read',0);
$messages->where(function ($query) use ($user) {
$query->where('to',$user->id)->orwhere('from',$user->id);
});
$message_unread= $messages->count();
$new_notifications= Notification::where('user_id',$user->id)->where('viewed',0)->count();
}
else
{
$message_unread=0;
$new_notifications=8888888;
//its 888888 for testing purposes.
}
view()->share(([
'message_unread'=>$message_unread,
'new_notifications'=>$new_notifications
]));
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
You should move this code to controller layer. boot method of Laravel's ServiceProviders serves for bootstrapping the services, not implementing busines logic.
You need to use auth in at the top of the serviceprovider class
use Auth;
Instead of
use Illuminate\Support\Facades\Auth;
Apart from using a view composer, you could also use middleware which is processed after the session variables have been loaded:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class SetViewVariables
{
protected $auth;
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next)
{
$user = $this->auth->user();
view()->share('user', $user);
return $next($request);
}
}

How to Add an Object to Laravel's IOC Container from Middleware

I want to create an object in my middleware (in this case, a collection from an Eloquent query), and then add it to the IOC container so I can type-hint method signatures in my controllers to access it.
Is this possible? I can't find any examples online.
You can do that very easy, in several steps.
Create new middleware (name it like you want)
php artisan make:middleware UserCollectionMiddleware
Create new collection class that will extend Eloquent database collection. This step is not required, but will let you in future to create different bindings, using different collection types. Otherwise you can do only one binding to Illuminate\Database\Eloquent\Collection.
app/Collection/UserCollection.php
<?php namespace App\Collection;
use Illuminate\Database\Eloquent\Collection;
class UserCollection extends Collection {
}
Add your bindings in app/Http/Middleware/UserCollectionMiddleware.php
<?php namespace App\Http\Middleware;
use Closure;
use App\User;
use App\Collection\UserCollection;
class UserCollectionMiddleware {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
app()->bind('App\Collection\UserCollection', function() {
// Our controllers will expect instance of UserCollection
// so just retrieve the records from database and pass them
// to new UserCollection object, which simply extends the Collection
return new UserCollection(User::all()->toArray());
});
return $next($request);
}
}
Don't forget to put the middleware on the desired routes, otherwise you will get an error
Route::get('home', [
'middleware' => 'App\Http\Middleware\UserCollectionMiddleware',
'uses' => 'HomeController#index'
]);
Now you can type hint this dependency in your controller like this
<?php namespace App\Http\Controllers;
use App\Collection\UserCollection;
class HomeController extends Controller {
/**
* Show the application dashboard to the user.
*
* #return Response
*/
public function index(UserCollection $users)
{
return view('home', compact('users'));
}
}

Categories