Many to Many to One relationship - laravel

I've got four tables Users[user_id] - role_user[user_id,role_id] - Roles[role_id] - Permissions[role_id]. A User could have many Roles, while the Role has many Permissions. So, a Permission has one Role, while a Role belongs to many Users.
// User.php ...
class User extends Model
{
public function roles()
{
return $this->belongsToMany('Role');
}
}
// Roles.php
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\User');
}
public function permissions()
{
return $this->hasMany('Permission');
}
}
// Permission.php
class Permission extends Model
{
public function role()
{
return $this->belongsTo('Role');
}
}
I guess the real question is; can you chain relationship methods, like: App\User::find(1)->roles->permissions; I don't think you can because the ->roles returns a Collection and not an eloquent model, so the permissions method doesn't exists off roles.
Is there another way I can get the collection of permissions for all roles for a given use, preferably with a single line?

I haven't tested it, but I think this will work or work with very small twick. Add this function in your User Model.
public function getPermission($id){
$roles = Roles::where('user_id','=', id)->get();
$permissions = array();
foreach($roles as $role){
array_push($permissions, $role->permissions);
}
return $permissions;
}
and access as $user->getPermission($user->id);. This might not be the best solution, but it should solve the problem.
UPDATED CODE
You can use accessor like the example bellow and this will return a permission collection. Use this function in your User Model
public function getPermissions($value){
$role_ids = Roles::where('user_id','=', $value)
->select(array('permission_id'))
->toArray();
return Permission::find($role_ids);
}
and access it like $permissions = App\User::find(1)->permissions;. I believe this will work as you expected.

Related

Trying to get property 'designation_name' of non-object in Laravel 8

I want to show the user role from my user role table, but I can't.
User.php
public function role()
{
return $this->belongsTo('App\Models\Designation');
}
UserController
public function index()
{
$user = User::all();
return view('dashboard2', compact('user'));
}
View
<h1>{{ Auth::user()->role->designation_name}}</h1>
You actually should have shared more details about the relationships. But I will give an answer based on an assumption. It seems like there is a one-to-one relationship betwen User and Role as well as Role and Designation. So you want to reach designation from user. Based on that:
//User.php
public function role()
{
return $this->hasOne(Role::class);
}
//Role.php
public function user()
{
return $this->belongsTo(User::class);
}
public function designation()
{
return $this->hasOne(Designation::class);
}
//Designation.php
public function role()
{
return $this->belongsTo(Role::class);
}
// Controller
public function index()
{
// If you need only the auth user's data, you don't
// need adding relationships into the query.
$users = User::with('role.desgination')->all();
return view('dashboard2', compact('users'));
}
// View
// For auth user:
// I haven't used this way before,
// but technically it should work.
auth()->role()->designation()->name;
// For users collection:
// Make sure you added the query to the controller.
#foreach($users as $user)
$user->role->desgination->name
#endforeach

Laravel Eloquent - Return Users with specific role (many-to-many relationship)

I have an application where I want to find all the users (from a specified client) with a certain role (in this case Super Admin)
A client can have many users
public function users() {
return $this->hasMany(User::class);
}
A user can belong to many roles
public function roles() {
return $this->belongsToMany(Role::class);
}
I want to be able to return all the users from a client with a specific role.
So in the Client Model I want something like:
public function superAdmins() {
return ... // NOT SURE WHAT TO PUT HERE
}
When defining relations you can add where() statements as well.
This means you can use whereHas:
public function superAdmins() {
return $this->hasMany(User::class)
->whereHas('roles', function($query) {
return $query->where('name', 'super');
});
}

How to get permissions from a user that has multiple roles in Laravel?

