I'm relatively new to PHP and just started to learn Laravel. I leave a few questions regarding a personal learning project I'm working on. Thank you in advance for any feedback!
CONTEXT:
My project is using the default laravel 7.x UI and auth scaffolding. I'v implemented user roles with a roles table and a role_user table. This works as intended (e.g. I can perform CRUD on users and their roles)
Many users can have many roles.
ROLES:
Customer
Agent
Admin
I run into trouble when trying to implement user Statuses. Like this:
Users with the Role of Agent can have only one Status at any given time; either 'AVAILABLE' or 'BUSY'.
QUESTIONS:
#1. How should I define the Agent User/Status relationship? Initially I did Many to Many. I created a statuses table and status_user table. Later I concluded that this was incorrect and changed the relationship to Many to One as seen below. ( I didn't change any of my tables)
In the Users Model:
public function statuses(){
return $this->belongsTo('App\Status');
}
In the Status Model:
public function users(){
return $this->belongsToMany('App\User');
}
Some thoughts:
After having trouble with some queries I'm starting to think using the two tables (statuses and status_user) is in incorrect given how I modeled them above.
Should I rollback and just add a "status_id" column to the user table while keeping the tables as is? I'm starting to think I'm getting the entire relationship wrong.
Maybe I shouldn't be relating status to the users table; instead to a separate 'Agents' table?
Related
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);
}
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'm kinda confused how the eloquent relationships works in Laravel 5.4.
I got a school model that has a "hasMany" relationship with my user model:
public function users()
{
return $this->hasMany('App\User');
}
The user is not required to be linked to a school though, so I haven't put the belongsTo (school) function on my user model.
How should I link the user to a school, when I create the user and how can I pull all users in a specific school into a view, for example?
If the user can only belong to one school, the most straightforward approach would be to add a school_id column to the users table. Since it's not required, you can allow for it to be null. This will allow you to run $school->users to retrieve a list of users for a given school.
I would also recommend adding the belongsTo relationship to the User model, so you can do $user->school to retrieve a user's school when applicable. It's okay that it'll be null for some users.
I am trying to create a laravel application with version 5.2. Where there will be 3 types of users
Administrator (website manager) - using default "users" table for
this.
Owners (Website listing creator from frontend) - using a
table "owners" for this.
Customer (Visitors or registered
visitors) - using a table "customers" for this.
Now my problem is:
i want to make sure login Owners will get proper authentication and redirect to their own (other then default Auth route) route.
And same with customer, and they will be mainly login through frontend of the website, so their route will be different from owners and Administrator. And these customer will also get authentication.
How can i manage that? I have worked around with single table, but being as a new person to Laravel i am not sure how i can achieve with multiple table.
I have checked laravel 5.2 started supporting multiple gaurds now, but not sure how can i do this.
There are certain packages for this, but i dont want to relay on package for this.
Thank you!
I would suggest you follow a Polymorphic approach for this.
Let's say there are three different tables - administrators, owners, customers
Now for all of them, there is a common table with the name users which will have the columns :- profile_id, profile_type.
Now profile_id will become the foreign key for tables administrators, owners and customers and profile_type will tell which Model the user belongs to.
Relation would be like,
class User {
public function profile() {
return $this->morphTo();
}
}
--
class Administrator {
public function user() {
return $this->morphOne('App\User', 'profile');
}
}
Here we are using morphOne instead of morphMany because the profile_id field in users table should have only one row for one admin.
Lastly, for the purpose of creation/storing. You'll have to :-
Create an admin like
$admin = Administrator::create($inputs);
Then do
$user = new User($inputs);
$admin->user()->save($user);
You're done!
You can learn more about it this approach from https://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations
Thanks,
I have an object that has a one-to-many relationship with another object,
Client n:1 Project
A project client can have many users
Client n:n Users (pivot table of client_user)
And a project can have many users
Project n:n Users (Pivot table of project_user)
I have the project model in my code, I can run a sync on the projects users,
$project->viewers()->sync($syncArray)
After that I also want to sync the users to client, I am trying to do this, my doing,
$project->clients()->viewers()->sync($syncArray)
but it is complaining that it cannot find viewers, is there a ways to sync a relationship from a relationship or will I need to query the database to get that specific client first?
I'm not sure that you can chain relationships that easily. ->clients() returns as HasMany class and doesn't know about it's relationship to the users yet until you query them. Try grabbing the clients first and then looping over them to sync, e.g.:
foreach($project->clients as $client)
{
$client->viewers()->sync($syncArray);
}
// or
$project->clients->each(function($client) use ($syncArray)
{
$client->viewers()->sync($syncArray);
});
Edit: You could also try using a hasManyThrough relationship
class Project {
public function viewers()
{
return $this->hasManyThrough('App\User', 'App\Client');
}
}
$project->viewers()->sync($syncArray);