From e7cc85a2db9ab3ae9201fc6775bcb7132d11c646 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 12 Sep 2024 18:28:02 +0100 Subject: [PATCH 1/9] Throw exception if relationship not found --- packages/forms/src/Components/Select.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/forms/src/Components/Select.php b/packages/forms/src/Components/Select.php index 2553c627ebb..f5cd0ca8548 100644 --- a/packages/forms/src/Components/Select.php +++ b/packages/forms/src/Components/Select.php @@ -1159,7 +1159,7 @@ public function getLabel(): string | Htmlable | null public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | HasManyThrough | BelongsToThrough | null { - if (blank($this->getRelationshipName())) { + if (! $this->hasRelationship()) { return null; } @@ -1167,7 +1167,9 @@ public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | Ha $relationship = null; - foreach (explode('.', $this->getRelationshipName()) as $nestedRelationshipName) { + $relationshipName = $this->getRelationshipName(); + + foreach (explode('.', $relationshipName) as $nestedRelationshipName) { if (! $record->isRelation($nestedRelationshipName)) { $relationship = null; @@ -1178,6 +1180,10 @@ public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | Ha $record = $relationship->getRelated(); } + if (! $relationship) { + throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$this->getModel()}]."); + } + return $relationship; } From bc1bb31ea55e777c35b233a665573120835cb2f9 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 12 Sep 2024 18:47:38 +0100 Subject: [PATCH 2/9] Update HasRelationship.php --- .../tables/src/Filters/Concerns/HasRelationship.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/tables/src/Filters/Concerns/HasRelationship.php b/packages/tables/src/Filters/Concerns/HasRelationship.php index b37d534ecec..f8211c7fb7b 100644 --- a/packages/tables/src/Filters/Concerns/HasRelationship.php +++ b/packages/tables/src/Filters/Concerns/HasRelationship.php @@ -2,6 +2,7 @@ namespace Filament\Tables\Filters\Concerns; +use Exception; use Closure; use Filament\Support\Services\RelationshipJoiner; use Illuminate\Database\Eloquent\Builder; @@ -49,11 +50,15 @@ public function queriesRelationships(): bool public function getRelationship(): Relation | Builder { - $record = app($this->getTable()->getModel()); + $model = $this->getTable()->getModel(); + + $record = app($model); $relationship = null; - foreach (explode('.', $this->getRelationshipName()) as $nestedRelationshipName) { + $relationshipName = $this->getRelationshipName(); + + foreach (explode('.', $relationshipName) as $nestedRelationshipName) { if (! $record->isRelation($nestedRelationshipName)) { $relationship = null; @@ -64,6 +69,10 @@ public function getRelationship(): Relation | Builder $record = $relationship->getRelated(); } + if (! $relationship) { + throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$model}]."); + } + return $relationship; } From ceec3525922f51c956b888432a69e71f846369a3 Mon Sep 17 00:00:00 2001 From: howdu Date: Thu, 12 Sep 2024 17:58:55 +0000 Subject: [PATCH 3/9] chore: fix code style --- packages/tables/src/Filters/Concerns/HasRelationship.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tables/src/Filters/Concerns/HasRelationship.php b/packages/tables/src/Filters/Concerns/HasRelationship.php index f8211c7fb7b..96e9bfc7f8d 100644 --- a/packages/tables/src/Filters/Concerns/HasRelationship.php +++ b/packages/tables/src/Filters/Concerns/HasRelationship.php @@ -2,8 +2,8 @@ namespace Filament\Tables\Filters\Concerns; -use Exception; use Closure; +use Exception; use Filament\Support\Services\RelationshipJoiner; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; From c4ad0c1073c74aa21ca9f8b87b7136b829373c23 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 24 Sep 2024 18:51:26 +0100 Subject: [PATCH 4/9] Throw exception if relationship not found --- packages/tables/src/Grouping/Group.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/tables/src/Grouping/Group.php b/packages/tables/src/Grouping/Group.php index 42414ef3634..628c0b577b2 100644 --- a/packages/tables/src/Grouping/Group.php +++ b/packages/tables/src/Grouping/Group.php @@ -6,6 +6,7 @@ use Carbon\Carbon; use Carbon\CarbonInterface; use Closure; +use Exception; use Filament\Support\Components\Component; use Filament\Support\Contracts\HasLabel as LabelInterface; use Filament\Tables\Table; @@ -412,9 +413,11 @@ public function getRelationship(Model $record, ?string $name = null): ?Relation return null; } + $relationshipName = $name ?? $this->getRelationshipName(); + $relationship = null; - foreach (explode('.', $name ?? $this->getRelationshipName()) as $nestedRelationshipName) { + foreach (explode('.', $relationshipName) as $nestedRelationshipName) { if (! $record->isRelation($nestedRelationshipName)) { $relationship = null; @@ -425,6 +428,10 @@ public function getRelationship(Model $record, ?string $name = null): ?Relation $record = $relationship->getRelated(); } + if (! $relationship) { + throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$record}]."); + } + return $relationship; } From ec4eac462723bad5c1fb536ad3969ca76f9192a2 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 24 Sep 2024 19:00:23 +0100 Subject: [PATCH 5/9] Revert "Throw exception if relationship not found" This reverts commit 903c8cf7e5c2e781fb5a9bf5951a4c64c10ab945. --- packages/tables/src/Grouping/Group.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/tables/src/Grouping/Group.php b/packages/tables/src/Grouping/Group.php index 628c0b577b2..42414ef3634 100644 --- a/packages/tables/src/Grouping/Group.php +++ b/packages/tables/src/Grouping/Group.php @@ -6,7 +6,6 @@ use Carbon\Carbon; use Carbon\CarbonInterface; use Closure; -use Exception; use Filament\Support\Components\Component; use Filament\Support\Contracts\HasLabel as LabelInterface; use Filament\Tables\Table; @@ -413,11 +412,9 @@ public function getRelationship(Model $record, ?string $name = null): ?Relation return null; } - $relationshipName = $name ?? $this->getRelationshipName(); - $relationship = null; - foreach (explode('.', $relationshipName) as $nestedRelationshipName) { + foreach (explode('.', $name ?? $this->getRelationshipName()) as $nestedRelationshipName) { if (! $record->isRelation($nestedRelationshipName)) { $relationship = null; @@ -428,10 +425,6 @@ public function getRelationship(Model $record, ?string $name = null): ?Relation $record = $relationship->getRelated(); } - if (! $relationship) { - throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$record}]."); - } - return $relationship; } From 55407eb608c5c70a276b5a6b5ca62c703c09c8a6 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 9 Dec 2024 18:23:28 +0000 Subject: [PATCH 6/9] Check if relation exists --- packages/forms/src/Components/CheckboxList.php | 9 ++++++++- packages/forms/src/Components/MorphToSelect.php | 10 +++++++++- packages/forms/src/Components/Repeater.php | 11 ++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/forms/src/Components/CheckboxList.php b/packages/forms/src/Components/CheckboxList.php index 9a801363aaf..f86cf5415e9 100644 --- a/packages/forms/src/Components/CheckboxList.php +++ b/packages/forms/src/Components/CheckboxList.php @@ -3,6 +3,7 @@ namespace Filament\Forms\Components; use Closure; +use Exception; use Filament\Actions\Action; use Filament\Schemas\Components\StateCasts\Contracts\StateCast; use Filament\Schemas\Components\StateCasts\EnumArrayStateCast; @@ -296,7 +297,13 @@ public function getRelationship(): ?BelongsToMany return null; } - return $this->getModelInstance()->{$name}(); + $record = $this->getModelInstance(); + + if (! $record->isRelation($name)) { + throw new Exception("The relationship [{$name}] does not exist on the model [{$this->getModel()}]."); + } + + return $record->{$name}(); } public function getRelationshipName(): ?string diff --git a/packages/forms/src/Components/MorphToSelect.php b/packages/forms/src/Components/MorphToSelect.php index 8536d8e0c99..be192a0898a 100644 --- a/packages/forms/src/Components/MorphToSelect.php +++ b/packages/forms/src/Components/MorphToSelect.php @@ -145,7 +145,15 @@ public function types(array | Closure $types): static public function getRelationship(): MorphTo { - return $this->getModelInstance()->{$this->getName()}(); + $record = $this->getModelInstance(); + + $relationshipName = $this->getName(); + + if (! $record->isRelation($relationshipName)) { + throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$this->getModel()}]."); + } + + return $record->{$relationshipName}(); } /** diff --git a/packages/forms/src/Components/Repeater.php b/packages/forms/src/Components/Repeater.php index aa7b66dfb24..14103c4ca22 100644 --- a/packages/forms/src/Components/Repeater.php +++ b/packages/forms/src/Components/Repeater.php @@ -3,6 +3,7 @@ namespace Filament\Forms\Components; use Closure; +use Exception; use Filament\Actions\Action; use Filament\Forms\Contracts\HasForms; use Filament\Schemas\Components\Concerns\CanBeCollapsed; @@ -1086,7 +1087,15 @@ public function getRelationship(): HasOneOrMany | BelongsToMany | null return null; } - return $this->getModelInstance()->{$this->getRelationshipName()}(); + $record = $this->getModelInstance(); + + $relationshipName = $this->getRelationshipName(); + + if (! $record->isRelation($relationshipName)) { + throw new Exception("The relationship [{$relationshipName}] does not exist on the model [{$this->getModel()}]."); + } + + return $this->getModelInstance()->{$relationshipName}(); } public function getRelationshipName(): ?string From 62c03244441702fd6fd7dbd01c7b3a42c76ff134 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 9 Dec 2024 18:24:02 +0000 Subject: [PATCH 7/9] Add tests for repeater relationship --- tests/src/Forms/Components/RepeaterTest.php | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/src/Forms/Components/RepeaterTest.php b/tests/src/Forms/Components/RepeaterTest.php index 7dc61a481ff..487a05e403c 100644 --- a/tests/src/Forms/Components/RepeaterTest.php +++ b/tests/src/Forms/Components/RepeaterTest.php @@ -4,6 +4,8 @@ use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Filament\Tests\Forms\Fixtures\Livewire; +use Filament\Tests\Models\Post; +use Filament\Tests\Models\User; use Filament\Tests\TestCase; use Illuminate\Support\Arr; use Illuminate\Support\Str; @@ -144,6 +146,40 @@ $undoRepeaterFake(); }); +it('loads relationship', function () { + $user = User::factory() + ->has(Post::factory()->count(3)) + ->create(); + + $componentContainer = Schema::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Repeater('repeater')) + ->relationship('posts'), + ]) + ->model($user); + + $componentContainer->loadStateFromRelationships(); + + $componentContainer->saveRelationships(); + + expect($user->posts()->count()) + ->toBe(3); +}); + +it('throw exception for missing relationship', function () { + $componentContainer = Schema::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Repeater(Str::random())) + ->relationship('missing'), + ]) + ->model(Post::factory()->create()); + + $componentContainer + ->saveRelationships(); +})->throws(Exception::class, 'The relationship [missing] does not exist on the model [Filament\Tests\Models\Post].'); + class TestComponentWithRepeater extends Livewire { public function form(Schema $form): Schema From d03530007ef2673a18b0f71751ee8c39a990d38b Mon Sep 17 00:00:00 2001 From: howdu Date: Wed, 18 Dec 2024 07:05:28 +0000 Subject: [PATCH 8/9] chore: fix code style --- packages/forms/src/Components/Repeater.php | 3 ++- packages/tables/src/Columns/Column.php | 3 ++- .../PostCategories/PostCategoryResource.php | 12 ++++++++---- tests/src/Fixtures/Resources/Posts/PostResource.php | 12 ++++++++---- .../Resources/Shop/Products/ProductResource.php | 12 ++++++++---- tests/src/Fixtures/Resources/Users/UserResource.php | 12 ++++++++---- 6 files changed, 36 insertions(+), 18 deletions(-) diff --git a/packages/forms/src/Components/Repeater.php b/packages/forms/src/Components/Repeater.php index 14103c4ca22..79834c3cb11 100644 --- a/packages/forms/src/Components/Repeater.php +++ b/packages/forms/src/Components/Repeater.php @@ -7,6 +7,7 @@ use Filament\Actions\Action; use Filament\Forms\Contracts\HasForms; use Filament\Schemas\Components\Concerns\CanBeCollapsed; +use Filament\Schemas\Components\Concerns\HasContainerGridLayout; use Filament\Schemas\Components\Contracts\CanConcealComponents; use Filament\Schemas\Components\Contracts\HasExtraItemActions; use Filament\Schemas\Schema; @@ -31,7 +32,7 @@ class Repeater extends Field implements CanConcealComponents, HasExtraItemAction use Concerns\CanGenerateUuids; use Concerns\CanLimitItemsLength; use Concerns\HasExtraItemActions; - use \Filament\Schemas\Components\Concerns\HasContainerGridLayout; + use HasContainerGridLayout; use HasReorderAnimationDuration; protected string | Closure | null $addActionLabel = null; diff --git a/packages/tables/src/Columns/Column.php b/packages/tables/src/Columns/Column.php index fecda6cea9e..9c92a4ff89a 100644 --- a/packages/tables/src/Columns/Column.php +++ b/packages/tables/src/Columns/Column.php @@ -7,6 +7,7 @@ use Filament\Support\Components\ViewComponent; use Filament\Support\Concerns\CanAggregateRelatedModels; use Filament\Support\Concerns\CanGrow; +use Filament\Support\Concerns\CanSpanColumns; use Filament\Support\Concerns\HasAlignment; use Filament\Support\Concerns\HasCellState; use Filament\Support\Concerns\HasExtraAttributes; @@ -25,6 +26,7 @@ class Column extends ViewComponent { use CanAggregateRelatedModels; use CanGrow; + use CanSpanColumns; use Concerns\BelongsToGroup; use Concerns\BelongsToLayout; use Concerns\BelongsToTable; @@ -46,7 +48,6 @@ class Column extends ViewComponent use Concerns\HasRowLoopObject; use Concerns\HasWidth; use Concerns\InteractsWithTableQuery; - use \Filament\Support\Concerns\CanSpanColumns; use HasAlignment; use HasCellState; use HasExtraAttributes; diff --git a/tests/src/Fixtures/Resources/PostCategories/PostCategoryResource.php b/tests/src/Fixtures/Resources/PostCategories/PostCategoryResource.php index 88d39bec24f..150b4eeeaa1 100644 --- a/tests/src/Fixtures/Resources/PostCategories/PostCategoryResource.php +++ b/tests/src/Fixtures/Resources/PostCategories/PostCategoryResource.php @@ -4,6 +4,10 @@ use Filament\Resources\Resource; use Filament\Tests\Fixtures\Models\PostCategory; +use Filament\Tests\Fixtures\Resources\PostCategories\Pages\CreatePostCategory; +use Filament\Tests\Fixtures\Resources\PostCategories\Pages\EditPostCategory; +use Filament\Tests\Fixtures\Resources\PostCategories\Pages\ListPostCategories; +use Filament\Tests\Fixtures\Resources\PostCategories\Pages\ViewPostCategory; class PostCategoryResource extends Resource { @@ -16,10 +20,10 @@ class PostCategoryResource extends Resource public static function getPages(): array { return [ - 'index' => \Filament\Tests\Fixtures\Resources\PostCategories\Pages\ListPostCategories::route('/'), - 'create' => \Filament\Tests\Fixtures\Resources\PostCategories\Pages\CreatePostCategory::route('/create'), - 'view' => \Filament\Tests\Fixtures\Resources\PostCategories\Pages\ViewPostCategory::route('/{record}'), - 'edit' => \Filament\Tests\Fixtures\Resources\PostCategories\Pages\EditPostCategory::route('/{record}/edit'), + 'index' => ListPostCategories::route('/'), + 'create' => CreatePostCategory::route('/create'), + 'view' => ViewPostCategory::route('/{record}'), + 'edit' => EditPostCategory::route('/{record}/edit'), ]; } } diff --git a/tests/src/Fixtures/Resources/Posts/PostResource.php b/tests/src/Fixtures/Resources/Posts/PostResource.php index 3eefae937cf..0205179d3ca 100644 --- a/tests/src/Fixtures/Resources/Posts/PostResource.php +++ b/tests/src/Fixtures/Resources/Posts/PostResource.php @@ -12,6 +12,10 @@ use Filament\Tables; use Filament\Tables\Table; use Filament\Tests\Fixtures\Models\Post; +use Filament\Tests\Fixtures\Resources\Posts\Pages\CreatePost; +use Filament\Tests\Fixtures\Resources\Posts\Pages\EditPost; +use Filament\Tests\Fixtures\Resources\Posts\Pages\ListPosts; +use Filament\Tests\Fixtures\Resources\Posts\Pages\ViewPost; use Illuminate\Database\Eloquent\Builder; class PostResource extends Resource @@ -70,10 +74,10 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => \Filament\Tests\Fixtures\Resources\Posts\Pages\ListPosts::route('/'), - 'create' => \Filament\Tests\Fixtures\Resources\Posts\Pages\CreatePost::route('/create'), - 'view' => \Filament\Tests\Fixtures\Resources\Posts\Pages\ViewPost::route('/{record}'), - 'edit' => \Filament\Tests\Fixtures\Resources\Posts\Pages\EditPost::route('/{record}/edit'), + 'index' => ListPosts::route('/'), + 'create' => CreatePost::route('/create'), + 'view' => ViewPost::route('/{record}'), + 'edit' => EditPost::route('/{record}/edit'), ]; } } diff --git a/tests/src/Fixtures/Resources/Shop/Products/ProductResource.php b/tests/src/Fixtures/Resources/Shop/Products/ProductResource.php index bd32984d4a2..2b27809ad38 100644 --- a/tests/src/Fixtures/Resources/Shop/Products/ProductResource.php +++ b/tests/src/Fixtures/Resources/Shop/Products/ProductResource.php @@ -4,6 +4,10 @@ use Filament\Resources\Resource; use Filament\Tests\Fixtures\Models\Product; +use Filament\Tests\Fixtures\Resources\Shop\Products\Pages\CreateProduct; +use Filament\Tests\Fixtures\Resources\Shop\Products\Pages\EditProduct; +use Filament\Tests\Fixtures\Resources\Shop\Products\Pages\ListProducts; +use Filament\Tests\Fixtures\Resources\Shop\Products\Pages\ViewProduct; class ProductResource extends Resource { @@ -16,10 +20,10 @@ class ProductResource extends Resource public static function getPages(): array { return [ - 'index' => \Filament\Tests\Fixtures\Resources\Shop\Products\Pages\ListProducts::route('/'), - 'create' => \Filament\Tests\Fixtures\Resources\Shop\Products\Pages\CreateProduct::route('/create'), - 'view' => \Filament\Tests\Fixtures\Resources\Shop\Products\Pages\ViewProduct::route('/{record}'), - 'edit' => \Filament\Tests\Fixtures\Resources\Shop\Products\Pages\EditProduct::route('/{record}/edit'), + 'index' => ListProducts::route('/'), + 'create' => CreateProduct::route('/create'), + 'view' => ViewProduct::route('/{record}'), + 'edit' => EditProduct::route('/{record}/edit'), ]; } } diff --git a/tests/src/Fixtures/Resources/Users/UserResource.php b/tests/src/Fixtures/Resources/Users/UserResource.php index 934ad88cc59..820b555f938 100644 --- a/tests/src/Fixtures/Resources/Users/UserResource.php +++ b/tests/src/Fixtures/Resources/Users/UserResource.php @@ -11,6 +11,10 @@ use Filament\Tables; use Filament\Tables\Table; use Filament\Tests\Fixtures\Models\User; +use Filament\Tests\Fixtures\Resources\Users\Pages\CreateUser; +use Filament\Tests\Fixtures\Resources\Users\Pages\EditUser; +use Filament\Tests\Fixtures\Resources\Users\Pages\ListUsers; +use Filament\Tests\Fixtures\Resources\Users\Pages\ViewUser; class UserResource extends Resource { @@ -68,10 +72,10 @@ public static function table(Table $table): Table public static function getPages(): array { return [ - 'index' => \Filament\Tests\Fixtures\Resources\Users\Pages\ListUsers::route('/'), - 'create' => \Filament\Tests\Fixtures\Resources\Users\Pages\CreateUser::route('/create'), - 'view' => \Filament\Tests\Fixtures\Resources\Users\Pages\ViewUser::route('/{record}'), - 'edit' => \Filament\Tests\Fixtures\Resources\Users\Pages\EditUser::route('/{record}/edit'), + 'index' => ListUsers::route('/'), + 'create' => CreateUser::route('/create'), + 'view' => ViewUser::route('/{record}'), + 'edit' => EditUser::route('/{record}/edit'), ]; } } From dab4b7610df9d35ce09421eb24738c53f2ce20a0 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Sun, 2 Feb 2025 20:38:40 +0000 Subject: [PATCH 9/9] Update RepeaterTest.php --- tests/src/Forms/Components/RepeaterTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/src/Forms/Components/RepeaterTest.php b/tests/src/Forms/Components/RepeaterTest.php index 750a2659743..f6cc05fb2f0 100644 --- a/tests/src/Forms/Components/RepeaterTest.php +++ b/tests/src/Forms/Components/RepeaterTest.php @@ -4,8 +4,8 @@ use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Filament\Tests\Fixtures\Livewire\Livewire; -use Filament\Tests\Models\Post; -use Filament\Tests\Models\User; +use Filament\Tests\Fixtures\Models\Post; +use Filament\Tests\Fixtures\Models\User; use Filament\Tests\TestCase; use Illuminate\Support\Arr; use Illuminate\Support\Str; @@ -146,7 +146,7 @@ $undoRepeaterFake(); }); -it('loads relationship', function () { +it('loads a relationship', function () { $user = User::factory() ->has(Post::factory()->count(3)) ->create(); @@ -167,7 +167,7 @@ ->toBe(3); }); -it('throw exception for missing relationship', function () { +it('throws an exception for a missing relationship', function () { $componentContainer = Schema::make(Livewire::make()) ->statePath('data') ->components([