Sharing across view in Laravel 5.4 - laravel-5

I have a project where users are assgned to a client and I wannt to share that info across views.
In AppServiceProvider I added
use View;
use Auth;
and then amended boot to
if ( Auth::check() )
{
$cid = Auth::user()->client_id;
$company = \App\Clients::first($cid);
view::share('company',$company);
}
but if I dd($company) I get
Undefined variable: company

This is because of the Auth is not working in AppServiceProvider
So your If condition return false
if you share data with all the views then your code like this without check Auth. then It will work.
$company = 'Some value';
view::share('company',$company);
dd($company); // for print output.
Solution - For Alternate option you have to make Helper class.

At the time the providers boot is run, the Auth guard has not been booted, so Auth::check() returns false, and Auth::user() returns null.
You could do the View::share in a middleware, or perhaps in the constructor of a controller (the base controller to share it across the whole application, or some particular controller if you need it in some subset of routes).

Related

View Share doesn't return updated data, how then to share live data?

I currently have a model which access data like so:
$currentSessionID = session()->getId();
$displayCart = Cart::where('session_id', $currentSessionID)->get();
return view('layouts.cart')->with('cartDetails', $displayCart);
This model correctly retrieves the data in a current session.
To access this same data in a header file I'm using View::Share in the AppServiceProvider like so:
public funciton boot()
{
$currentSessionID = session()->getId();
$inCartDetails = Cart::where('session_id', $currentSessionID)->get();
View::share('inCartDetails', $inCartDetails);
}
In my blade the $inCartDetails returns empty. I get [].
My suspicion is that this function ONLY gets called at boot. Hence the name :) and that it's empty cause at the time of starting the session it's empty since user hasn't selected anything. If this is correct how would I then pass live data to multiple views?
The session is not available in the boot method of the service providers. You should create a middleware for this. Check out this answer here: How to retrieve session data in service providers in laravel?

Laravel 5 Unable to access currently logged in user id from custom helper

In AppServiceProvider, I called a function from a custom helper as follows:
public function boot()
{
View::share('tree', customhelper::generateSiteTree(0));
}
The custom helper file is calling the database function as below:
$children = UserPermission::getLeftNavByUserId($startAt);
In the custom helper function, I want to pass the current logged in user ID however, dd(Auth::user()) is returning null.
How can I pass the Auth::user()->id with the method
getLeftNavByUserId($startAt, Auth::user()->id);
The variable (or Facade) isn't available yet. One way to solve this is by using a view composer.
View::composer('my.view.with.children', function(View $view){
$view->with('children', UserPermission::getLeftNavByUserId($startAt, Auth::id()));
});
Ofcourse you need to add a check if the user is logged in or not etc.
Custom helper function will be initialized in application instance before the Auth middleware therfore it will always be null, if you want to use the auth user bind it from middlware instead.

Controller constructor to check Auth middleware for two different guards

I have a dashboard view that shows certain contain depending on which user is viewing, whether it be an admin or just a regular user.
I can get my admins onto that page, but regular users aren't able to currently because of my middleware guard.
class DashboardController extends Controller {
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('dashboard.index');
}
}
The following code checks on each DashboardController call for auth:admins, but I want regular users to access this too, is there a way to check the auth middleware twice like so?
$this->middleware(['auth:admin','auth']);
So ideally it will check if you're an admin or just a regular auth user.
Also on my view page, when accessing properties of an admin I'm using:
{{ Auth::user()->admin_username }}
Is this normal? I have an admin Model but I'm still accessing it via Auth::user() which feels strange to me, shouldn't it be Auth::admin()->admin_username
Accessing a particular page for users with differing roles is more suited for laravels gates and policy authorization mechanisms.
https://laravel.com/docs/5.5/authorization#writing-gates
These allow you to write fine tuned rules for each use case you have. Simple gates can be defined as closures within your application AuthServiceProvider. For example:
public function boot()
{
$this->registerPolicies();
Gate::define('access-dashboard', function ($user, $post) {
return auth()->check() && (auth()->user()->hasRole('admin') || auth()->user()->hasRole('regular'));
});
}
Then you can use the gate facade wherever necessary, for instance a controller method or constructor.
if (Gate::allows('access-dashboard', $model)) {
// The current user can access dashboard, load their data
}
Alternatively use the can or cant helpers on the user model directly.
if (auth()->user()->can('access-dashboard')) {
//
}
Of course, you can achieve similar via middleware, the advantage of using the above is you can authorize actions at specific points in your code as well as reusability.
As for for last question, as you have it written is correct.
{{ Auth::user()->admin_username }}
Auth::user() or auth()->user() simply returns the currently authenticated user, regardless of their role.
Policies will never work without auth middleware

Laravel - How to get the guard that authenticated the user?

I have a customized LoginController with two functions:
loginCustomer that runs Auth::guard('customer')->attempt(...);
loginEmployee that runs Auth::guard('employee')->attempt(...);
I have customized two guards in config.auth that points to my two Models (Customer and Employee) and protect the routes of backoffice and frontend.
Now in my customized LogoutController i want to run Auth::logout() but it doesn't work because i think it uses the default guard.
It only works if i specify Auth::guard('customer')->logout() or Auth::guard('employee')->logout(), depending the guard that was used to login.
Is there any way to get the guard used to authenticate the user so i can use only Auth::guard($guard)->logout?
You can use shouldUse method:
After the call of this method you can logout user via guard you was previously set by shouldUse method.
In your case:
if( Auth::guard('customer')->attempt(...) ){
Auth::shouldUse('customer');
}
if( Auth::guard('employee')->attempt(...) ){
Auth::shouldUse('employee');
}
After this you can use Auth::logout and previously choosen guard (via shouldUse) will be used:
// just use Auth::logout without Auth::guard(GUARDNAME)->logout()
Auth::logout();
Short documentation about this method: https://laravel.com/api/5.4/Illuminate/Auth/AuthManager.html#method_shouldUse
This might not be the perfect solution, but it works. Basically, just go through all the guards and check if the user is authenticated by that guard. If he is - log him out. Be aware that this will log him out of all the guards he is logged in to.
This code would go to your logout controller:
$guards = array_keys(config('auth.guards'));
foreach ($guards as $guard) {
if(Auth::guard($guard)->check()) Auth::guard($guard)->logout();
}

Laravel 5: Sessions not working the way they should

On top of every controller and routes.php I used:
use Illuminate\Support\Facades\Session;
In routes.php I set the session using:
Session::put('key', 'value');
In a controller I want to call the session value of key using:
echo Session::get('key');
But once I set a new value to key in routes.php and call it in a controller, I still get the first value and not the new one. If I echo the the session using Session::all() in routes.php after setting it, I see the new value, but in a controller it flips back to the first value. I even tried using below in routes.php before setting the new value, but without success.
Session::forget('key');
Am I forgetting something here?
Using regular PHP $_SESSION my routes.php looks like this:
$slug = $_SERVER['REQUEST_URI'];
$slug = explode('/', $slug[0]);
if(in_array($slug[1], Language::all()->lists('iso'))) {
$_SESSION['language'] = $slug[1];
if(!$slug[2]) {
$_SESSION['slug'] = 'home';
Route::any('/{slug}', ['as' => 'pages.page', 'uses' => 'PagesController#page']);
} else {
if($slug[2] != 'dashboard' && $slug[2] != 'migrate' && $slug[2] != 'form-send') {
if (in_array($slug[2], ElementValue::where('element_field_id', 2)->lists('value_char')) && !isset($slug[3])) {
$_SESSION['slug'] = $slug[2];
Route::any('/{slug}', ['as' => 'pages.page', 'uses' => 'PagesController#page']);
} else {
$_SESSION['slug'] = 'home';
Route::any('/{slug}', ['as' => 'pages.page', 'uses' => 'PagesController#page']);
}
}
}
}
Where in routes.php are you setting the session value? It sounds like you're doing something like this:
Session::put('key', 'value');
Route::get('my-route', 'MyController#doSomething');
and then doing this:
class MyController {
public function doSomething()
{
Session::get('key');
}
}
Is that correct? If so, read on...
I'm no expert on the Laravel request lifecycle (for more, see the documentation), but it doesn't surprise me that this doesn't work. The way I think about it is this: the routes.php file is loaded and executed early in the life cycle - probably first - since it tells the application what code to execute next (ie. what do when a particular request is received). And when I say "early in the life cycle", I mean early - like before sessions are initialized. I believe that the Session::put call is simply being ignored, since at the time when you're setting the value, the session does not exist.
You may want expand your question with a little more detail about what you're trying to accomplish - there has got to be a better way to do it.
EDIT - in response to the comments below...
I am not saying you should touch the $_SESSION superglobal - that's a bad idea because I'm not even sure that Laravel uses the native PHP session facility and you have no guarantee that whatever you do will continue to work in the future.
It's not clear what you're trying to do, but to me this sounds like a value that does not belong in the session.
By placing the Session::put in the routes.php file, it sounds like you have some value that's important and should be set for every session and every request
If that's the case, and it's a static value, then it's not a session value, it's a configuration value.
If, instead, it's a dynamic value and/or it changes depending on which user is associated with a session, then you can set it in one of several places:
if you're using controller-based routing, you could set this in the controller constructor, although I wouldn't recommend it, because you will probably have to do it for several controllers, leading to code duplication
if you're using closures in your routes, set it there. E.g.
Route::get('some/route', function () {
Session::put('key', 'value');
// this works, because the closure isn't executed until after
// the application is initialized
});
you could also do it in middleware
or in a service provider (although I'm not certain that sessions would be available when the service providers are executed).
The best option is probably middleware - this would allow you to set (or calculate) the session value in one place in your code and also associate it with particular routes, if you don't need it for all routes.
Don't use $_SESSION in laravel. Uses the laravel Session class. See the following post How to access the globals $_SESSION and $_COOKIE from a laravel app?
Also, all your if logic should not be living in routes.php. You should add that to middleware to filter your routes.
Also, you are really making this hard for yourself. Laravel provides most of what you need in convenient helper classes e.g. Request::url(), Request::getHost(), Request::getLocale(). Have a read through the docs and get familiar with "The Laravel Way" it will be much easier and things will then work as you expect.
I moved the logic to the controller and now my routes are this simple:
Route::pattern('slug', '[a-zA-Z0-9\-_\/]+');
$slug = Request::path();
if(isset($slug)) {
Route::any('/{slug}', 'PagesController#index')->where('slug', '[a-zA-Z0-9\-_\/]+');
}
The session is stored in the PagesController and used further in the application. Thanks for your help guys.

Resources