I have a project running Laravel 5.5, and I have the following tables in the database.
USERS (
ID,
NAME,
PERMISSION_ID
)
PERMISSIONS (
ID,
NAME
)
If I am not wrong, USERS relationship with PERMISSIONS is 1.1 (USERS has at least 1 permission and a maximum of 1), so it's a OneToOne relationship.
In my user model I made the following relationship.
class User extends Authenticatable
{
public function permission () {
return $this->hasOne('App\Models\Permission');
}
}
But in this way Laravel/Eloquent looks for the relationship in the PERMISSIONS table. Generating a select similar to:
SELECT * FROM PERMISSIONS WHERE PERMISSIONS.USER_ID = 1
I have already consulted the Laravel documentation and saw that I can specify the ForeignKey and LocalKey in the hasOne method. This solves the relationship.
But is it really correct for Laravel/Eloquent by default to fetch the information in the PERMISSIONS table? The correct one would not be to look in the USERS table with PERMISSION_ID?
#Edit
Due to the response of Alexey Mezenin
I researched the difference between hasOne and belongsTo. And I found the following answer:
What is the difference between BelongsTo And HasOne in Laravel
From what I understood, when the foreign key is on the other table the correct one is to use hasOne.
When the foreign key is in the template's own table, the correct one is to use belongsTo.
I'll stay tuned in on these details next time, thanks Alexey Mezenin and jedrzej.kurylo
Your relationship is inverted, you're using hasOne() instead of belongsTo. Use this relationship in the User model:
public function permission()
{
return $this->belongsTo(Permission::class);
}
And in the Permission model you might want to add hasOne() relationship (in case if you would want to use it):
public function user()
{
return $this->hasOne(User::class);
}
But usually, the same permission can be used by many users. If this is the case, just change hasOne to hasMany.
Related
I have a problem with Laravel relationships.
I need to make relationship based on this table:
issuer and friend need to be united. Relationship will return all rows where user id in issuer or in friend. At the moment code looks like this:
return DB::table('contacts')->select()->where('friend', $this->id)->orWhere('issuer', $this->id)->where('status', 'approved');
Previously I used that method, but there are no relationship, 'cause attach() is undefined.
private function contactsIssued() {
return $this->belongsToMany(User::class, 'contacts','issuer', 'friend');
}
private function contactsFriended() {
return $this->belongsToMany(User::class, 'contacts','friend', 'issuer');
}
public function contacts() {
return $this->contactsIssued()->union($this->contactsFriended()->toBase());
}
So, I need to make one relationship that has two foreign columns.
Sorry, my English can be broken, 'cause it's not my native language.
That's look like a one to many relationship but you are using belongsToMany which is many to many relationship and required a pivot table.
if you have user model that has many contact model then in your contact model you should use the one to many relationship by using belongsTo.
but if you have 3 table you didn't say that in you question then please edit you question and provide your models and the relations between them.
I am currently building my first App with Laravel and have stumbled upon the problem that I dont know how to setup the relationship Many-to-Many between the Models (User and Group).
I've created a board in which I store the relationship between all users and the Group they are in.
My Problem is that I dont know how to acces and set this up in Laravel.
Im not sure whether I have to user hasMany or belongsToMany.
I am trying to find a method to add a User to Group, so that a new entry will be created in the UserGroups table.
My tables:
User
ID
Name
Email
Group
ID
Name
Creator_ID
UserGroup
User_ID
Group_ID
I appreciate any help, thanks!
If you want to create a many-to-many relationship, it should be belongsToMany, not hasMany.
In the Group model:
public function users()
{
return $this->belongsToMany(Group::class);
}
And in the User model:
public function groups()
{
return $this->belongsToMany(User::class);
}
The pivot table should be called group_user.
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
In the model class, use belongsToMany as demonstrated here: https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
To add a user to a group, use attach(), as demonstrated here:
https://laravel.com/docs/5.4/eloquent-relationships#the-create-method (scroll to many to many relations)
So I understand how to load the roles for a user and the permissions for a role.
But now I have a user table, a role table, and a permission table. I also have role_user table for linking users and roles. And of course a permission_role for linking permissions and roles.
Now when I want to get all the roles for the user, I simply do something like this:
public function roles()
{
return $this->belongsToMany('Uppdragshuset\AO\Tenant\Models\Role');
}
Similarly I can fetch permissions for roles like so:
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
Now according to the documentation on laravel, I can directly fetch permissions for a user by using the hasManyThrough relation too like so:
public function permissions()
{
return $this->hasManyThrough(Permission::class, Role::class);
}
But this is returning with an error saying:
Unknown column 'role.user_id' in 'field list'
I think I understand why. Laravel is looking for user_id field in the role table but it does not understand that it is a many to many relation and it should look for it in the pivot table.
So what is the way around this? Is there a way around this in Eloquent or will I have to resort to using the query builder? And if yes, how to do the same thing with the query builder?
HasManyThrough can only be used to connect two HasMany relationships. There is no native relationship for your case.
I created a HasManyThrough relationship with unlimited levels and support for BelongsToMany:
Repository on GitHub
After the installation, you can use it like this:
class User extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function permissions() {
return $this->hasManyDeep(Permission::class, ['role_user', Role::class, 'permission_role']);
}
}
I am building an app with a many-to-many between users and roles and a many-to-many between roles and permissions.
I would like to get the permissions of a user with the hasManyThrough, but it doesn't work. This relation expects a user_id in the roles table, but as they are many to many, there is none of course.
Anyone who has a fix?
hasmanythrough on a many-to-many relationship is not possible.
This has been answered in more detail in another thread:
HasManyThrough with one-to-many relationship
And you can also refer to: http://laravel-tricks.com/tricks/i-has-many-through-relation-laravel-the-missed-shortcut
There is a Laravel 5.5 composer package that can perform multi-level relationships (deep)
Package:
https://github.com/staudenmeir/eloquent-has-many-deep
Example:
User → belongs to many → Role → belongs to many → Permission
class User extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function permissions()
{
return $this->hasManyDeep(
'App\Permission',
['role_user', 'App\Role', 'permission_role'], // Pivot tables/models starting from the Parent, which is the User
);
}
}
Example if foreign keys need to be defined:
https://github.com/staudenmeir/eloquent-has-many-deep/issues/7#issuecomment-431477943
I have a couple of models that I have included pivot tables for to avoid a polymorphic relation.
role table
id
name
description
restriction table
id
rule
status
restriction_role table
id
restriction_id
role_id
Reason for this setup is that both Roles and Restrictions can actually belong to multiple other models. In this case, a Role can only have 1 Restriction. I would normally define this as
class Role extends Eloquent {
public function restrictions()
{
return $this->hasOne('Restriction');
}
}
This obviously does not work because Laravel is unaware of the pivot table connecting this relation. I could easily accomplish this by using a many-to-many relationship instead, but this is not exactly how my model works. Not seeing anything in the documentation for defining this. Any thoughts?
I've solved this by using the belongsToMany relation and defining a custom accessor for it, like so:
public function foo()
{
return $this->belongsToMany(App\Bar::class);
}
public function getFooAttribute()
{
return $this->foo()->first();
}
As #deczo stated in the comments, belongsToMany() is about all that will work here. I recommend returning the first result using the first() method if you require only one result but cannot use a hasOne() relationship.