laravel hasmanythrough on manytomany - php

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

Related

Understanding hasOne() and belongsTo() functions in Laravel

All I'm trying to do is understanding when exactly should I use hasOne() and when should I use belongsTo(). Both seem identical to me. For example, here is my model:
use Illuminate\Database\Eloquent\Model;
use App\Categories;
use App\User;
class tickets extends Model
{
protected $table = "tickets";
public function category()
{
return $this->hasOne(Categories::class, 'id', 'category_id');
}
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}
I can do the same by using belongsTo() function too. Just I should put them into user and category models instead. Anyway, when should I use either hasOne() or belongsTo() ?
When dealing with 1 to many relationships, you will have a hasMany()and a belongsTo() .
The rule of thumb I use, is if a table has a foreign key (tickets table has a user_id fk) then this model belongsTo users.
The same with Category.
So your above example, Ticket belongsTo User & Category.
Inversely, User hasMany Ticket and similarly Category hasMany Ticket
Anyway, when should I use either hasOne() or belongsTo() ?
Think of it like what would be hasMany if there is one to many relation probable in the future. For example: consider User and Phone models. Nature of relation would be User hasOne Phone, but if you would like to extend functionality for it so user could have multiple phone numbers registered User would still have has* relation while Phone would keep belongsTo relation. Just consider which one could be "parent" entity and that one should have hasOne relation in method. I would always consider User as parent entity and for me logically would be user has one ticket.
Also, try to stick with Eloquent/Laravel/artisan naming convention and name that model Ticket and other one Category (Eloquent and Laravel will solve plural where needed i.e. table name).
hasOne is a 1:1, or one-to-one relationship.
hasMany is a 1:n, or one-to-many relationship.
The belongsTo method in Eloquent is used to define the inverse of these relationships.
The definition of these will depend on your data model.
In your case:
You have a Category model, which hasMany Tickets.
You also have a User model, which hasMany Tickets.
Now from the Ticket perspective, you would want to define the inverses of these 2 hasMany relationships. You will do this by defining a belongsTo.
So the Ticket belongsTo a User and belongsTo a Category.
To answer your question:
From the Tickets perspective, it is a 1:1 relation, because the foreign key in the Ticket model points to 1 User and the category foreign key points to 1 Category.
But since the relation you created is a 1:n (one-to-many) and you have also defined it on the User and Category models, you should define the relation in your Ticket model as the inverse of those relations, and the inverse of a hasMany (and hasOne) is belongsTo.
When defining your relations in Laravel, keep your database schema in mind and define your relations in the same way that they exist in your database schema.
These are same with a single difference. Both returns the single associated object with one difference. When we declare some relation as belongsTo it means there is a database table which has a foreign key of some other table. When we declare hasOne relation it means that this table's primary key has been referenced in another table. Think of it as a parent child table. When we would make the child table we reference each child to its parent, right? This is belongsTo. And when we would make the parent table we know that each entry in parents table can have a single or many entries in the child table. That's hasOne or hasMany relation. You can ask further if you need any more clarification.

Laravel's relationship using Eloquent really correct?

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.

Laravel Many to Many Relationship ( hasMany or belongsToMany )

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)

How to establish a hasManyThrough relationship in laravel for roles and permissions?

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']);
}
}

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