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([]));
Related
In my app, you can create lists of roles that are attached to contacts. So you can assign the contact "Bob" the roles of "Gardener" and "Pet Sitter". Then you can create the list "People" and add "Gardener (Bob)" and "Pet Sitter (Bob)" to it.
I have the following tables:
contacts
id
name
roles
id
name
contact_role (pivot)
id
contact_id
role_id
lists
id
name
contact_role_list (pivot)
id
contact_role_id
list_id
Everything was working smoothly until the second pivot table linked to the first pivot table. My pivot tables are (currently) not having any models so I'm not sure if there is a built-in feature to tackle this in Laravel or if I need to think differently.
I currently have this in my List model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(XYZ::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
Is this even close? What do I put where it says XYZ::class?
Ok, so the below is doing what I want, but is there an even better way to do it? The key to solving my problem was to create a Model for ContactRole and changing extends Model to extends Pivot.
I placed this in my List Model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(ContactRole::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
And this in my ContactRole Model:
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
Now I could reach the contact data by using something like this: List::first()->contact_roles->first()->contact
Any way to use with, pivot or similar to tidy this up even more? Thanks!
I like to approach these issues in terms of Models rather than pivots. I think many new Developers in Laravel get over obsessed with what's going on in the Database which is fine, but theres a lot of Magic going on so you can write very simple code that does a lot of Heavy lifting, so that being said if I fully understand your problem
You have a Contacts Model
This model can have many roles
so in your contacts Model you need a role relationship
public function roles()
{
return $this->belongsToMany(Roles::class);
}
next of course you have a role Model (pun intended)
your each role can have many list
public function lists()
{
return $this->hasMany(List::class)
}
then the idea is now that you have roles on contacts and lists on roles you should be able to have many lists through contact
public function lists()
{
return $this->hasManyThrough(List::class, Role::class);
}
I've done similar things before and for your description it seems like that's the approach you might need to take.
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);
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.
I'm trying to create a polymorphic relationship with multiple pivot tables. I have a table of requirements that can be assigned to accounts, roles, trips, and countries. This needs to be a many to many relationship because the same requirement could apply to multiple countries and/or trips and/or accounts etc.
I then need a table listing outstanding requirements for the user. For example: if a user has a certain account and there are requirements related to that account, then those requirements would be added to the user's list of requirements.
One solution I have is to first assign the requirements to the accounts, roles, trips, and countries using Pivot tables in a Many to Many relationship. Then using a polymorphic relationship I would connect the user to whichever pivot tables relate.
But I don't know how to do this or if it is even possible?
Here are my tables:
user_requirements
- id
- user_id
- requireable_id
- requireable_type
account_requirement
- id
- account_id
- requirement_id
role_requirement
- id
- role_id
- requirement_id
trip_requirement
- id
- account_id
- requirement_id
country_requirement
- id
- account_id
- requirement_id
Laravel 4.1 now has support for polymorphic many to many relationships.
Example below shows how I have implemented sharing Photos with both Products and Posts.
DB Schema
photos
id integer
filename string
alt string
photoable
id integer
photoable_id integer
photoable_type string
Models
Photo Model
class Photo extends Eloquent
{
public function products(){
return $this->morphedByMany('Product', 'photoable');
}
public function posts(){
return $this->morphedByMany('Post', 'photoable');
}
}
Product Model
class Product extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
Post Model
class Post extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
With the above, I can access all photos which are attached to a product as follows:
$product = Product::find($id);
$productPhotos = $product->photos()->all();
I can also iterate over to display all photos as any collection of models.
foreach ($productPhotos as $photo)
{
// Do stuff with $photo
}
The above can be replicated almost exactly to your requirements.
create a requirements table
create a requireable table
In Requirement model, declare all morphedByMany relationships
In Country, Trip, Role etc. declare morphToMany relationships
nb - I've typed this out freehand in S/O with no code editor, so there will probably be a typo, error or two - but concept remains the same.
A polymorphic relation in Laravel 4 is intended for single MODEL associations, therefore you cannot achieve what you are trying to build with this method. This is due to the fact that a pivot table doesn't represent a Model.
I can't find anywhere the information on how you have several intermediate tables with your Eloquent ORM models. The problem I'm facing is that I have a table for my users, permissions and roles. These are the 4 tables:
Permissions:
id
name
Permission_roles:
id
name
Permission_role_mappings:
id
permission_id
permission_role_id
Permission_role_user_mappings:
id
permission_role_id
user_id
(Well, I also have a users table but the layout of it doesn't matter since the foreign key is in permission_role_user_mapping.)
So the problem is that I want to be able to get the data from the permissions table when calling from the User model. I have some trouble grasping the workflow with Eloquent ORM altogether so if I'm missing something basic which is crucial then please point it out.
According to the documentation it seems that I don't need to create models for the intermediate tables. So how would I specify the relationship from the User class? Could I do something similar to this?
class User extends Eloquent {
public function permission_role()
{
return $this->has_many_and_belongs_to('Permission_Role', 'permission_role_user_mappings');
}
public function permission()
{
return $this->has_many_and_belongs_to('Permission_Role', 'permission_role_user_mappings')->has_many_and_belongs_to('Permission','permission_role_mappings');
}
}
This doesn't seem to be working, this is the error:
User::find(1)->first()->permission()->first();
...
Method [permission] is not defined on the Query class.
I also want to be able to get data by starting from Permission_Role and Permission. I'd prefer that the answer would help me specifying all the models required.
Eloquent relationships are accessed as an object property instead of a function.
User::find(1)->first()->permission;
You can wrap that above statement in the dd function to get a look at it.
This guide on Eloquent Relationships should be helpful
Edit for question in comments about selecting all permissions in the role:
$roles = array();
$permission_roles = User::find(1)->permission_roles()->get();
foreach ($permission_roles as $pr) {
if (! in_array($pr->permissions)) {
$roles[] = $pr->permissions;
}
}
This will get you what you want. However, this will end up doing a lot of queries. It's best to make use of Eager Loading here.