Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.x throw exception if relationship is not found #14334

Open
wants to merge 9 commits into
base: 4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/forms/src/Components/CheckboxList.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion packages/forms/src/Components/MorphToSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}();
}

/**
Expand Down
14 changes: 12 additions & 2 deletions packages/forms/src/Components/Repeater.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace Filament\Forms\Components;

use Closure;
use Exception;
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;
Expand All @@ -30,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;
Expand Down Expand Up @@ -1086,7 +1088,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
Expand Down
10 changes: 8 additions & 2 deletions packages/forms/src/Components/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -1159,15 +1159,17 @@ public function getLabel(): string | Htmlable | null

public function getRelationship(): BelongsTo | BelongsToMany | HasOneOrMany | HasManyThrough | BelongsToThrough | null
{
if (blank($this->getRelationshipName())) {
if (! $this->hasRelationship()) {
return null;
}

$record = $this->getModelInstance();

$relationship = null;

foreach (explode('.', $this->getRelationshipName()) as $nestedRelationshipName) {
$relationshipName = $this->getRelationshipName();

foreach (explode('.', $relationshipName) as $nestedRelationshipName) {
if (! $record->isRelation($nestedRelationshipName)) {
$relationship = null;

Expand All @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion packages/tables/src/Columns/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,6 +26,7 @@ class Column extends ViewComponent
{
use CanAggregateRelatedModels;
use CanGrow;
use CanSpanColumns;
use Concerns\BelongsToGroup;
use Concerns\BelongsToLayout;
use Concerns\BelongsToTable;
Expand All @@ -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;
Expand Down
13 changes: 11 additions & 2 deletions packages/tables/src/Filters/Concerns/HasRelationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Filament\Tables\Filters\Concerns;

use Closure;
use Exception;
use Filament\Support\Services\RelationshipJoiner;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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'),
];
}
}
12 changes: 8 additions & 4 deletions tests/src/Fixtures/Resources/Posts/PostResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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'),
];
}
}
12 changes: 8 additions & 4 deletions tests/src/Fixtures/Resources/Shop/Products/ProductResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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'),
];
}
}
12 changes: 8 additions & 4 deletions tests/src/Fixtures/Resources/Users/UserResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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'),
];
}
}
36 changes: 36 additions & 0 deletions tests/src/Forms/Components/RepeaterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +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\TestCase;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
Expand Down Expand Up @@ -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
Expand Down