Skip to content

Instantly share code, notes, and snippets.

@pboivin
Created July 17, 2023 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pboivin/b770334a5c6c2fdf0a21d1288b21476b to your computer and use it in GitHub Desktop.
Save pboivin/b770334a5c6c2fdf0a21d1288b21476b to your computer and use it in GitHub Desktop.
[FilamentPHP] Attaching records using the Repeater field and HasMany

Attaching records using the Repeater field and HasMany

Context

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!

Problem

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.

Solution

  1. Introduce a new TeamPlayer model:
class TeamPlayer extends Model
{
    protected $table = 'team_player';

    protected $fillable = ['team_id', 'player_id'];
}
  1. 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();
});
  1. Update your Team-Player relationship to HasMany instead of BelongsToMany:
class Team extends Model
{
    protected $fillable = ['name'];

    public function teamPlayers()
    {
        return $this->hasMany(TeamPlayer::class, 'team_id', 'id');
    }
}
  1. 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:

Edit Team Page


https://filamentphp.com/tricks/attaching-records-using-the-repeater-field-and-hasmany

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment