Marcelo Silva
Marcelo Silva

Reputation: 21

How to use sync on a 3 model relationship? - Laravel

I have 3 models:

Match Team Player

And i want to create a table with the following structure:

id | match_id | team_id | player_id

So that i can associate the 3 models i refered.

I created a 4th model MatchPlayers for the table i referred and I can use the 'search' functions without a problem. Like this:

$match->matchPlayers()->first()->team()->get() 

And it returns the excpected result, but I cant do a

$match->matchPlayers()->sync([])

So, how should i solve this? Is my relationship wrong or the sync method isnt allowed on a 3 model relationship and I shoud use other method?

Thanks in advance


Edit:

Match.php

public function teamPlayers(){
    return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}

Team.php

public function matchTeamPlayers(){
    return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}

Player.php

public function matchTeamPlayers(){
    return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}

MatchPlayer.php

public function player(){
    return $this->belongsTo('\Modules\Players\Entities\Player');
}

public function match(){
    return $this->belongsTo('\Modules\Matchs\Entities\Match');
}

public function team(){
    return $this->belongsTo('\Modules\Teams\Entities\Team');
}

Upvotes: 1

Views: 1226

Answers (2)

Namoshek
Namoshek

Reputation: 6544

Using a fourth model for this kind of relationship makes sense, as it gives you a navigation property for the third relation on your pivot table. This way you can form more complex queries this way.

For your particular problem, syncing based on match_id and team_id, I would simply do something like this:

$matchId = 123;
$teamId = 234;
$rows = [
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];

// remove all previously stored connections
MatchPlayer::where('match_id', $matchId)
    ->where('team_id', $teamId)
    ->delete();

// insert the news ones
// (you could also use MatchPlayer::create() per item or 
// $matchPlayer->save(), it doesn't matter)
MatchPlayer::insert($rows);

If this operation occurs very frequently, you will potentially burn through a lot of id values of the pivot table. In this case you could also perform a more efficient sync, which is slightly more complex:

$matchId = 123;
$teamId = 234;
$rows = [
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
    ['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];

// delete all players that are not among the new data anymore
MatchPlayer::where('match_id', $matchId)
    ->where('team_id', $teamId)
    ->whereNotIn('player_id', array_pluck($rows, 'player_id'))
    ->delete();

// remove rows from new data that already exist
$exist = MatchPlayer::where('match_id', $matchId)
    ->where('team_id', $teamId)
    ->pluck('player_id')
    ->toArray();
$rows = array_filter($rows, function ($value, $key) use ($exist) {
    return ! in_array($value['player_id'], $exist);
});

// then we store the remaining data
MatchPlayer::insert($rows);

Upvotes: 0

Someone
Someone

Reputation: 3568

If you've followed the Laravel documentation on Pivot tables and Many-Many relationships found here, and it's still not working, you might have more luck with "Attach". For example;

$matchPlayer = MatchPlayer::create([...]);

$match->matchPlayers()->attach($matchPlayer)

A good example of sync vs attach can be found here

Upvotes: 1

Related Questions