F
Filament16mo ago
Dex

Updating rows of a belongsToMany relationship

Is there a possibility to update the rows of the pivot table instead of deleting the row. For example I have 2 Table: Table1 ( group ) ID NAME CHALLENGE_ID Table2 (group_users -> pivot) ID GROUP_ID USER_ID IS_GROUP
public function users(): BelongsToMany
{
return $this->belongsToMany(TenantUser::class, 'group_users', 'group_id', 'user_id')->withTimestamps();
}
public function users(): BelongsToMany
{
return $this->belongsToMany(TenantUser::class, 'group_users', 'group_id', 'user_id')->withTimestamps();
}
When I do it as follow:
protected function getFormSchema(): array
{
return [
TextInput::make('name')
->label('Name')
->required()
->autofocus()
->unique('groups', fn(): string => !isset($this->group) ? 'name' : 'id'),
Select::make('challenge_id')
->label('Challenge')
->hint('Optional')
->searchable()
->options(function (): Collection {
return Challenge::where('type', 'group')
->whereIn('id', tenant()->get_challenges()->pluck('id'))
->pluck('title', 'id');;
}),
Select::make('users')
->label('Users')
->multiple()
->searchable()
->relationship('users', 'full_name')
->preload(),
];
}
public function submit()
{
$state = $this->form->getState();
if ($this->group) {
$this->group->update($state);
} else {
$this->group = TenantGroup::create($state);
$this->form->model($this->group)->saveRelationships();
}
}
protected function getFormSchema(): array
{
return [
TextInput::make('name')
->label('Name')
->required()
->autofocus()
->unique('groups', fn(): string => !isset($this->group) ? 'name' : 'id'),
Select::make('challenge_id')
->label('Challenge')
->hint('Optional')
->searchable()
->options(function (): Collection {
return Challenge::where('type', 'group')
->whereIn('id', tenant()->get_challenges()->pluck('id'))
->pluck('title', 'id');;
}),
Select::make('users')
->label('Users')
->multiple()
->searchable()
->relationship('users', 'full_name')
->preload(),
];
}
public function submit()
{
$state = $this->form->getState();
if ($this->group) {
$this->group->update($state);
} else {
$this->group = TenantGroup::create($state);
$this->form->model($this->group)->saveRelationships();
}
}
The record will be deleted from the pivot when I remove a user, instead I would like to update the updated_at for example.
15 Replies
Patrick Boivin
Patrick Boivin16mo ago
I'm not sure the Select is the right field for this... can you describe your use-case a bit more?
Dex
DexOP16mo ago
A group can have one or multiple users, a user can be in one or more than one group and I would like to keep track of the updates like if a user isn't in a group anymore I want to know the date of exclusion as also the date the user entered the group @Patrick Boivin
Patrick Boivin
Patrick Boivin16mo ago
Ok, makes sense. I'm not sure but maybe you could introduce a pivot model instead and implement soft deletes on it? That way you could keep track of the created_at for entering the group and deleted_at for leaving the group.
Dex
DexOP16mo ago
Can you provide some example?
Patrick Boivin
Patrick Boivin16mo ago
I don't have one unfortunately Oh wait... maybe I do
Patrick Boivin
Patrick Boivin16mo ago
So this is a different context with the Repeater field but it can at least show you what I mean by "pivot model": https://gist.github.com/pboivin/b770334a5c6c2fdf0a21d1288b21476b
Gist
[FilamentPHP] Attaching records using the Repeater field and HasMany
[FilamentPHP] Attaching records using the Repeater field and HasMany - README.md
Dex
DexOP16mo ago
unfortunatelly none of both examples helped as far. I cant prevent deleting records from the pivot table when the relationship changes.
Patrick Boivin
Patrick Boivin16mo ago
Are you implementing soft deletes on the pivot model?
Dex
DexOP16mo ago
$this->saveRelationshipsUsing(static function (Select $component, Model $record, $state) {
if ($component->isMultiple()) {
$component->getRelationship()->sync($state ?? []);

return;
}

$component->getRelationship()->associate($state);
$record->save();
});
$this->saveRelationshipsUsing(static function (Select $component, Model $record, $state) {
if ($component->isMultiple()) {
$component->getRelationship()->sync($state ?? []);

return;
}

$component->getRelationship()->associate($state);
$record->save();
});
just found out that filament uses the sync method which will delete all records which aren't in the array so one of the possibilities would be to patch that somehow and use syncWithoutDettach() instead of sync() bump bump
Patrick Boivin
Patrick Boivin16mo ago
@Dex
so one of the possibilities would be to patch that somehow and use syncWithoutDettach() instead of sync()
Have you been exploring this? What have you been trying recently?
Dex
DexOP16mo ago
Yes it works as far but it is not a good option because it will work globally and I have no idea how to override filament functions
Patrick Boivin
Patrick Boivin16mo ago
You can call saveRelationshipsUsing() directly on the one Select you want to change Replace the logic just for one field, if that makes sense
Dex
DexOP16mo ago
can you give me an example on that?
Patrick Boivin
Patrick Boivin16mo ago
I'm referencing your code snippet above 👆 You can customize it for a particular Select field like this:
Forms\Components\Select::make('my_field')
// ...
->saveRelationshipsUsing(static function (Select $component, Model $record, $state) {
// customize here
}),
Forms\Components\Select::make('my_field')
// ...
->saveRelationshipsUsing(static function (Select $component, Model $record, $state) {
// customize here
}),
Want results from more Discord servers?
Add your server