Let's say you want to associate Players to Teams in your application. After reading the Laravel Documentation, you create this database table structure:
teams
id - integer
name - string
players
id - integer
name - string
team_player
player_id - integer
team_id - integer
You create the corresponding Player
model with a BelongsToMany
relationship to the Team
model
class Player extends Model
{
protected $fillable = ['name'];
public function teams()
{
return $this->belongsToMany(Team::class, 'team_player');
}
}
class Team extends Model
{
protected $fillable = ['name'];
public function players()
{
return $this->belongsToMany(Player::class, 'team_player');
}
}
You then attach Players to a Team by calling $team->attach([$player->id])
, all is good!
Now in Filament, in your TeamResource
, you add a Repeater field to let your site administrators attach Players to Teams:
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name'),
Repeater::make('players')
->relationship()
->schema([
Select::make('player_id')
->label('Player')
->options(Player::pluck('name', 'id')),
]),
]);
}
When you try to add a Player to a Team using the Repeater field and save, you see this error:
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: players.name
INSERT INTO "players" ("updated_at", "created_at") VALUES (2023-07-17 13:55:12, 2023-07-17 13:55:12)
What's happening? Filament is trying to create a new Player record instead of simply attaching the selected Player to the Team.
- Introduce a new
TeamPlayer
model:
class TeamPlayer extends Model
{
protected $table = 'team_player';
protected $fillable = ['team_id', 'player_id'];
}
- Update your
team_player
table schema:
Schema::create('team_player', function (Blueprint $table) {
$table->id();
$table->integer('team_id');
$table->integer('player_id');
$table->timestamps();
});
- Update your Team-Player relationship to
HasMany
instead ofBelongsToMany
:
class Team extends Model
{
protected $fillable = ['name'];
public function teamPlayers()
{
return $this->hasMany(TeamPlayer::class, 'team_id', 'id');
}
}
- Update your Repeater field name:
Repeater::make('teamPlayers')
->relationship()
->schema([
Select::make('player_id')
->label('Player')
->options(Player::pluck('name', 'id')),
]),
The Repeater should now correctly attach Players to Teams as intended:
https://filamentphp.com/tricks/attaching-records-using-the-repeater-field-and-hasmany