
In this guide, we will explore how we can add nested resources in filament panel. This feature was introduced in filament v4.
Setup model to add nested resources in filament
For nested resources, we will have 4 models.
- Chapter
- Topic
- Lesson
- Quiz
The relationship for above is:
chapter --> hasMany--> topics
topic --> hasMany --> lessons
lesson -->hasMany -->quizes
I’ve used this approach in the backend of my mobile app — the frontend you see here is powered by it.
Chapter Model
Lets see the code for chapter model:
class Chapter extends Model
{
protected $fillable = [
'chapter_id',
'title',
'order',
'status',
];
protected $casts = [
'order' => 'integer',
];
public function topics(): HasMany
{
return $this->hasMany(Topic::class)->orderBy('order');
}
....
}
Topic Model
class Topic extends Model
{
protected $fillable = [
'chapter_id',
'title',
'description',
'order',
'status'
];
protected $casts = [
'order' => 'integer',
];
public function chapter(): BelongsTo
{
return $this->belongsTo(Chapter::class);
}
public function lessons(): HasMany
{
return $this->hasMany(Lesson::class)->orderBy('order');
}
}
Lesson Model
class Lesson extends Model
{
protected $fillable = [
'topic_id',
'title',
'order',
'estimated_minutes',
'content',
'key_points',
'status'
];
protected $casts = [
'order' => 'integer',
'estimated_minutes' => 'integer',
'key_points' => 'array',
];
public function topic(): BelongsTo
{
return $this->belongsTo(Topic::class);
}
public function questions(): HasMany
{
return $this->hasMany(Question::class);
}
}
Question
class Question extends Model
{
protected $fillable = [
'lesson_id',
'type',
'question',
'options',
'correct_answer',
'explanation',
'status'
];
protected $casts = [
'options' => 'array',
];
public function lesson(): BelongsTo
{
return $this->belongsTo(Lesson::class);
}
}
Now all our four model are setup with their relationship.
Create a resource
We will first create a normal filament resource for our chapter using the following command:
php artisan make:filament-resource Chapter
And our ChapterResource consists of its own forms and tables.
class ChapterResource extends Resource
{
protected static ?string $model = Chapter::class;
protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-document';
protected static string | \UnitEnum | null $navigationGroup = "Courses";
protected static ?string $recordTitleAttribute = 'title';
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('title')
->required(),
Toggle::make('status')
->default(true),
TextInput::make('order')
->default(function(){
return Chapter::count();
})
]);
}
public static function table(Table $table): Table
{
return $table
->reorderable('order')
->defaultSort('order','asc')
->columns([
TextColumn::make('order'),
TextColumn::make('title')
->searchable(),
TextColumn::make('total_topics')
->searchable(),
ToggleColumn::make('status')
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
]);
}
....
}
Create your first nested resource
To create a nested resource for our Topic Resource, use the following command:
php artisan make:filament-resource Topic --nested
The above command will ask for the following questions:
- Title attribute: the attribute that you want to show on breadcrumb. If you don’t want, leave it empty.
- Which panel would you like to create this resource in? : if you have more than one panel, it can ask for the confirmation of panel. choose your own.
- Which resource would you like to nest this resource inside? : Most important, here you need to choose the Chapter Resource as we want Topic resource to be nested inside the Chapter Resource.
- Would you like to generate a read-only view page for the resource? : Answer this on the basis of your need.
- Should the configuration be generated from the current database columns?: Generally yes, as it automatically creates the form and columns.
After you create your nested resource, now its time to create a relation manager to connect it.
php artisan make:filament-relation-manager CourseResource topics title
// 1. Resource Name
// 2. relationship Name
// 3. title attribute
When hitting the above command, it will ask for
- Which resource would you like to create this relation manager in?: Choose the Chapter resource here.
- Filament can link this to an existing resource, which will open the resource’s pages instead of modals when links are clicked. It will also inherit the resource’s configuration : Click yes and choose TopicResource
So, the above command will create us a TopicsRelationManger.
class TopicsRelationManager extends RelationManager
{
protected static string $relationship = 'topics';
protected static ?string $relatedResource = TopicResource::class;
public function table(Table $table): Table
{
return $table
->headerActions([
CreateAction::make(),
]);
}
}
After generating that, from our Topic Resource ,
protected static ?string $parentResource = ChapterResource::class;
Add the $parentResource property pointing to the parent.
Finally, we need to register the relationmanager. Inside our ChapterResource:
public static function getRelations(): array
{
return [
TopicsRelationManager::make()
];
}
custom page filamentIn this way, you can create as many nested resource you want. So, now similar to above, you can created a nested resource for your Lesson as well as Quiz Resource. Read more in official guide to add nested resources in filament. Read mor about filament articles here.
Have any confusion, please comment it down.