Skip to content

Commit 429fc0c

Browse files
committed
Merge branch '4.x' of https://github.com/filamentphp/filament into fix/chart-border-and-radar-regression
2 parents 970150f + a09c635 commit 429fc0c

11 files changed

Lines changed: 282 additions & 0 deletions

File tree

packages/forms/src/Components/CheckboxList.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ public function fillStateFromRelationship(): void
284284
public function saveStateToRelationship(): void
285285
{
286286
$relationship = $this->getRelationship();
287+
$record = $this->getRecord();
288+
$relationshipName = $this->getRelationshipName();
287289

288290
if ($this->modifyRelationshipQueryUsing) {
289291
$this->evaluate($this->modifyRelationshipQueryUsing, [
@@ -312,11 +314,13 @@ public function saveStateToRelationship(): void
312314

313315
if ($pivotData === []) {
314316
$relationship->sync($state, detaching: false);
317+
$record->unsetRelation($relationshipName);
315318

316319
return;
317320
}
318321

319322
$relationship->syncWithPivotValues($state, $pivotData, detaching: false);
323+
$record->unsetRelation($relationshipName);
320324
}
321325

322326
public function bulkToggleable(bool | Closure $condition = true): static

packages/forms/src/Components/ModalTableSelect.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ public function saveStateToRelationship(): void
580580
{
581581
$relationship = $this->getRelationship();
582582
$record = $this->getRecord();
583+
$relationshipName = $this->getRelationshipName();
583584
$state = $this->getState();
584585

585586
if (($relationship instanceof HasOne) || ($relationship instanceof HasMany)) {
@@ -615,6 +616,8 @@ public function saveStateToRelationship(): void
615616
});
616617
}
617618

619+
$record->unsetRelation($relationshipName);
620+
618621
return;
619622
}
620623

@@ -671,11 +674,13 @@ public function saveStateToRelationship(): void
671674

672675
if ($pivotData === []) {
673676
$relationship->sync($state, detaching: false);
677+
$record->unsetRelation($relationshipName);
674678

675679
return;
676680
}
677681

678682
$relationship->syncWithPivotValues($state, $pivotData, detaching: false);
683+
$record->unsetRelation($relationshipName);
679684
}
680685

681686
public function getOptionLabelFromRecordUsing(?Closure $callback): static

packages/forms/src/Components/Select.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,7 @@ public function saveStateToRelationship(): void
13251325
{
13261326
$relationship = $this->getRelationship();
13271327
$record = $this->getRecord();
1328+
$relationshipName = $this->getRelationshipName();
13281329
$state = $this->getState();
13291330

13301331
if (($relationship instanceof HasOne) || ($relationship instanceof HasMany)) {
@@ -1360,6 +1361,8 @@ public function saveStateToRelationship(): void
13601361
});
13611362
}
13621363

1364+
$record->unsetRelation($relationshipName);
1365+
13631366
return;
13641367
}
13651368

@@ -1416,11 +1419,13 @@ public function saveStateToRelationship(): void
14161419

14171420
if ($pivotData === []) {
14181421
$relationship->sync($state, detaching: false);
1422+
$record->unsetRelation($relationshipName);
14191423

14201424
return;
14211425
}
14221426

14231427
$relationship->syncWithPivotValues($state, $pivotData, detaching: false);
1428+
$record->unsetRelation($relationshipName);
14241429
}
14251430

