laravel 2 tables have 1:n relationship with the same table - php

I have a users table, a products table, and and an assets table. A user can have many assets, as can a product, meaning both Users, and Products have a 1:n relationship with assets. In Laravel how would show this relationship in Eloquent, is this a Polymorphic relationship, with the struct of the assets table columns being something like,
ID, type, file_path, ownable_id, ownable_type

I think your assets table columns should be
id, type, file_path, assetable_id, assetable_type
Add this relation to your user and product model
public function assets()
{
return $this->morphMany(Asset::class, 'assetable');
}
Next, add this relation to your asset model
public function assetable()
{
return $this->morphTo();
}

relation of user model
public function assets()
{
return $this->morphMany(Asset::class, 'assetable');
}
relation of asset model
public function assetable()
{
return $this->morphTo();
}

Related

Laravel many-to-many with 3 models

I have 3 models: Movie, Celebrity, Role. Each movie has many celebrities and each celebrity has many roles in many movies (for example the movie "Once Upon a Time" has celebrity "Quentin Tarantino" as roles ["Director","Writer"], and obviously "Quentin Tarantino" can have other movies performing different roles.
What is the best way to implement a many-to-many relationship between these 3 models, where we can easily access each movie's staff directly (like $movie->$roles->director)
Should we define a pivot table with movie_id, celebrity_id, role_id and a primary key of (movie_id, celebrity_id, role_id)?
class Movie extends Model{
public function movieCelebrityRole()
{
return $this->hasMany(MovieCelebrityRole::class);
}
}
class Celebrity extends Model{
public function movieCelebrityRole()
{
return $this->hasMany(MovieCelebrityRole::class);
}
}
class Role extends Model{
public function userRoleCompany()
{
return $this->hasMany(MovieCelebrityRole::class);
}
}
class MovieCelebrityRole extends Model{
public function movie()
{
return $this->belongsTo(Movie::class);
}
public function celebrity()
{
return $this->belongsTo(Celebrity::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
}
If you get a pivot table with more than two Foreign Keys, or have multiple many-to-many relationships, try to treat it as full model.
This also helps you to define more simple relationships.
Instead of Many-to-Many relationship. You can divide it into multiple of One-to-Many relationships.
E.g: In your case, you're going to have 4 models : Movie, Celebrity, Role, Program.
Movie hasMany Program.
Celebrity hasMany Program.
Role hasMany Program.
Program belongsTo Movie.
Program belongsTo Celebrity.
Program belongsTo Role.
For more details, check the Laravel documentation about the One-to-Many relationships :
https://laravel.com/docs/8.x/eloquent-relationships#one-to-many

Many to Many Relation with custom pivot table

I have 4 tables in project's database:
users (id, name)
teams (id, name)
team_members (id, user_id, team_id)
team_member_permissions (team_member_id, team_id)
I need to get user's teams. My current solution is to create teamMembers relationship in User model:
public function teamMembers()
{
return $this->hasMany(TeamMember::class);
}
members relationship in Team model:
public function members()
{
return $this->hasMany(TeamMember::class);
}
permissions relationship in TeamMember model:
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
But how can I optimise it? For example, to get all teams for users I need to use
Team::whereHas('teamMember', function($query) use ($user){
$query->where('user_id', $user->id);
})->paginate();
But how can I implement a relationship that will contains all user's teams to get user's teams in one string of code, like $user->teams?
I suggest you use many to many relation in regards to your team_members tables to explicitly mention as pivot.
User model:
public function teams()
{
return $this->belongsToMany(Team::class, 'team_members');
}
Team model:
public function users()
{
return $this->belongsToMany(User::class, 'team_members');
}
Since you want to use whereHas clause on teamMember table, I believe that you want to extract teams based on the fact that all teams belonging to that user based on team_members table.
So, You can specify the table name on many to many relation as above.
Now you can use
$user->teams

How to order by many-to-many relationship Laravel Eloquent

I have many-to-many relationship users|pivot|task
I need to order records by pivot table column(role) and by user table column(name). Ordering by pivot works, but order by users doesnt. Please give any advice how to fix this
Job model
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class,'user_job')
->using(UserJob::class)
->withPivot('role')
->withTimestamps();
}
User Model
public function jobs(): BelongsToMany
{
return $this->belongsToMany(Job::class,'user_job')
->using(UserJob::class)
->withPivot('role')
->withTimestamps();
}
Repository
return User::find($dto->getUserId())
->jobs()
->where($dto->getFilters())
->with('users')
->orderBy($dto->getSortBy(),$dto->getSortType()) // need to order by users.name
->paginate($dto->getPerPage());

Eloquent ORM hasManyTrough

i have a hasManyTrough() relation in my database but could not get it to work with eloquent.
the relation in my database
category(id)
entry(id)
category_entries(category_id, entry_id)
i have 3 models
Category
has_many CategoryEntries
Entry
has_many CategoryEntries
CategoryEntry
belongs_to Category
belongs_to Entry
so every category has many entries and every entry has many categories.
in rails i would do the following
Entry
has_many CategoryEntries
has_many Categories, through: :category_entries
i have created the following in eloquent
CategoryEntry
public function category(){
return $this->belongsTo('App\Category');
}
public function entry(){
return $this->belongsTo('App\Entry');
}
Category
public function categoryEntries(){
return $this->hasMany('App\CategoryEntry');
}
Entry
public function categoryEntries(){
return $this->hasMany('App\CategoryEntry');
}
public function categories()
{
return $this->hasManyThrough('App\Category', 'App\CategoryEntry', 'category_id', 'id');
}
but this will create the following sql command:
select `entries`.*, `category_entries`.`category_id` from `entries`
inner join `category_entries` on `category_entries`.`id` = `entries`.`entry_id`
this makes no sence. where is my mistake?
As described in your question, relation is
Category (hasMany) Entry (hasMany) CategoryEntries
So we can add hasManyThrough relation in Category Model not in Entry model
class Category
.......
public function categoryEntries()
{
$this->hasManyThrough(App\CategoryEntry::class, App\Entry::class);
}
UPDATE
if the relation is based on db you have given, then you have Many-Many relation between Category and Entry. then you can have,
class Entry
....
public function categories()
{
return $this->belongsToMany(App\Category::class, 'category_entries');
}

Laravel Eloquent Relationship custom query

I have 2 tables: USERS and SUBJECTS
The relationship between USER and SUBJECT is many to many.
In the User.php and Subject.php models, I defined:
User.php
function subjects() { return $this->belongsToMany('App\User'); }
Subject.php
function users() { return $this->belongsToMany('App\Subject'); }
The pivot table is subject_user and it has 3 columns:
subject_id, user_id, finished
The finished value can only be between 0 and 1.
Now I know that when I want to select all the subjects that an user studied, I have to write $user->subjects.
But what if I want to select all the subjects that an user studied and the finished value in the pivot table is equal to 1?
You need to add "withPivot()" to your relationship definitions, like this:
function subjects() { return $this->belongsToMany('App\User')->withPivot('finished'); }
function users() { return $this->belongsToMany('App\Subject')->withPivot('finished'); }
Then you can do:
$user->subjects()->where('finished', 1)->get();
You will need to eager load that relationship and use the wherePivot method.
$user = User::with(['subjects' => function($q) {
$q->wherePivot('finished', 1);
}])->fine($user_id);

Categories