Eloquent relationship between user roles - php

I am creating an app where users have different roles. Some of the roles include:
Administrator
Supervisor
Contractor
I have the following tables setup:
user
role
role_user
The role_user is a pivot table used to store the user_id and role_id.
Now, when a Contractor is created, I trigger an event which assigns the user to the Contractor role in the database:
$user->roles()->save($role, ['cust_id' => $event->user->cust_id]);
The above line basically just creates a new row in the role_user pivot table and points to the role_id of a Contractor. This results in the user having Contractor privileges.
Also, within the event I need to assign the user to a Supervisor. However, there is no Supervisor model. Supervisors are also stored in the user table and have a role of Supervisor assigned to them.
How can I create a relationship between Contractors and Supervisors?
Ideally, i'd like to use something like this to create the Contractor/Supervisor relationship in the pivot table:
$user->supervisors()->save($supervisors, ['cust_id' => $event->user->cust_id]);
But i'm not sure how to setup my model...?
/**
* The supervisors that belong to the user.
*
* #return Object
*/
public function supervisors()
{
return $this->belongsToMany('SimplyTimesheets\Models\User\User')->withTimestamps();
}

What your asking is possible, however your relationship model would look like this:
public function cands()
{
return $this->belongsToMany('Some\Model')->where('something', $something)->where('something', $something);
}
You would have to use where clauses to hard code a relationship between contractors and supervisors because there is no direct relationship between them both.
/* Edit */
From your comment, you would have to approach that query with eager loading your relationship like so:
User::has('supervisors')->join(...)->where(...)->get();
The query above would return all users which meet the roles criteria. If you was just after one result you could create a hasOne relationship with your where clauses.
public function relationship()
{
return $this->hasOne('Your\User_Role\Model', 'foreign_key', 'other_key')->where('role_id', supervisor)->where('role_id', contractor)
}
It all comes down to your application needs.

Related

Laravel adding a role to a newly created user

I am creating a new user from my already made CRUD, however, I don't know how I can also assign a role to the user we are creating. I am working with Laravel and 3 tables. I have 1 table that is my users table, 1 table that is my roles table, and 1 table that is my bridge table between roles and users. I have this made because my users can have more than 1 role assigned to themselves.
My question now is how do I give the user a role and how do I save the user to all the tables I mentioned before. Please remember I am working from a crud, so I have a create view.
Greetings and thanks for all the help!
Assuming you have these tables:
users
roles
role_user
Where role_user has a role_id and a user_id column. Then your models would look something like:
class User extends Model
{
/**
* Roles relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
}
class Role extends Model
{
/**
* Users relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
}
And because it's a BelongsToMany relation, you would use the sync or syncWithoutDetaching methods to add or synchronise user roles. Or attach() for adding a single role to a user. For example:
// The $role variable can be a model instance, or an ID of the role.
$role = Role::all()->random();
$user = User::all()->random();
$user->roles()->syncWithoutDetaching($role);
// or
$user->roles()->attach($role);
I would recommend looking at the documentation for managing the relations (link). Because sync for example removes relations that aren't provided in the given array of models or ID's to synchronise - which would result in an unexpected behaviour if you aren't aware of this behaviour.
I fixed it with the solution written above.

No data fetched from associated table : Laravel

I have users and user_roles tables, and id of user_roles is used as foreign key in users. I fetched data from users using User::with('userRole')->find($user). In returned result userRole is present, however it is empty, instead it was supposed to have data from user_roles for the particular foreign key.
Please, share what can be the possible issues with the functionality or if anyone can explain working of laravel associations in brief.
/* User Model */
public function userRole()
{
return $this->belongsTo('App\UserRole');
}
/* UserRole Model */
public function user()
{
return $this->hasMany('App\User');
}
Thank You,
Many to many relationships in Laravel often require you to have 2 models and 3 tables. One to many relationships require you to have 2 models and 2 tables. One to one relationship also requires you to have 2 models and 2 tables.
Many to many relationship
Let's take User and Role models, since each User can have multiple roles and one Role can be assigned to different users, you will naturally want a Many to many relationship. Now, you will need to create an intermediate table in which you will store the results, why? Because you already defined both User and Role and since it is Many to many none of those objects will have any identifier of the other one inside of them, but rather will have their own identifier in the intermediate table, and this is how Laravel fetches the relationship, it connects Models primary key with foreign key inside of the intermediate table.
One to many relationships
Let's take User and Role models again and let's say that this time, one Role can be assigned to multiple users, but one User can ONLY have 1 Role. Naturally you will have a field role_id inside of your User model and you will connect role_id from users with id from roles.
One to one relationships
Lets take User and Role models again :D Let's say you want to create a separate Role for every user, then you will have 2 models and 2 tables where your users table will have all the users and your roles table will contain id, name, user_id and now when you try to retrieve the relationship, if you define one to one laravel will return only 1 result, no matter if you have multiple same user_id on the roles table, Laravel will return only 1 role because you told him explicitly it's 1-to-1 relationship.
EDIT:
Here is an example of one to one relationship:
/* User Model */
public function userRole()
{
return $this->belongsTo('App\UserRole', 'user_role_id', 'id');
}
#Tim and #Nikola
Thank you, for your efforts mates.
However, I found the reason behind the problem. It was because the wrong naming of userRole function in User model.
I was using foreign key of user_roles as user_roles_id in users table and defined function with name of userRole in User model. This leads to ORM not found the relevant column for attaching user_roles data.
The solution is either I have to change the name of user_roles_id to user_role_id or userRole function name to userRoles. And I choose the first one and it worked fine. :)
For reference on the naming conventions of laravel please refer to Laravel - Database, Table and Column Naming Conventions?.

