Laravel _ How to inject a query into Auth::user() - php

I'm making a blog with laravel. When I look into user authentication, I have a few issues here. I have 2 tables, one is users: id, name, ... the other is role: user_id, privilege .. I need to check whether a user is admin or not, I will need a function like isAdmin() or a $isAdmin attribute. This is my function placed in the app/providers/AuthServiceProvider.php:
private static $isAdmin;
public static function isAdmin() {
if (isset(self::$isAdmin)) {
return self::$isAdmin;
}
$user_privilege = DB::table('role')
->select('privilege')
->where([
['privilege', '=', 'admin'],
['user_id', '=', Auth::user()->id],
])
->get()
->first();
self::$isAdmin = isset($user_privilege->privilege);
return self::$isAdmin;
}
This code works fine, but this will require two queries to the database to check the user's admin rights. So I wanted to find a way to inject a query into Auth :: user () so that only one query would retrieve all the stuff I wanted. I'm a beginner with laravel. Can you help me?

I assume that user can have only one role. You can create isAdmin() method in the User model:
public function isAdmin()
{
return auth()->user()->role->privilege === 'admin';
}
Define the relationship if you didn't do that yet:
public function role()
{
return $this->hasOne(Role::class);
}
Then use it with auth()->user()->isAdmin().
If a user can have many roles:
public function isAdmin()
{
auth()->user()->loadMissing('roles');
return auth()->user()->roles->contains('admin');
}
And the relationship:
public function roles()
{
return $this->hasMany(Role::class);
}

On your User model define an isAdmin method:
public function isAdmin() {
// simplified your query here
return $this->hasRole('admin');
}
Then it will be accessible on the Auth guard like:
Auth::user()->isAdmin();

Related

how can retrive specific data for each user by using eloquent in Laravel

I have two tables in Database, user table and meeting table.
when a user login successfully I want that the information in the meeting table shown to them.
but not all of them just the one which he created them or invited to.
this ids my route:
Route::get('/dashboard/per_user{id}',[meetingController::class, 'meet_for_user'])-
>name('meet_for_user');
this is my controller:
public function meet_for_user()
{
$meetings=meeting::with('users')->get();
return view('dashboard', compact('meetings'));
}
this is user model:
public function meeting()
{
return $this->hasMany(meeting::class,'idCreateMeeting','id');
}
this is meeting model:
public function users()
{
return $this->belongsTo(User::class,'idCreateMeeting','id');
}
If you change how your route is defined to expect a User id, you can use route model binding to inject the User into your controller method and get their meetings from there.
Route::get('/dashboard/per_user/{user}',[meetingController::class, 'meet_for_user'])
->name('meet_for_user');
public function meet_for_user(User $user)
{
$meetings = $user->meetings;
return view('dashboard', compact('meetings'));
}

Laravel 5.7 not returning new record when global scope applied

I'm sure I'm missing something simple here but I am completely at a loss so any input would be greatly appreciated.
I have two models, User and Account with a many to many relationship with the model Channel. Accounts can be associated with multiple channels and users can also be associated with multiple channels. This has been created so that users can only access accounts that are associated with channels they are also associated with.
In order to do the filtering, I have applied a global scope to the account model so when I perform a query, it only returns accounts associated with the channels that the user is associated with. This works as intended for everything except newly created accounts.
If I call $account = Account::find($id) on a newly created account it returns null. If I drop the global scope it returns the account.
The only way I have found to fix the problem is if I sync the pivot table for the channel_user table and only include a single channel that is also associated with the account.
It feels like something is being cached somewhere but I'm not sure where to go from here. Please let me know what else you need to know
Account Model:
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ChannelScope);
}
public function channels()
{
return $this->belongsToMany('App\Channel');
}
public function user()
{
return $this->belongsTo('App\User');
}
User Model:
public function accounts() {
return $this->hasMany('App\Account');
}
public function channels(){
return $this->belongsToMany( 'App\Channel' );
}
Channel Model:
public function accounts()
{
return $this->belongsToMany('App\Account');
}
public function users(){
return $this->belongsToMany('App\User');
}
Channel Scope:
public function apply(Builder $builder, Model $model)
{
$channels_ob = Auth::user()->channels;
$channels = array();
foreach ($channels_ob as $channel){
array_push($channels,$channel->id);
}
$builder->whereHas('channels', function ($q) use ($channels){
$q->where('channels.id','=', $channels);});
}
AccountController.php Store:
$account->save();
if (isset($request->chk_channels)){
foreach($request->chk_channels as $channel){
$ch = Channel::where('name',$channel)->get();
$ch_array[] = $ch[0]->id;
}
}
$account->channels()->sync($ch_array);
UserController.php update_channels:
public function update_channels(Request $request, $id)
{
$user = User::find($id);
if ($user->hasPermission('view_all_accounts')){
if (isset($request->chk_channels)){
foreach($request->chk_channels as $channel){
$ch = Channel::where('name',$channel)->get();
$ch_array[] = $ch[0]->id;
}
$user->channels()->sync($ch_array);
}
}
You can't have a column value equivalent to an array. You're building up an array of channels in your scope and then checking equivalency:
$q->where('channels.id','=', $channels);
Perhaps, you want whereIn:
$q->whereIn('channels.id', $channels);

Laravel permissions can() function | Authorization

I have users, app_roles, app_permissions, app_permission_app_role, app_role_user.
The tables are self explanatory, I am creating permissions, Then assigning that permissions to new role on role creation, And then i assigns roles to users.
i check permission of the authenticated user like :
#if(auth()->user()->can('some route name'))
Html...
#endif
The above condition checks if the user have access to that content or not based of the assigned role as we know that the role have permissions, And the can('some route name') parameter is a route name. Its working fine.
Where i am stuck !!!
The table app_role_user had user_id, app_role_id, Now i added another column organization_id... (Consider Organizations as groups, Where a user can be a member of that groups, And the owner of the group assigns single role(Can't assign multiple role) to that user). Because now the user can switch between organization and the user can have different roles in different organizations.
I have to clear path for the :
#if(auth()->user()->can('some route name'))
Html...
#endif
Note : : Auth::user()->current_org->id show the id of the organization in which the user is in right now
As well as currently i am saving role_id, user_id, organization_id in app_role_user table.
Here is my AuthServiceProvider class,
I am Dynamically registering permissions with Laravel's Gate :
public function boot(GateContract $gate)
{
$this->registerPolicies();
$this->registerAllPermissions($gate);
}
protected function getPermissions() {
return $this->app->make('App\Repositories\PermissionRepository')->withRoles();
}
private function registerAllPermissions($gate) {
if (Schema::hasTable('app_permissions') and Schema::hasTable('users') and Schema::hasTable('app_roles')) {
cache()->forget('app_permissions_with_roles');
foreach ($this->getPermissions() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->hasPermission($permission);
});
}
}
}
Here is PermissionRepository class :
class PermissionRepository
{
protected $model;
public function __construct(AppPermission $model)
{
$this->model = $model;
}
public function all(){
return $this->model->all();
}
public function withRoles(){
$model = $this->model;
$permissions = cache()->remember('app_permissions_with_roles', 1*60*24, function() use($model) {
return $model->with('roles')->get();
});
return $permissions;
}
}
And here is HasRoles trait having hasPermission(AppPermission $permission) because AuthServiceProvider class needs it in registerAllPermissions.
trait HasRoles {
public function assignRole($role)
{
return $this->roles()->save(
AppRole::whereName($role)->firstOrFail()
);
}
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return !! $role->intersect($this->roles)->count();
}
public function hasPermission(AppPermission $permission)
{
return $this->hasRole($permission->roles);
}
}
What should i do, I have tried many conditions but nothing worked at all.
Looking forward to hear from you guys.
Thanks for the read, Need serious attention please.
You can try like this
User Model
//add organization_id as pivot field
public function roles(){
return $this->belongsToMany(AppRole::class)->withPivot('organization_id');
}
//define a function
public function orgRoles($orgId){
return $this->roles()->wherePivot('organization_id', $orgId)->get();
}
Now in trait modify hasRole function
public function hasRole($role)
{
$orgId = Auth::user()->current_org->id;
if (is_string($role)) {
return $this->orgRoles($orgId)->contains('name', $role);
}
return !! $role->intersect($this->orgRoles($orgId))->count();
}

