How to Structure Code for Filament Modules in Livewire?

I am using all Filament modules in Livewire directly, not the Panel Builder. My goal to make the main component cleaner and lighter by breaking down functionality into smaller parts. Here are the two approaches I am considering: Approach 1: Using Traits - Break down actions and forms into traits to keep the main Livewire component focused on its primary responsibilities.
- The traits encapsulate logic related to actions and forms for better code clarity.
File Structure:
app/
├── Http/
│ ├── Livewire/
│ │ ├── Organization/
│ │ │ ├── Index.php
│ │ │ ├── Traits/
│ │ │ │ ├── Actions.php
│ │ │ │ ├── Forms.php
app/
├── Http/
│ ├── Livewire/
│ │ ├── Organization/
│ │ │ ├── Index.php
│ │ │ ├── Traits/
│ │ │ │ ├── Actions.php
│ │ │ │ ├── Forms.php
--- Approach 2: Using Classes - Encapsulate each action and bulk action into its own class for better organization.
- The classes are grouped logically in directories to separate concerns and keep the main component light.
File Structure:
app/
├── Http/
│ ├── Livewire/
│ │ ├── Organization/
│ │ │ ├── Index.php
│ │ │ ├── Actions/
│ │ │ │ ├── Edit.php
│ │ │ │ ├── Restore.php
│ │ │ │ ├── Delete.php
│ │ │ │ ├── ForceDelete.php
│ │ │ ├── BulkActions/
│ │ │ │ ├── BulkRestore.php
│ │ │ │ ├── BulkDelete.php
│ │ │ │ ├── BulkForceDelete.php
app/
├── Http/
│ ├── Livewire/
│ │ ├── Organization/
│ │ │ ├── Index.php
│ │ │ ├── Actions/
│ │ │ │ ├── Edit.php
│ │ │ │ ├── Restore.php
│ │ │ │ ├── Delete.php
│ │ │ │ ├── ForceDelete.php
│ │ │ ├── BulkActions/
│ │ │ │ ├── BulkRestore.php
│ │ │ │ ├── BulkDelete.php
│ │ │ │ ├── BulkForceDelete.php
Which approach is more used in the filament Community
1 Reply
sohail
sohailOP2w ago
code example for using a class
class Edit
{
public static function create(): Action
{
return EditAction::make()
->icon('fal-pen-to-square')
->hidden(fn($record) => $record->deleted_at)
->fillForm(fn(Organization $organization) => $organization->toArray())
->form(self::form())
->slideOver();
}

private static function form(): array
{
return [
TextInput::make('name')
->required()
->maxLength(255),
TextInput::make('address')
->required()
->maxLength(1500),
Textarea::make('description')
->required()
->maxLength(3000),
];
}
}
class Edit
{
public static function create(): Action
{
return EditAction::make()
->icon('fal-pen-to-square')
->hidden(fn($record) => $record->deleted_at)
->fillForm(fn(Organization $organization) => $organization->toArray())
->form(self::form())
->slideOver();
}

private static function form(): array
{
return [
TextInput::make('name')
->required()
->maxLength(255),
TextInput::make('address')
->required()
->maxLength(1500),
Textarea::make('description')
->required()
->maxLength(3000),
];
}
}
depending on the action i can also include the edit form inside the class since it part of the edit action but in some case where both the edit and create from is the same i just put inside the model so both class can access it this is how my index compoent look like regradless of the apporch
public function table(Table $table): Table
{
return $table->query(Organization::query())
->searchPlaceholder('Search For Organizations')
->columns($this->column())
->actions($this->actions())
->bulkActions($this->bulkActions())
->filters([
TrashedFilter::make('trashed')
->label('Deleted Organizations')
->native(false)
]);
}

public function render()
{
return view('livewire.organization.index');
}

protected function column(): array
{
return [
...column_here

];
}

protected function actions(): array
{
return [
ActionGroup::make([
Edit::create(), // $this->edit() when using traits
Restore::create(),
Delete::create(),
ForceDelete::create(),
])
->button()
->extraAttributes(['class' => 'hfi-action-group-btn'])
];
}

protected function bulkActions(): array
{
return [
BulkActionGroup::make([
BulkRestore::create(),
BulkDelete::create(),
BulkForceDelete::create(),
])
];
}
public function table(Table $table): Table
{
return $table->query(Organization::query())
->searchPlaceholder('Search For Organizations')
->columns($this->column())
->actions($this->actions())
->bulkActions($this->bulkActions())
->filters([
TrashedFilter::make('trashed')
->label('Deleted Organizations')
->native(false)
]);
}

public function render()
{
return view('livewire.organization.index');
}

protected function column(): array
{
return [
...column_here

];
}

protected function actions(): array
{
return [
ActionGroup::make([
Edit::create(), // $this->edit() when using traits
Restore::create(),
Delete::create(),
ForceDelete::create(),
])
->button()
->extraAttributes(['class' => 'hfi-action-group-btn'])
];
}

protected function bulkActions(): array
{
return [
BulkActionGroup::make([
BulkRestore::create(),
BulkDelete::create(),
BulkForceDelete::create(),
])
];
}
Want results from more Discord servers?
Add your server