Many to many relationship not syncing laravel 4.2 - php

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);

Related

How should I model this relationship?

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?

Laravel/Eloquent - Modeling a HasOne relationship via a BelongsToMany relationship

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

Should some relationship tables have their own models?

I'm writing an API with an MVC framework in PHP, and I'm using the Eloquent ORM.
My app has some models which are eventually linked through relationship tables, but intended to be created in a separate, decentralized manner.
Should these relationship tables have their own models, or should the models that are related have methods to create links?
With Eloquent, in regards to intermediate or pivot tables with many to many relationships, you shouldn't need to create an additional model.
You should always set up the relationships for related Models with the belongsToMany() method, documented here: https://laravel.com/docs/5.3/eloquent-relationships#many-to-many
class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
They have various methods of then using this relationship to adding or updating items to the pivot table including attach, detach, or sync documented here: https://laravel.com/docs/5.3/eloquent-relationships#updating-many-to-many-relationships
$user = App\User::find(1);
$user->roles()->attach($roleId);
You can also add data to extra fields:
$user->roles()->attach($roleId, ['expires' => $expires]);
Extra fields on the pivot table are important when you have data, like timestamps, that relate to the relationship and not either of the related models.
An example I could think of would be if you wanted to maintain a history of store managers. You wouldn't just want a store_id and manager_id, you'd also want a started_at and ended_at timestamp. This would allow you to view who is managing a store right now, but also who managed a store in the past.
With Eloquent, these types of extra fields don't require their own model, they can be accessed through the various methods documented above.

Can I use php artisan db:seed to seed related tables?

Is it possible to seed related tables using the following in Laravel 5?
php artisan db:seed
I have two tables
users
id
first name
projects
id
name
and a pivot table
project_user
project_id
user_id
I would like to create a number of users, a number of projects and then relate the users and their respective projects.
Seeding the users and projects isn't a problem but I am not sure how to handle the pivot table.
Is it possible?
Of course you can. If you are using Eloquent, you can simply work with normal relations (maybe the easiest way). Or if you use the SQL builder directly, you can feed the table just as normal, but you need to stick to your foreign key rules.
Just give in a try and you'll see. But make sure you import classes you use.
Adding a relation between two models is easy, but there are some differences between the common relation types (and he perspective): one-to-many, many-to-one and many-to-many.
One-to-Many and Many-to-One
Assumed that each of your project has a creator, an owner so-to-say, you could have a 1:n relation between User and Project.
public class User {
public function ownedProjects() {
return $this->hasMany('App\Project');
}
}
public class Project {
public function owner() {
return $this->belongsTo('App\User');
}
}
In this relation, you can either attach a Project to a User or tell the Project who his owner is.
// Attach a project to an user
$project = Project::create([]);
User::find($id)->ownedProjects()->save($project);
// There is also a function saveMany() for an array of projects
// Tell the project who his owner is
$project = Project::create([]);
$project->owner()->associate(User::find($id));
Many-to-Many
In your case, we need a Many-to-Many relation between Users and Projects. The syntax is a bit different, but the outcome quite straight forward. First we need a relation between the both models:
public class User {
public function projects() {
return $this->belongsToMany('App\Project');
}
}
public class Project {
public function users() {
return $this->belongsToMany('App\User');
}
}
Then we can query the relation just like that:
$project = Project::create([]);
User::find($id)->projects()->attach($project->id);
You can also attach a whole bunch of projects, do the same things from the other side, detach models or synchronize them, if you want to make sure that an exact amount (and only this amount) is in relation:
// Adds a relation for the user to projects with ids 1, 2, 4 and 6
User::find($id)->projects()->attach([1, 2, 4, 6]);
// Adds the users with ids 19 and 173 to this project
Project::find($id)->users()->attach([19, 173]);
// Removes the user 19 from the projects relations
Project::find($id)->users()->detach(19);
// Removes all relations between this user and projects that are
// not listed in the synchronization array and adds a relation
// to all projects where none exists yet
User::find($id)->projects()->sync([4, 7, 19, 6, 38]);
This is the normal syntax for Many-to-Many relations, but you can also attach models just like in a One-to-Many relation:
// Creation of project could also be done before and saved to a variable
User::find($id)->projects()->save(Project::create([]));

What is the correct type of relationship

I have system that logs projects to project managers,
1 Project Can Have Multiple Project Managers
The project managers are essentially just system users, maybe I am having a brain fart but I am struggling to work out the correct relationship to get the data out I need, what I am wanting to is get the database, the project details and the user details for each project manager.
I envisage it being a 1:n relationship but I cannot seem to get the data I want, I am using eloquent to get my relationships and load the data, here are my models,
Project.php
public function projectmanager() {
return $this->belongsToMany('User');
}
User.php
public function projectmanager() {
return $this->belongsTo('Project');
}
But that does not seems to make sense, in my head it feels like I need my project table, user table, and then a further table that would store and ID, the user id, and the project id.
Maybe someone could point me in the right direction, because I am just confusing myself at the moment
Case 1.
If "One Project Can Have Multiple PMs" and "One PM Can Have Only One Project" - you need One-to-Many relationship.
Project.php
public function managers()
{
return $this->hasMany('Manager');
}
Manager.php
public function project()
{
return $this->belongsTo('Project');
}
In this case you need 2 tables: one for projects and one for PMs. In PMs table there should be a field like project_id, which is a foreign key pointing to id field in projects table.
Case 2.
If "One Project Can Have Multiple PMs" and "One PM Can Have Multiple Projects" - then you need Many-to-Many relationship.
Project.php
public function managers()
{
return $this->belongsToMany('Manager');
}
Manager.php
public function projects()
{
return $this->belongsToMany('Project');
}
In this case you need 3 tables: projects table, PMs table (with no foreign key in this case) and so called pivot table, which helds corresponding id fields from projects and PMs tables.
More on relationships and models you can learn in:
Laravel 4.2 Relationships
Laravel 5.0 Relationships
Laravel 6.x Relationships
Laravel 7.x Relationships
Laravel 8.x Relationships
depending on which version you are using.
To create these tables you can use Migrations. You can learn more on this in:
Laravel 4.2 Migrations
Laravel 5.0 Migrations
Laravel 6.x Migrations
Laravel 7.x Migrations
Laravel 8.x Migrations
depending on which version you are using.

Categories