Creating a custom resume page in filament php: a step-by-step guide
Filament is a robust framework for building beautiful admin panels in Laravel. Customizing Filament allows you to tailor its components to your specific needs, such as creating a custom page. In this blog, we'll walk through how to create a custom "Resume" page in Filament using a practical example.
For a visual guide, check out my YouTube tutorial
We'll cover:
- Setting up the custom page class.
- Defining the form schema.
- Handling form actions.
Let's dive in!
Prerequisites
Ensure you have the following before starting:
- Filament installed and set up in your Laravel project.
- Knowledge of Laravel and Filament basics.
- Enum for Page Types (optional but recommended).
Example Code Overview
Here's a complete example of the Resume
page we'll create. We'll dissect it step by step to understand each part:
<?php namespace App\Filament\Pages; use App\Enums\PageType; use App\Models\User; use Filament\Facades\Filament; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\RichEditor; use Filament\Forms\Components\TextInput; use Filament\Forms\Concerns\InteractsWithForms; use Filament\Forms\Contracts\HasForms; use Filament\Forms\Form; use Filament\Notifications\Notification; use Filament\Pages\Page; use Filament\Support\Exceptions\Halt; use Illuminate\Support\Str; class Resume extends Page implements HasForms { use InteractsWithForms; public ?array $data = []; protected static ?string $navigationIcon = 'heroicon-o-briefcase'; protected static ?string $title = 'Resume Page'; protected static ?string $navigationGroup = 'CMS'; protected static ?int $navigationSort = 2; protected static string $view = 'filament.pages.custom'; public User $user; public function mount(): void { $this->user = Filament::getCurrentPanel() ->auth() ->user(); if ($record = $this->user->pages->where('type', PageType::RESUME)->first()) { $this->form->fill($record->data); } } public function form(Form $form): Form { return $form ->schema([ Repeater::make('education') ->schema([ DatePicker::make('date_of_starting') ->required() ->native(false), DatePicker::make('date_of_ending') ->native(false), TextInput::make('course') ->required(), TextInput::make('institute') ->required(), ]) ->itemLabel(fn (array $state): ?string => (Str::title($state['course']) ?? null).' ('.(Str::title($state['institute']) ?? null).')') ->collapsible() ->collapsed() ->columns(2) ->required(), Repeater::make('experience') ->schema([ DatePicker::make('date_of_joining') ->required() ->native(false), DatePicker::make('date_of_leaving') ->native(false), TextInput::make('position') ->required(), TextInput::make('organization') ->required(), RichEditor::make('role') ->toolbarButtons([ 'bold', 'bulletList', 'h2', 'h3', 'italic', 'orderedList', 'redo', 'undo', ])->columnSpanFull(), ]) ->itemLabel(fn (array $state): ?string => (Str::title($state['position']) ?? null).' ('.(Str::title($state['organization']) ?? null).')') ->collapsible() ->collapsed() ->columns(2) ->required(), Repeater::make('skills') ->schema([ TextInput::make('name') ->required(), TextInput::make('percentage') ->suffix('%') ->numeric() ->step(1) ->minValue(0) ->maxValue(100) ->required(), ]) ->itemLabel(fn (array $state): ?string => Str::title($state['name']) ?? null) ->collapsible() ->collapsed() ->columns(2) ->required(), Repeater::make('knowledge') ->schema([ TextInput::make('name') ->hiddenLabel() ->required(), ]) ->itemLabel(fn (array $state): ?string => Str::title($state['name']) ?? null) ->collapsible() ->collapsed() ->columns(1) ->grid(4) ->required(), ]) ->statePath('data'); } protected function getFormActions(): array { return [ Action::make('save') ->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label')) ->submit('save'), ]; } public function save(): void { try { $data = $this->form->getState(); $this->user->pages()->updateOrCreate( ['type' => PageType::RESUME], ['data' => $data] ); } catch (Halt $exception) { return; } Notification::make() ->success() ->title(__('filament-panels::resources/pages/edit-record.notifications.saved.title')) ->send(); }
}
Step-by-Step Breakdown
1. Setting Up the Custom Page Class
Create a new class in the App\Filament\Pages
namespace. This class should extend Filament\Pages\Page
and implement Filament\Forms\Contracts\HasForms
.
namespace App\Filament\Pages; use App\Models\User; use Filament\Pages\Page; use Filament\Forms\Contracts\HasForms; use Filament\Forms\Concerns\InteractsWithForms; class Resume extends Page implements HasForms { use InteractsWithForms; public User $user; public function mount(): void { $this->user = Filament::getCurrentPanel()->auth()->user(); }
}
Explanation:
- Namespace: Ensure it's under the correct namespace.
- Inheritance: Extends
Page
and implementsHasForms
to integrate form functionalities. - Mount Method: Initializes the user using Filament's authentication.
2. Defining the Form Schema
Define the form's structure in the form
method. Use Filament's form components to build the form schema.
public function form(Form $form): Form { return $form->schema([ Repeater::make('education') ->schema([ DatePicker::make('date_of_starting')->required()->native(false), DatePicker::make('date_of_ending')->native(false), TextInput::make('course')->required(), TextInput::make('institute')->required(), ]) ->itemLabel(fn (array $state): ?string => (Str::title($state['course']) ?? null).' ('.(Str::title($state['institute']) ?? null).')') ->collapsible() ->collapsed() ->columns(2) ->required(), // Similar Repeater fields for 'experience', 'skills', 'knowledge' ])->statePath('data');
}
Explanation:
- Repeater: Creates repeating fields for entries like education, experience, etc.
- DatePicker and TextInput: Define various input fields.
- itemLabel: Generates labels for each repeater item.
3. Handling Form Actions
Define form actions for handling form submissions. In this example, we have a "Save" action.
protected function getFormActions(): array
{
return [
Action::make('save')
->label('Save')
->submit('save'),
];
}
4. Saving the Form Data
Implement the save
method to handle data saving. This method updates or creates the user’s resume data.
public function save(): void { try { $data = $this->form->getState(); $this->user->pages()->updateOrCreate( ['type' => PageType::RESUME], ['data' => $data] ); } catch (Halt $exception) { return; } Notification::make() ->success() ->title('Saved Successfully') ->send();
}
Explanation:
- Form State: Retrieves the form's current state.
- Update or Create: Updates existing resume data or creates a new entry.
- Notification: Sends a success notification upon saving.
5. Configuring Navigation
Configure the page's navigation properties such as icon, title, and group.
protected static ?string $navigationIcon = 'heroicon-o-briefcase';
protected static ?string $title = 'Resume Page';
protected static ?string $navigationGroup = 'CMS';
protected static ?int $navigationSort = 2;
protected static string $view = 'filament.pages.custom';
Explanation:
- Icon: Sets the navigation icon.
- Title: Sets the page title.
- Group: Groups the page under CMS in the navigation.
- Sort:
Defines the sort order.
- View: Specifies the Blade view for rendering.
Conclusion
Creating a custom page in Filament PHP involves defining a new page class, building a form schema, and handling form actions. This example provides a solid foundation for building more complex custom pages in your Filament admin panel.
Feel free to experiment with different form components and actions to tailor your pages to your specific needs. Happy coding!
Refrence : Custom pages - Panel Builder - Filament
If you have any questions or need further assistance, leave a comment below or reach out through my YouTube channel.