Say I have four tables:
users
groups
activities
group_activities
Where a group can have any number of activities and an activity can belong to any number of groups through their intermediate table group_activities, and a user belongs to one group via users.group_id. I want to correctly model a relationship between users and activities so that a user can have any one activity, but only if the group that user belongs to has a relation to that activity.
HasOneThrough doesn't seem to work here, since the group the user is related through has multiple activities. HasManyThrough doesn't work since the user can only have one.
I want to properly model this relationship so that it can be picked up for selection automatically via a Nova relationship field, but I'm struggling to figure out exactly how I would do so. My first thought is a HasOneThrough relation with some set of subqueries, but I can't quite piece together where to start.
How would I do this, or conversely, is it possible via Eloquent's automatic relationship system at all?
To ensure we are on the same idea of your relationships:
The relationship between Groups and Activities is a Many To Many relationship (Many To Many - Larvel Documentation).
The group_activities table is the pivot table.
The relationship between users and groups is a One To Many relationship One To Many - Larvel Documentation and the inverse of it One To Many (Inverse) - Larvel Documentation.
To actually answer your question:
If you want to use a shortcut from users to their activities, the Has Many Through is the correct way. If a group can have arbitrary many activities, and a user belongs to one group, the user will be associated to these arbitrary many activities through the group -hence Has Many Through. Note that this is not really a separate relationship though, it's just a convient shortcut.
If you wan't to associate a user with a single Activity directly, you need to to this via a separate One to Many relationship between Users and Activities.
I'm not entirely sure if I interpret your question correctly, so the following is just an assumption, but do you want to ensure a user can only be associated to an activity thats also associated with the user group? So to restrict possible activites by group? If that is the case, you'd simply need to check if the selected activity is in the activities associated with the users group:
With your relationships set up like this:
class User {
public function activity(){
return $this->belongsTo('App\Activity');
}
public function possibleActivities(){
return $this->hasManyThrough('App\Activity','App\Group');
}
}
you can check and associate activities like this:
if( $user->possibleActivities()->contains( $activity ) ){
$user->activity()->associate($activity);
}
Related
Same story as many other questions on this site: I've banged my head into the wall for hours on end trying to figure out these relationships.
I have 3 models where the relationship should work like this:
Model: User
User can belong to many schools.
User belongs to one “Role” separately on each school.
User can be activated/deactivated separately on each school.
Model: School.
School can belong to many users
Model: Role.
Roles would be “Standard” or “Administrator”.
I have a pivot table that connects users and schools.
On the pivot table, I've also experimented with adding 'role_id' and 'is_activated' columns - which I doubt is the correct way about doing this?
I want to access data like this:
User
Get schools belonging to the user.
Get role for current school.
Get activated/deactivated status for current school.
School
Get all users belonging to the school.
Get role for each user.
Get activated/deactived status for each user.
I would've solved this if users could only belong to one school each, but since the same user can belong to several schools it got too complicated for me.
What kind of relationships should I apply on each model?
I would very much appreciate if anyone can point me in the right direction here. Thanks!
You can have a many-to-many relationship between user and school. This would require a pivot table between them to store the ids of the two models. At the end your relationship from a user point of view will end up being:
public function schools() {
return $this->belongsToMany('App\Models\School', 'pivot_table', 'user_id', 'school_id');
}
You can have a look at laravel docs on Many-to-Many
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?.
I'm curious why the Eloquent relationship for hasMany has a different signature than for belongsToMany. Specifically the custom join table name-- for a system where a given Comment belongs to many Roles, and a given Role would have many Comments, I want to store the relationship in a table called my_custom_join_table and have the keys set up as comment_key and role_key.
return $this->belongsToMany('App\Role', 'my_custom_join_table', 'comment_key', 'role_key'); // works
But on the inverse, I can't define that custom table (at least the docs don't mention it):
return $this->hasMany('App\Comment', 'comment_key', 'role_key');
If I have a Role object that hasMany Comments, but I use a non-standard table name to store that relationship, why can I use this non-standard table going one way but not the other?
hasMany is used in a One To Many relationship while belongsToMany refers to a Many To Many relationship. They are both distinct relationship types and each require a different database structure - thus they take different parameters.
The key difference is that in a One To Many relationship, you only need the two database tables that correspond to the related models. This is because the reference to the relation is stored on the owned model's table itself. For instance, you might have a Country model and a City model. A Country has many cities. However, each City only exists in one country. Therefore, you would store that country on the City model itself (as country_id or something like that).
However, a Many To Many relationship requires a third database table, called a pivot table. The pivot table stores references to both the models and you can declare it as a second parameter in the relationship declaration. For example, imagine you have your City model and you also have a Car model. You want a relationship to show the types of cars people drive in each city. Well, in one city people will drive many different types of car. However, if you look at one car type you will also know that it can be driven in many different cities. Therefore it would be impossible to store a city_id or a car_id on either model because each would have more than one. Therefore, you put those references in the pivot table.
As a rule of thumb, if you use a belongsToMany relationship, it can only be paired with another belongsToMany relationship and means that you have a third pivot table. If you use a hasMany relationship, it can only be paired with a belongsTo relationship and no extra database tables are required.
In your example, you just need to make the inverse relation into a belongsToMany and add your custom table again, along with the foreign and local keys (reversing the order from the other model).
Try to understand with text and a figure.
One to One(hasOne) relationship:
A user has(can have) one profile. So, a profile belongs to one user.
One to many(hasMany):
A user has many(can have many) articles. So, many articles belong to one user.
Many to many(BelongsToMany):
A User can belong to many forums. So, a forum belongs to many users.
I was wondering if there is a smart way of having several common columns to different tables in CakePhP. I could use a common table having relationships to these tables, but is there a behavior or similar mechanism for which I can have:
Users
Customers
CommonPersonalFields
And have some common fields in the third table, fetched automatically by cake. In this way you could also have common views for those fields, included in the other tables views.
This is done with Model Associations in CakePHP. In this scenario, your models would be User, Customer, and PersonalData, and your associations are User hasOne PersonalData, Customer hasOne PersonalData, and if you want the association to be linked from both directions, PersonalData belongsTo User and PersonalData belongsTo Customer.
I am trying to get my head around some relationships between models in Laravel.
I would like to define the relationship between the following models:
User - the users
Campaign - a campaign
Call - a phone call
Lead - Lead/client
Sale - A sale
Appointment - A scheduled phone call.
This is the way the relationship should be:
A user can be assigned to many campaigns.
A user can have many calls.
One user can have many appointments.
One call belongs to one user.
One call belongs to one campaign.
A campaign can have many calls.
A campaign can have many sales
A lead can be assigned to many campaigns.
A lead can have many sales
One lead belongs to one user in one campaign.
One lead can have many calls
One sale belongs to one campaign
One sale belongs to one user
One appointments belongs to one lead.
I uncertain about how to setup the relationship. Its easy with the one-to-one or many-to-one.
But what about this:
Call->User (one-to-one)
Call->Campaign (one-to-one)
Campaign->Call (one-to-many)
User->Call (one-to-many)
Hopefully I managed to explain it clear enough. Thanks.
I'd recommend reading the Laravel docs on relationships again.
Taking the Call/User relationship as an example, here's what you're looking at:
User --------> Call
(one) (many)
This is clearly a one to many relationship. And if you want to set up both sides of this relationship in terms of an Eloquent model, the relationships are this:
A User hasMany Calls
A Call belongsTo a User
These terms are taken directly from the documentation, in the section entitled One To Many.
So, in code...
User Model
public function Calls()
{
$this->hasMany("Call");
}
(notice that I've made the method name plural - this is my own preference, since using $user->Calls will return a collection if items).
Call Model
public function User()
{
$this->belongsTo("User");
}
Rather than taking the two sides of a relationship in isolation, as you seem to have done in your analysis, consider both sides of the relationship at the same time.