Filament Nested Resources: Manage Courses and their Lessons

If you have two Resource Controllers like Courses and Lessons, they are often called nested resources in Laravel. In this tutorial, I will show you how to make nested resources in Filament.

For this tutorial we will have two models Course, and Lesson. The course will have many Lessons, and Lessons will belong to a Course.

And this is what we will be building:

  1. In the list of courses, you will see a link to manage lessons of that course
  2. The page for managing lessons will show the title of the course and breadcrumbs including that course title

courses page

lessons page


Prepare Resources

First, we will prepare resources. In the LessonResource, we need to set a new route and change create a route so that it would have a record, change a slug URL, set that it won't be registered in the navigation, and change the query so that it would get lessons only for the selected course.

app/Filament/Resources/LessonResource.php:

class LessonResource extends Resource
{
protected static ?string $model = Lesson::class;
 
protected static ?string $slug = 'courses/lessons';
 
protected static bool $shouldRegisterNavigation = false;
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('title')
->required(),
]);
}
 
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
 
public static function getPages(): array
{
return [
'index' => Pages\ListLessons::route('/'),
'lessons' => Pages\ListLessons::route('/{record}'),
'create' => Pages\CreateLesson::route('/{record}/create'),
'edit' => Pages\EditLesson::route('/{record}/edit'),
];
}
 
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->where('course_id', request('record'));
}
}

Now, that we have created a route for listing lessons, we can add an action to the CourseResource to list lessons.

app/Filament/Resources/CourseResource.php:

class CourseResource extends Resource
{
protected static ?string $model = Course::class;
 
protected static ?string $navigationIcon = 'heroicon-o-collection';
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('title')
->required(),
]);
}
 
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('lessons_count')
->counts('lessons'),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
])
->prependActions([
Tables\Actions\Action::make('View lessons')
->color('success')
->icon('heroicon-s-view-list')
->url(fn (Course $record): string => LessonResource::getUrl('lessons', ['record' => $record]))
]);
}
 
public static function getRelations(): array
{
return [
//
];
}
 
public static function getPages(): array
{
return [
'index' => Pages\ListCourses::route('/'),
'create' => Pages\CreateCourse::route('/create'),
'edit' => Pages\EditCourse::route('/{record}/edit'),
];
}
}

After creating a couple of courses you should see result like the bellow:

course list page


Creating Lesson

Before creating a lesson, we need to modify the URL of the create action.

app/Filament/Resources/LessonResource/Pages/ListLessons.php:

class ListLessons extends ListRecords
{
protected static string $resource = LessonResource::class;
 
protected function getActions(): array
{
return [
Actions\CreateAction::make()
->url(fn (): string => LessonResource::getUrl('create', ['record' => request('record')])),
];
}
}

There are a couple of ways to set the course_id field. For this tutorial, we will use...

The full tutorial [8 mins, 1462 words] is only for Premium Members

Login Or Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1056 lessons, total 44 h 09 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials