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

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.

Related

Laravel Eloquent model events on created user

I'm trying to automatically create a profile for a user when a user is created.
I'm using the created event and overriding the boot() method. But I when call the create() method on user->profile->create(), it says create was called on null. I checked and profile is null in this.
Here's the code:
static::created(function ($user) {
// it returns profile as null, thus create() can't be used on null.
$user->profile->create(['title' => $user->username,]);
});
Can anyone help me understand this? It's working in my tutor's code, and he is using Laravel 5.8 but I have version 7.1.
$user->profile returns the related model if any exists. You have to do $user->profile() which returns a query builder to query the relation. Try to do it like so:
$user->profile()->create(['title' => $user->username,]);

Laravel Nova Observe not connecting to tenant database

I have a multi tenant App. My system database I have models- User, Billing, FrontEnd ... and using policies I'm able to show, hide and prevent viewing and actions by tenant.
Each tenant has a database with models- Member, Event, Item ...
I set each model database based on the Auth::user()->dbname in the _construct method. This allows me to set my dbname to a clients database for tech support.
class Item extendsw Model {
public function __construct() {
parent::__construct();
if(Auth::user()->dbname) {
Config::set('database.connections.tenant.database', auth()->user()->dbname);
$this->connection = 'tenant';
}
}
This all works as planned until I add and Observer for a client model e.g. Member
I now get an error on any Observer call.
Trying to get property on non object Auth::user()->dbname.
Where should I be registering the Observer? I tried AppServiceProvider and NovaServiceProvider.
I think that happens because the observer instantiates your User model before the request cycle has started and that means that your User instance does not exist yet neither has been bound in the Auth facade.
Thus, Auth::user() returns null and you are trying to get a property from it.
A way to solve the issue may be to check if the user instance exists or not:
public function __construct() {
parent::__construct();
if (optional(Auth::user())->dbname !== null) {
Config::set('database.connections.tenant.database', auth()->user()->dbname);
$this->connection = 'tenant';
}
}
The optional helper return the value of the accessed property (dbname in your case) if and only if the argument is not null, otherwise the whole call will return a null value instead throwing an exception.
If that is not the case, maybe update the question with the error stacktrack and the code/action that triggers the error

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

How to use global variables in Laravel

Is it possible to share and change some variable between multiple views? For example, I want to have a variable $user that will be shared between all views. When a user logs the variable is set up, when the user logs out, the variable is unset. I was unable to achieve requested using
the following combination:
in AppServiceProvider:
view()->share('var', 1);
in the controller:
$var = view()->shared('var');.
$var ++;
view()->share('var', var);
return view(''', 'var'=>$var)
Every time when the page is reloaded $var is always the same (2).
I want to have a variable $user that will be shared between all views
You should use auth()->user() to get authenticated user instance in any view.
But if you don't want to use it for some reason, you could share the variable between multiple views with a view composer.
share() method will be useful only if you want to share a variable with all views. To make it work, put view()->share('key', 'value') to the boot() method of a service provider.
Also, the code in your controller looks like you want to share data not between views, but between requests. Use session for that.
To save the data:
session(['key' => 'value']);
To get the data in another request:
session('key');
It would be better to add another service provider. Take a look at my provider:
<?php
namespace App\Providers;
use Request;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider
{
public function boot()
{
$this->globalThings();
//call another globals' function here
}
public function register()
{
//
}
/**
* Get the golbals
*/
private function globalThings()
{
view()->composer(array('*.*'),function($view){
//get the data however you want it!
$view->with('global', Model::where('field','value')->get());
});
}
And don't forget to add the service provider to list of provider is config/app.php
App\Providers\ViewComposerServiceProvider::class,

Sharing across view in Laravel 5.4

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

Resources