I've read the docs on relationships and have a few questions.
I have a user and a role table. The relationship is many to many. A user has many roles and a role can belong to many users. So I have set up a pivot table and have used a belongsToMany in each model. But surely a user hasMany roles and a role belongsToMany users.
But when I use hasMany, my queries do not work as expected. Is this just a wording thing and both should be belongsToMany?
I also wanted to know about defining the relationship on each model - do you need to or can it just be defined on users?
The hasMany relationship is for defining one to many relationships and that is why it will break your queries.
I can see why you are thinking along the lines of a user having many roles, but it also perfectly good English to say a user belongs to many roles and that a role belongs to many users.
You don't need to define the relationship on both models if you are only going to query one model and it's relationship. But can you say definitively that you will never need to query the relationship on roles?
I advice to you, study this description:
http://scotch.io/tutorials/php/a-guide-to-using-eloquent-orm-in-laravel
It will be useful for you.
(You should use only "belongToMany" in each model without "hasMany")
User model:
// app/models/User.php
<?php
class User extends Eloquent {
// each user BELONGS to many role
// define our pivot table also
public function roles() {
return $this->belongsToMany('Role', 'users_roles', 'user_id', 'role_id');
}
}
Role model:
// app/models/Role.php
<?php
class Role extends Eloquent {
// DEFINE RELATIONSHIPS --------------------------------------------------
// define a many to many relationship
// also call the linking table
public function users() {
return $this->belongsToMany('User', 'users_roles', 'role_id', 'user_id');
}
}
Related
I am using the User model and want to reference other users on a One to Many relationship.
With two models, this would be done by a Many to Many but this attempt at it is obviously wrong:
public function relatedUsers()
{
return $this->belongsToMany(User::class, 'related_user', 'user_id', 'user_id');
}
Is there a better way I can achieve my goal? I don't need an inverse method.
You can use hasMany() or belongsTo() (according to your need) relation for same model relationship
Define hasMany relationship in User model:
public function relatedUsers() {
return $this->hasMany('User','user_id');
}
Example:
Consider you have one User object
$user = User::where('id',$id)->first();
If you want to access related records
$related_users = $user->relatedUsers; // this will return all related users for particular object
I would like to obtain for ONE user his country. So I have two tables:
User
id
country_id
Countries
id
I can't decide which relationship to use. I think it is the OneToMany relationship (Inverse) but it implies that the Countries table has the user id.
I can't understand how to use the oneToMany relationship in this case...
Docs link: https://laravel.com/docs/6.x/eloquent-relationships#one-to-many-inverse
One To Many (Inverse)
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship function on the child model which calls the belongsTo method:
You need to create a belongsTo to relation on your user model.
class User extends Model
{
public function country()
{
return $this->belongsTo('App\Country');
}
}
Lets supose this scenery:
We have 3 models -> User, Role and Permission.
Relationships
User has one to many relationship with Role.
Role has many to many relationship with Permission
User has many to many relationship with Permission.
The final purpose to the User -- Permisson relationships is to override the permission assigned to the user through his role. Just an exception for this User.
I am trying to to something like this:
public function permissions () {
return $this->hasManyThrough('App\Permission', 'App\Role')->merge($this->permissionOverrides);
}
In this case when I try to eager load the model permissions Laravel throws an error 'cause permissions is not detected as a relationships.
In the other hand, what if we change User -- Role relationship to many to many?
Thanks a lot for your knowledge!
EDIT
Role Relationships
public function permissions() {
return $this->belongsToMany('App\Permission')->withTimestamps();
}
Permission relationships
public function roles() {
return $this->belongsToMany('App\Role')->withTimestamps();
}
User relationships
public function roles() {
return $this->belongsToMany('App\Role')->withTimestamps();
}
public function permissionOverrides() {
return $this->belongsToMany('App\Permission')->withTimestamps();
}
The question is how to make the permissions() relationship merging the role permissions and the user permissions.
BETTER EXPLANATION
Due to misunderstanding shown in comments I will try to exlain this better. I had set all the relations between App\User and App\Role; I also had set the the relationship between App\Role and App\Permission. I can do right now:
$user->role->permissions;
For obtaining this I have configured the pivot table permission_role which stores the relation.
Thats not the case. What I want is to add one more var to the equation. Now I want to have the ability to override the role permissions adding a relationship between App\User and App\Permission. I have the pivot table permission_user and the relation stablished:
public function permissionsOverride() {
return $this->belongsToMany('App\Permission');
}
The REAL QUESTION is how to obtain all the permissions (both role permissions and overrided permissions in only ONE relationship). I mean merging both relationships.
Why I want to merge relationships? I could do a regular function to do this, but I would want to eager load this relation, Laravel way.
You can try like this, ManyToMany relation between User And Role, similarly ManyToMany relation between Role and Permission.
User Model
public function roles() {
return $this->belongsToMany('App\Role', 'user_role')->withTimestamps();
}
public function permissions() {
return $this->belongsToMany('App\Permission', 'permission_user')->withTimestamps();
}
Role Model
public function users() {
return $this->belongsToMany('App\User', 'user_role')->withTimestamps();
}
public function permissions() {
return $this->belongsToMany('App\Permission', 'permission_role')->withTimestamps();
}
Fetch Data
$user = User::with('permissions','roles','roles.permissions')->find(1);
$permissions = $user->permissions;
foreach($user->roles as $role){
$permissions->merge($role->permissions); //merger collection
}
dd($permissions->all());
For details you can look https://laravel.com/docs/5.6/eloquent-relationships#many-to-many
And for Collection you can look this https://laravel.com/docs/5.6/collections#method-merge
Hello Am trying to create many to many relationship but I failed. I have two table requests_table and Users_table and the relationship is many to many I introduce associative table called request_user with attribute of user_id, request_id and user_reqId(primary key). what I want is to submit data(user_id and request_id) to the associative entity when user request for anything?. help please....
Many-to-many relations are slightly more complicated than hasOne and hasMany relationships. An example of such a relationship is a user with many roles, where the roles are also shared by other users. For example, many users may have the role of "Admin". To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
Many-to-many relationships are defined by writing a method that returns the result of the belongsToMany method.
Happy coding:)-
You should try this:
request_tbl.php
public function users() {
return $this->belongsToMany(User::class, 'request_user');
}
user.php
public function requests()
{
return $this->belongsToMany(RequestTbl::class, 'request_user');
}
Controller
$request_tbl = new requests_table();
$users = $request->users;
$request_tbl->users()->sync($users);
For the case of a one-to-one relationship, if I fully specify the keys in the method calls, is there a difference between hasOne and belongsTo relationships? Or, asked differently, if I used hasOne on both sides of the relation, would it be the same result?
Yes it works for some cases to specify the keys and make the relation work. And with some cases I mean mainly retrieving results. Here's an example:
DB
users profiles
----- --------
id id
etc... user_id
etc...
Models
Using "wrong" relations with hasOne twice
class User extends Eloquent {
public function profile(){
return $this->hasOne('Profile');
}
}
class Profile extends Eloquent {
public function user(){
return $this->hasOne('User', 'id', 'user_id');
}
}
Queries
Let's say we wanted to get the user from a certain profile
$profile = Profile::find(1);
$user = $profile->user;
This is working. But it's not working how it's supposed to be. It will treat the primary key of users like a foreign key that references user_id in profiles.
And while this may work you will get in trouble when using more complicated relationship methods.
For example associate:
$user = User::find(1);
$profile = Profile::find(2);
$profile->user()->associate($user);
$profile->save();
The call will throw an exception because HasOne doesn't have the method associate. (BelongsTo has it)
Conclusion
Whereas belongsTo and hasOne may behave similar in some situations. They are clearly not. More complex interactions with the relationship won't work and it's nonsense from a semantic point of view.