I'm building a new laravel application, where a user can have multiple roles and these roles have multiple rights (permissions). Now i want to get all the permissions from a certain user.
I'm using Laravel 5.8 and Eloquent. I can get the roles from a user an permissions from a role, but not the permissions from a user.
dd(Auth::user()->roles->rights);
Model user:
public function roles()
{
return $this->belongsToMany(Role::class);
}
Model role:
public function users()
{
return $this->belongsToMany(User::class);
}
public function rights()
{
return $this->belongsToMany(Right::class);
}
Model right
public function roles()
{
return $this->belongsToMany(Role::class);
}
I'm expect to get all permissions for one user past trough by the roles he has.
Since One User can have many roles and one role can have many rights,
you will need to loop through each roles
//Retrieving rights associated with the user
public function retrieveRightsAssociatedWithUser($user){
$rightsAssociatedWithUser = [];
foreach($user->roles as $role){
$rightsAssociatedWithUser[] = $role->rights;
}
return $rightsAssociatedWithUser;
}
You can add to method rights() to User model:
public function rights()
{
return $this->hasManyThrough(Role::class, Right::class);
}
and then use $user->rights();
Additional info:
Laravel has't Thought for manyToMany.
You can install pakage
composer require staudenmeir/eloquent-has-many-deep
and use this:
class User extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function rights()
{
return $this->hasManyDeep(Right::class, ['role_user', Role::class]);
}
}

Should I place logic about authentication on the model?

I'm developing an application which involves authentication and files acl.
Now I want to write a method on the file model called "userCanAccess" which check if the given user/ the user role is in the file acl.
The code will be something along those lines:
public function userCanAccess($user = null) {
$user = is_null($user) ? auth()->user() : $user;
if($this->acl->users->contains($user)
|| $this->acl->roles->contains($user->role)) {
return true;
}
return false
}
Is it right to place this kind of logic on the model?
Laravel has a neat built-in bit of functionality called Policies.
You'd create a FilePolicy that applies to the File model:
php artisan make:policy FilePolicy --model=File
and in the resulting app/Policies/FilePolicy.php, you'll see some ready-to-edit existing policies, one of which is called view. Put your authorization logic here.
Once you've built that, you can apply the policy in a variety of ways, like controller functions, middleware on your routes, or directly within views using the #can Blade directive.
https://laravel.com/docs/5.8/authorization#authorizing-actions-using-policies
This should work just fine for me, but rather than bombing the model class, I would extract it to the trait.
You can make roles and permissions tables
User model:
public function roles()
{
return $this->belongsToMany(Role::class);
}
Role model:
public function users()
{
return $this->belongsToMany(User::class);
}
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
Permission model:
public function roles()
{
return $this->belongsToMany(Role::class);
}
then in app/Providers/AuthServiceProvider you can make Gate like this:
public function boot()
{
$this->registerPolicies();
foreach ($this->getPermissions() as $permission) {
Gate::define($permission->name,function($user) use($permission){
return $user->hasRole($permission->roles);
});
}
}
private function getPermissions(){
return Permission::with('roles')->get();
}
at the end you can use ACL everywhere you want by just write Gate name like:show-comments or access-files or ....

Laravel Eloquent - Get all records of child relation model

My data model is this:
Users > Offices > Organization
This is my model
class Organization extends Model {
protected $table = 'organizations';
public function offices()
{
return $this->hasMany('App\Models\Office');
}
public function users()
{
return $this->offices()->users();
}
....
So.. I want to get all users from an organization (of all the offices).
But I don't know how to do something like
$this->offices()->users();
(Avoiding user a manual collection or map to do that)
Thanks!
So, you have organization ID. You can load all users by using whereHas():
$users = User::whereHas('office', function ($q) use ($organizationId) {
$q->where('organization_id', $organizationId);
})
->get();
Make sure office() relationship is defined correctly in User model:
public function office()
{
return $this->belongsTo('App\Office');
}
Alternatively, you could define hasManyThrough() relationship:
public function users()
{
return $this->hasManyThrough('App\Office', 'App\User');
}
And use it:
$organization->users()

Resources