Laravel models to return null relation?

I am writing a website for photo posts and I have these functions relating likes (they determine if the user is liking the specific post or not)
Post Model:
public function likes()
{
return $this->hasMany('Like');
}
public function isLiked()
{
return $this->likes()->where('user_id', Auth::user()->id);
}
Post Controller function for example:
public function postsByType($type)
{
if($this->user){
$posts = Post::with('isLiked')->where('type', '=', $type)->paginate(12);
} else {
$posts = Post::where('type', '=', $type)->paginate(12);
}
return $posts;
}
Is there any way to return null in MODEL function when user is not logged in, without running a query?
I want to avoid writing that if in post controller
I thought about the following solution but it's not working...
public function isFollowing()
{
return $this->setRelation('isFollowing', null);
}
getting this error:
Call to undefined method Illuminate\Database\Query \Builder::addEagerConstraints()
Since you probably always want to fetch the relation (except if there's no user logged in) I suggest you do something like this in your model:
(I also renamed the relationship to liked, you'll see later why)
public function newQuery(){
$query = parent::newQuery();
if(Auth::check()){
$query->with('liked');
}
return $query;
}
Now every time a query is run with the model with('isLiked') will be added if the user is logged in.
One problem remains though. If you access isLiked the query will be run anyways. And even for every post because it's not eager loaded. You can fix that by adding an attribute accessor:
public function getIsLikedAttribute(){
if(Auth::guest) return false;
return ! $this->liked->isEmpty();
}
So in your view you can just do this:
#if($post->isLiked)
Note: It would be nicer to move the things inside newQuery() to a global scope. Make sure to check out how to do that in the documentation if you're interested.
Here's an example with a scope. Create a class, let's call it LikedScope:
class LikedScope implements Illuminate\Database\Eloquent\ScopeInterface {
public function apply(Builder $builder, Model $model){
if(Auth::check()){
$builder->with('liked');
}
}
public function remove(Builder $builder, Model $model){
}
}
And then add it to your model:
public static function boot(){
parent::boot();
static::addGlobalScope(new LikedScope);
}

Eloquent many-to-many-to-many - how to load distant relation easily

I have 3 tables; users, groups and permissions
In models I have the relationships set as belongsToMany
in user model:
public function groups() {
return $this->belongsToMany('Group');
}
in group model:
public function users() {
return $this->belongsToMany('User');
}
public function permissions() {
return $this->belongsToMany('Permission');
}
in permissions model:
public function groups() {
return $this->belongsToMany('Group', 'id');
}
many users - to - many groups
many groups - to - many permissions
I'm trying to get all the permissions a user has, and have no clue what the code for it should look like. Can anyone help?
This is how you can do it:
User::where('id', $id)->with(['groups.permissions' => function ($q) use (&$permissions) {
$permissions = $q->get()->unique();
}])->first();
// then
$permissions; // collection of unique permissions of the user with id = $id
It should look something like this if you are eager loading...
$user = User::where('id', $id)->with(['groups.permissions'])->first();

Categories