How do I access one model from another which don't have direct relationship?

I have an User model. Each user has certain grades and each grade has certain students.
User and Grade models have one-to-many relationship. Grade and Student models have one-to-many relationship too. But, User and Student models don't have any relationship.
Once User is logged in, he should be able to search all students that belongs to the user.
Do I have to create relationship between these two models to?
If I understand the question correctly, a user has multiple students, so what I'd do is create a one-to-many relationship between them like this:
//User.php
public function students()
{
return $this->hasMany(Student::class);
}
//Student.php
public function user()
{
return $this->belongsToOne(User::class);
}
This would allow you to pick up a users students by doing: $students = $user->students Note: I didn't use () here. If you were to execute $students = $user->students() you'd end up with a query builder object.

Laravel eloquent many to many relationship determine if relation exist

I am working on a project with many-to-many relationship between two tables roles and users. I also have a pivot table role_user that holds information about the relation between the other two tables.
role_user two fields namely the ids of the two tables: role_id and user_id.
Now I have a user object gotten from the users table and another role object gotten from the roles table. I want to determine if a particular role belongs to a certain user.
I know this can be done by creating a model for the pivot table and then using the model, the role_user table can be queried and determined if the relation exists.
But I find this method stressful and wonder if eloquent provides an easy method to determine this.
Thanks for any help?
You don't need to have a role_user model. You might already have role model and the user model related to the tables you have.
Specify the many to many relationship in Role.php and User.php
User.php - function roles
public function roles()
{
return $this->belongsToMany('App\Role');
}
Role.php - function users
public function users()
{
return $this->belongsToMany('App\User');
}
You may have to define other parameters like pivot table etc if you don't follow the naming conventions in table columns and tables. Since you seem to have follow the rules I'm not going to explain it. But you always can refer to laravel documentation's eloquent many-to-may section
now you can easily check whether a user belongs to a certain role.
Consider the following examle
//select a user
$user = App\User::find(1);
//select a role
$role = App\Role::find(1);
//get $user's roles. This ill return an array of role objects that are belong to $user
$userRoles = $user->roles;
//check whether $role is in that array
if(in_array($role, $userRoles)){
//do something
}

Laravel 5 database relation type

I would like to use Laravel 5 Models to retrieve a relationship, but i dont know which relation type i should use and how to implement it.
i have 4 database tables:
Users
Roles
Permissions
role_permission
i need to retrieve all the permissions for a "User" based on its "role_id" column.
I've created 3 models:
User
Role
Permission
The database table "users" holds 2 columns:
id
role_id
The database table "roles" holds 2 columns
id
name
The database table "permissions" holds 2 columns
id
name
The database table "role_permission" holds 3 columns that defines which Role is associated to which Permission.
role_id
permission_id
flag
What i want to achieve is the following syntax:
$user->role // Get the associated "Role"
$user->role->permissions // Get the associated permissions for a "Role"
App\Role::find(1)->permissions // Get the associated permissions for a "Role"
i did read the Laravel documentation about model relations but i really dont get it. Does someone understand what i'm trying to achieve and how to implement it in the Models? maybe with some simpel code examples so i can understand the relations and how they work?
Thanks in advance.
The way that you have your database defined, you have defined the following relationships: a one-to-many between role and users, and a many-to-many between roles and permissions. It can also be stated that a role has many users, a user belongs to a role, a role has many permissions, and a permission has many roles.
In Laravel, one-to-one relationships are modeled using a hasOne/belongsTo set, one-to-many relationships are modeled using a hasMany/belongsTo set, and many-to-many relationships are modeled using a belongsToMany/belongsToMany set.
The relationships are defined in the models below:
User:
Since the users table contains the foreign key to the roles table (role_id), the User model is on the belongsTo side of the one-to-one/one-to-many relationship.
class User extends Model {
public function role() {
return $this->belongsTo('\App\Role');
}
}
Role/Permission:
The many-to-many with permissions is done by both models having a belongsToMany relationship. The Laravel convention for the pivot table name is the combination of the singular table names, in alphabetical order, with an underscore separator, so it should be 'permission_role'. Since the pivot table name doesn't follow convention, it must be specified in the relationship definition. Also, since you have an extra field on the pivot table, you need to specify access to that field with the withPivot() method on the relationship.
class Role extends Model {
public function users() {
return $this->hasMany('\App\User');
}
public function permissions() {
return $this->belongsToMany('\App\Permission', 'role_permission')->withPivot('flag');
}
}
class Permission extends Model {
public function roles() {
return $this->belongsToMany('\App\Role', 'role_permission')->withPivot('flag');
}
}

Categories