问题
I am having trouble defining the relationships in my Eloquent Models when using a 3 way intermediate pivot table.
Here are the 4 tables in my database:
users
- id
- name
instruments
- id
- key
instruments_users
- id
- user_id
- instrument_id
- level_id
levels
- id
- key
- Instruments keys can be: guitare, piano, trumpet, etc.
- Levels keys can be: beginner, intermediate, expert, etc.
Each user can play of 1 or more instrument. For each played instrument (relationship), we attribute a level with level_id
.
I am trying to get a list of instruments for a given user, with the corresponding level. Here is the JSON returned for a user with 1 instrument:
"instruments":[
{
"id":1,
"key":"guitar",
"pivot":{
"user_id":1,
"instrument_id":1,
"level_id":1
},
"level":[
{
"id":1,
"key":"beginner",
"pivot":{
"instrument_id":1,
"level_id":1
}
}
]
}
]
My issue here is that level
is an array, but I want only one level
attributed to each played instrument
. I believe this is because I used a belongsToMany
relationship, but that was the only way I found to be able to pass through the intermediate table (instruments_users
).
In Laravel I configured my Eloquent Models as follow:
User.php
public function instruments() {
return $this->belongsToMany(
Instrument::class,
'instruments_users'
)->withPivot('level_id');
}
Instrument.php
protected $with = ['level'];
public function users() {
return $this->belongsToMany(
User::class,
'instruments_users'
)->withPivot('level_id');
}
public function level() {
return $this->belongsToMany(
Level::class,
'instruments_users'
);
}
Level.php
public function instruments() {
return $this->belongsToMany(
Instrument::class,
'instruments_users'
);
}
回答1:
I think you are better off defining different kind of relationships:
Tables and models:
users >> Model User
- id
- name
instruments >> Model Instrument
- id
- key
instruments_users >> Model InstrumentUser
- id
- user_id
- instrument_id
- level_id
levels >> Model Level
- id
- key
Model User:
function userInstruments()
{
//One user can have many user_instruments
return $this->hasMany(App\InstrumentUser::class);
}
Model UserInstrument:
function instrument()
{
//One user_instrument belongs to one instrument
return $this->belongsTo(App\Instrument::class);
}
function level()
{
//One user_instrument belongs to one level
return $this->belongsTo(App\Level::class);
}
With this setup, you can get all the data required with a query like this:
$user = User::with(['userInstruments.instrument', 'userInstruments.level'])->find($id);
$users = User::with(['userInstruments.instrument', 'userInstruments.level'])->get();
The output should look something like this:
//User
{
"id": 1,
"name": "Darth",
"user_instruments": [
{
"id": 1,
"instrument_id": 1,
"instrument": {
"id": 1,
"name": "clarinet",
},
"level_id": 1,
"level": {
"id": "1",
"key": "Noob"
},
"user_id": 1
}
]
}
I hope this helps.
来源:https://stackoverflow.com/questions/61125916/laravel-3-way-intermediate-pivot-table