14261431
/**

packages/forms/src/Components/TableSelect.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ public function saveStateToRelationship(): void
244244
{
245245
$relationship = $this->getRelationship();
246246
$record = $this->getRecord();
247+
$relationshipName = $this->getRelationshipName();
247248
$state = $this->getState();
248249

249250
if (($relationship instanceof HasOne) || ($relationship instanceof HasMany)) {
@@ -265,6 +266,8 @@ public function saveStateToRelationship(): void
265266
});
266267
}
267268

269+
$record->unsetRelation($relationshipName);
270+
268271
return;
269272
}
270273

@@ -314,11 +317,13 @@ public function saveStateToRelationship(): void
314317

315318
if ($pivotData === []) {
316319
$relationship->sync($state, detaching: false);
320+
$record->unsetRelation($relationshipName);
317321

318322
return;
319323
}
320324

321325
$relationship->syncWithPivotValues($state, $pivotData, detaching: false);
326+
$record->unsetRelation($relationshipName);
322327
}
323328

324329
public function relationshipName(string | Closure | null $name): static

packages/spatie-laravel-tags-plugin/src/Forms/Components/SpatieTagsInput.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ protected function setUp(): void
4545
(! $component->isAnyTagTypeAllowed())
4646
) {
4747
$record->syncTagsWithType($state, $type);
48+
$record->unsetRelation('tags');
4849

4950
return;
5051
}
5152

5253
$component->syncTagsWithAnyType($record, $state);
54+
$record->unsetRelation('tags');
5355
});
5456

5557
$this->dehydrated(false);

tests/src/Fixtures/Livewire/SpatieTagsInputForm.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public function save(): void
4949
$this->form->saveRelationships();
5050
}
5151

52+
public function saveOnly(): void
53+
{
54+
$this->record->load('tags');
55+
$this->form->saveRelationships();
56+
}
57+
5258
public function render(): View
5359
{
5460
return view('livewire.form');

tests/src/Forms/Components/CheckboxListTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,48 @@ public function render(): View
443443
}
444444
}
445445

446+
class CheckboxListWithEagerLoadedBelongsToManyRelationship extends Component implements HasActions, HasSchemas
447+
{
448+
use InteractsWithActions;
449+
use InteractsWithSchemas;
450+
451+
public $data = [];
452+
453+
public User $record;
454+
455+
public function mount(): void
456+
{
457+
$this->record->load('teams');
458+
$this->form->fill([]);
459+
}
460+
461+
public function hydrate(): void
462+
{
463+
$this->record->load('teams');
464+
}
465+
466+
public function form(Schema $form): Schema
467+
{
468+
return $form
469+
->schema([
470+
CheckboxList::make('teams')
471+
->relationship('teams', 'name'),
472+
])
473+
->model($this->record)
474+
->statePath('data');
475+
}
476+
477+
public function save(): void
478+
{
479+
$this->form->getState();
480+
}
481+
482+
public function render(): View
483+
{
484+
return view('livewire.form');
485+
}
486+
}
487+
446488
class CheckboxListWithBelongsToManyRelationshipAndModifyQuery extends Component implements HasActions, HasSchemas
447489
{
448490
use InteractsWithActions;
@@ -1110,6 +1152,23 @@ public function render(): View
11101152
expect($user->fresh()->teams)->toHaveCount(3);
11111153
expect($modifyCallCount)->toBeGreaterThan(0);
11121154
});
1155+
1156+
it('invalidates the cached `BelongsToMany` relationship after save so a subsequent reload does not re-attach detached rows', function (): void {
1157+
$user = User::factory()->create();
1158+
$teams = Team::factory()->count(2)->create();
1159+
$user->teams()->attach($teams);
1160+
1161+
$component = livewire(CheckboxListWithEagerLoadedBelongsToManyRelationship::class, ['record' => $user])
1162+
->fillForm(['teams' => []])
1163+
->call('save');
1164+
1165+
expect($user->fresh()->teams)->toHaveCount(0)
1166+
->and($component->instance()->data['teams'])->toBe([]);
1167+
1168+
$component->call('save');
1169+
1170+
expect($user->fresh()->teams)->toHaveCount(0);
1171+
});
11131172
});
11141173

11151174
describe('loading relationships', function (): void {

tests/src/Forms/Components/ModalTableSelectTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,50 @@ public function render(): View
273273
}
274274
}
275275

276+
class ModalTableSelectWithEagerLoadedBelongsToManyRelationship extends Component implements HasActions, HasSchemas
277+
{
278+
use InteractsWithActions;
279+
use InteractsWithSchemas;
280+
281+
public $data = [];
282+
283+
public User $record;
284+
285+
public function mount(): void
286+
{
287+
$this->record->load('teams');
288+
$this->form->fill([]);
289+
}
290+
291+
public function hydrate(): void
292+
{
293+
$this->record->load('teams');
294+
}
295+
296+
public function form(Schema $form): Schema
297+
{
298+
return $form
299+
->schema([
300+
ModalTableSelect::make('teams')
301+
->relationship('teams', 'name')
302+
->tableConfiguration(TeamsTable::class)
303+
->multiple(),
304+
])
305+
->model($this->record)
306+
->statePath('data');
307+
}
308+
309+
public function save(): void
310+
{
311+
$this->form->getState();
312+
}
313+
314+
public function render(): View
315+
{
316+
return view('livewire.form');
317+
}
318+
}
319+
276320
class ModalTableSelectWithBelongsToManyRelationshipAndModifyQuery extends Component implements HasActions, HasSchemas
277321
{
278322
use InteractsWithActions;
@@ -814,6 +858,23 @@ public function render(): View
814858
expect($pivotRows->first()->role)->toBe('viewer');
815859
expect($pivotRows->last()->role)->toBe('viewer');
816860
});
861+
862+
it('invalidates the cached `BelongsToMany` relationship after save so a subsequent reload does not re-attach detached rows', function (): void {
863+
$user = User::factory()->create();
864+
$teams = Team::factory()->count(2)->create();
865+
$user->teams()->attach($teams);
866+
867+
$component = livewire(ModalTableSelectWithEagerLoadedBelongsToManyRelationship::class, ['record' => $user])
868+
->fillForm(['teams' => []])
869+
->call('save');
870+
871+
expect($user->fresh()->teams)->toHaveCount(0)
872+
->and($component->instance()->data['teams'])->toBe([]);
873+
874+
$component->call('save');
875+
876+
expect($user->fresh()->teams)->toHaveCount(0);
877+
});
817878
});
818879

819880
describe('saving BelongsTo relationships', function (): void {

tests/src/Forms/Components/SelectTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@
225225
expect($user->teams->pluck('id')->sort()->values()->all())->toBe($teams->take(2)->pluck('id')->sort()->values()->all());
226226
});
227227

228+
it('invalidates the cached `BelongsToMany` relationship after save so a subsequent reload does not re-attach detached rows', function (): void {
229+
$user = User::factory()->create();
230+
$teams = Team::factory()->count(2)->create();
231+
$user->teams()->attach($teams);
232+
233+
$component = livewire(TestComponentWithEagerLoadedBelongsToManyMultipleSelect::class, ['record' => $user])
234+
->fillForm(['teams' => []])
235+
->call('save');
236+
237+
expect($user->fresh()->teams)->toHaveCount(0)
238+
->and($component->instance()->data['teams'])->toBe([]);
239+
240+
$component->call('save');
241+
242+
expect($user->fresh()->teams)->toHaveCount(0);
243+
});
244+
228245
it('can use `BelongsToMany` relationship as single select', function (): void {
229246
$user = User::factory()->create();
230247
$teams = Team::factory()->count(3)->create();
@@ -1034,6 +1051,50 @@ public function render(): View
10341051
}
10351052
}
10361053

1054+
class TestComponentWithEagerLoadedBelongsToManyMultipleSelect extends Component implements HasActions, HasSchemas
1055+
{
1056+
use InteractsWithActions;
1057+
use InteractsWithSchemas;
1058+
1059+
public $data = [];
1060+
1061+
public User $record;
1062+
1063+
public function mount(): void
1064+
{
1065+
$this->record->load('teams');
1066+
$this->form->fill($this->record->attributesToArray());
1067+
}
1068+
1069+
public function hydrate(): void
1070+
{
1071+
$this->record->load('teams');
1072+
}
1073+
1074+
public function form(Schema $form): Schema
1075+
{
1076+
return $form
1077+
->schema([
1078+
Select::make('teams')
1079+
->relationship('teams', 'name')
1080+
->multiple()
1081+
->preload(),
1082+
])
1083+
->model($this->record)
1084+
->statePath('data');
1085+
}
1086+
1087+
public function save(): void
1088+
{
1089+
$this->form->getState();
1090+
}
1091+
1092+
public function render(): View
1093+
{
1094+
return view('livewire.form');
1095+
}
1096+
}
1097+
10371098
class SelectWithBelongsToManyRelationship extends Component implements HasActions, HasSchemas
10381099
{
10391100
use InteractsWithActions;

0 commit comments

Comments
 (0)