Laravel Nova Observe not connecting to tenant database - laravel

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

Related

How to restrict users to use application

I am using laravel framework to develop api’s ,it’s an existing application .there is a requirement if more than 5users registered from 6th user onwards i have to restrict them to use application until they approved by manager or they paid for registration fee then only the user will allow to use the application.
Can anyone give me the idea how to acheive this scenario or suggest me any package in laravel
Solution:
You can add 'status' field in your table. Now when your api is registering a user, you can check the No. of users in the database. If more than or equals to 5, you can set the status to 0. Now show the manager list of user with status 0 and when the status changes you can use the application.
Make sure to add condition where status = 1 when user is getting logged in.
I hope it helps!
Well, you can just put a isApproved column to indicate if the user is already approved or just like the email_verified_at that accepts timestamp as a value then create a middleware where you can check if the user is approved or not. then add a method to the user model to check if the user is approve :
User model
class User extends Authenticatable
{
public function isApproved()
{
// check if the account_approved_at column is not null.
return ! is_null($this->account_approved_at);
}
}
Middleware
class EnsureUserIsApproved
{
public function handle(Request $request, Closure $next)
{
if(! $request->user()->isApproved()) {
// can also use abort(403) instead of redirect
return redirect('route-where-you-want-the-user-to-redirect')
}
return $next($request);
}
}
You can check this for more information about middleware

refresh page after updated model - Laravel

I want to refresh current page after any user update
I'm trying to do something like that in User Model :
public static function boot()
{
self::updated(function ($model) {
return back(); //or redirect(Request::url())
});
}
but it wasn't working.
How can I refresh the page if any user updated
In general, the model event functions creating/created/updating/updating/saved/saving should only ever return false or nothing (void). Returning false in for instance updating (that is: before the model is persisted in the database) cancels the model update (this works for all propagating events, see https://laravel.com/docs/9.x/events#stopping-the-propagation-of-an-event).
To "refresh" the current page after a user update, you have to be more specific about what you require. The back() function that you use (or the aliases redirect()->back() or even app('redirect')->back()) is (to my knowledge) to be used in controllers and it uses the Referer header or a property in the user's session to determine to which page to send the client to. This is most often used with validation errors, so that you can send the user back to the page they came from along with any possible validation error messages.
Using back() (or any other request completions like return response()->json('mydata')) inside events is wrong and it doesn't even work since the result of such events is not being used to complete the request. The only valid thing you "could" do is to try validation inside an event, which in turn could throw ValidationExceptions and is therefore automatically handled.
What you should do is use the controller method that actually handles the request that updates the user:
// UserController.php
/** (PUT) Update a user */
public function update(Request $request, User $user)
{
if($user->update($this->validate($request, [/* validations */])) {
return redirect()->back();
// or even be explicit and use `return redirect()->route('users.show', $user);`
}
// `update()` returned false, meaning one of the model events returned `false`
// (there is no exception thrown here).
session()->flash('alert-info', 'Something went wrong');
return redirect()->back();
}

Laravel 8 - Global Object available throughout application (not just in view files)

In my application, users can belong to different accounts and have different roles on those accounts. To determine which account is "current" I am setting a session variable in the LoginController in the authenticated() method.
$request->session()->put('account_id', $user->accounts()->first()->id);
Then, throughout the application I am doing a simple Eloquent query to find an account by ID.
While this "works", I am basically repeating the same exact query in every single Controller, Middleware, etc. The maintainability is suffering and there are duplicate queries showing in Debugbar.
For example, in every controller I am doing:
protected $account;
public function __construct()
{
$this->middleware(function($req, $next){
$this->account = Account::find($req->session()->get('account_id'));
return $next($req);
});
}
In custom middleware and throughout the entire application, I am essentially doing the same thing - finding Account by ID stored in session.
I understand you can share variable with all views, but I need a way to share with the whole application.
I suppose much in the same way you can get the auth user with auth()->user.
What would be the way to do this in Laravel?
I would create a class to handle this logic. Making it a singleton, to ensure it is the same class you are accessing. So in a provider singleton the class you are gonna create in a second.
$this->app->singleton(AccountContext::class);
Create the class, where you can set the account in context and get it out.
class AccountContext
{
private $account;
public function getAccount()
{
return $this->account;
}
public function setAccount($account)
{
$this->account = $account;
}
}
Now set your account in the middleware.
$this->middleware(function($req, $next){
resolve(AccountContext::class)->setAccount(Account::find($req->session()->get('account_id')));
return $next($req);
});
Everywhere in your application you can now access the account, with this snippet.
resolve(AccountContext::class)->getAccount();

Get Auth User ID Laravel

I Made Laravel Project And install the Breeze package for multi authentication And the Create a guard call admin in order to control user assess to dashboard It works fine Here is the route
Route::get('/dashbord',[AdminController::class, 'Dashbord'])
->name('admin.dashbord')
->middleware('Admin');
Route::get('/profile/edit',[AdminProfileSettings::class, 'index'])
->name('admin.profile.settings')
->middleware('Admin');
Here Is the middleware
public function handle(Request $request, Closure $next)
{
if(!Auth::guard('admin')->check()) {
return redirect()->route('login_form')->with('error','please Login First');
}
return $next($request);
}
This code works fine but the problem is when I log in to the dashboard and try to get admin ID to admin.profile.settings route it wont get the Id, I Passed the logged admin id by using AdminProfileSettings controller like this
public function index()
{
$id=Auth::user()->id;
$adminData = Admin::find($id);
return view('admin.admin_profile_settings',compact('adminData'));
}
But, when I try to access it in the admin.admin_profile_settings view it show me this error:
Trying to get property 'id' of non-object
But, if I use $adminData = Admin::find(1); it get the Id without any problem but when I try to get auth user id it show me the error and if I have logged in using default guard this error wont show but it get the id from users table
You're not using the auth:admin middleware, so the Auth facade is going to pull the user from the default guard defined in the config (which is web, unless you've changed it).
Without using the auth:admin middleware, you'll need to specify the guard for which to get the user.
$adminUser = Auth::guard('admin')->user();
Note 1: if you have the $request variable, you can also pull the user off of the $request with $request->user(), instead of reaching out to the Auth facade. It's just a matter of preference. The user() method also takes a guard as a parameter, if needed.
$adminUser = $request->user('admin');
Note 2: the user() method (Auth and request) returns the fully hydrated model. There is no need to get the id and re-retrieve the model.

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.

Resources