Skip to content

Instantly share code, notes, and snippets.

@tiagofrancafernandes
Last active January 25, 2024 22:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiagofrancafernandes/31dc00f5502cee6e230cf1834761df62 to your computer and use it in GitHub Desktop.
Save tiagofrancafernandes/31dc00f5502cee6e230cf1834761df62 to your computer and use it in GitHub Desktop.
dev-filamentphp Laravel admin
<?php

namespace Yemenpoint\FilamentCustomFields\Resources;

use Closure;
use Filament\Forms;
use Filament\Tables;
use Illuminate\Support\Str;
use Filament\Resources\Form;
use Filament\Resources\Table;
use Spatie\Html\Facades\Html;
use Filament\Resources\Resource;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Illuminate\Database\Eloquent\Model;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Yemenpoint\FilamentCustomFields\Models\CustomField;
use Yemenpoint\FilamentCustomFields\CustomFields\PermissionsHelper;
use Yemenpoint\FilamentCustomFields\Resources\CustomFieldResource\Pages;
use Yemenpoint\FilamentCustomFields\CustomFields\FilamentCustomFieldsHelper;

class CustomFieldResource extends Resource
{
    use PermissionsHelper;

    protected static ?string $resourceKey = 'custom_fields';

    protected static array $options = [];

    protected static ?string $model = CustomField::class;

    protected static ?string $navigationIcon = 'heroicon-o-collection';

    protected static function getNavigationGroup(): ?string
    {
        return __('filament-custom-fields::resource.navigation_group');
    }

    public static function getPluralModelLabel(): string
    {
        return __('filament-custom-fields::resource.custom_field_plural_label');
    }

    public static function getModelLabel(): string
    {
        return __('filament-custom-fields::resource.custom_field_label');
    }

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Card::make()->schema([
                    Forms\Components\Grid::make()->schema([
                        Forms\Components\Select::make('model_type')
                            ->label(__('filament-custom-fields::resource.custom_field.form.model_type.label'))
                            ->options(config("filament-custom-fields.models"))
                            ->required(),

                        Forms\Components\Select::make('type')
                            ->label(__('filament-custom-fields::resource.custom_field.form.type.label'))
                            ->reactive()
                            ->options(FilamentCustomFieldsHelper::getTypes())->default("text")
                            ->required(),

                        Forms\Components\TextInput::make('title')
                            ->label(__('filament-custom-fields::resource.custom_field.form.title.label'))
                            ->required(),
                        Forms\Components\TextInput::make('hint')
                            ->label(__('filament-custom-fields::resource.custom_field.form.hint.label')),

                        \Filament\Forms\Components\Fieldset::make('options_fieldset')
                            ->label(__('filament-custom-fields::resource.custom_field.form.select.options_fieldset.label'))
                            ->schema([
                                Forms\Components\Repeater::make('options')
                                    ->disableLabel()
                                    ->before(function (?Model $record) {
                                        static::$options = (array) ($record?->options ?? []);
                                    })
                                    ->columnSpan("full")
                                    ->hidden(fn (callable $get) => $get("type") != "select")
                                    ->schema([
                                        Grid::make(2)
                                            ->schema([
                                                Forms\Components\Hidden::make('updatedAt')
                                                    ->disabled()
                                                    ->dehydrateStateUsing(fn () => now()->format('c')),

                                                Forms\Components\TextInput::make('label')
                                                    ->label(__('filament-custom-fields::resource.custom_field.form.select.label.label'))
                                                    ->required()
                                                    ->reactive()
                                                    ->afterStateUpdated(
                                                        function (
                                                            ?string $state,
                                                            callable $set,
                                                            callable $get,
                                                            string $context,
                                                            ?Model $record,
                                                        ) {
                                                            if (($context != 'create') && $get('updatedAt')) {
                                                                return;
                                                            }

                                                            $count = collect($record?->options)
                                                                ->where('value', $state)->count();

                                                            $set('value', str($state)->slug()->append(
                                                                $count ? '_' . ($count + 1) : ''
                                                            ));
                                                        }
                                                    )
                                                    ->columnSpan(1),

                                                Forms\Components\TextInput::make('value')
                                                    ->label(__('filament-custom-fields::resource.custom_field.form.select.value.label'))
                                                    ->string()
                                                    ->required()
                                                    ->reactive()
                                                    ->afterStateUpdated(
                                                        function (
                                                            ?string $state,
                                                            ?string $old,
                                                            callable $get,
                                                            callable $set,
                                                            ?Model $record,
                                                        ) {
                                                            $state = trim((string) $state);

                                                            if ($get('updatedAt') || !($state && collect($record?->options)
                                                                ->where('value', $state)->count())) {
                                                                return;
                                                            }

                                                            Notification::make()
                                                                ->danger()
                                                                ->title(
                                                                    __('filament-custom-fields::resource.custom_field.form.select.value.validation.duplicated.title')
                                                                )
                                                                ->body(
                                                                    __('filament-custom-fields::resource.custom_field.form.select.value.validation.duplicated.body')
                                                                )
                                                                ->seconds(3)
                                                                ->id('select.value.validation.duplicated') // prevent duplication
                                                                ->send();

                                                            $set('value', $old ?: '');
                                                        }
                                                    )
                                                    ->disabled(function (?string $state, callable $get, ?Model $record) {
                                                        return $state && collect($record?->options)
                                                            ->where('value', $state)->count() && $get('updatedAt');
                                                    })
                                                    ->columnSpan(1),
                                            ]),
                                    ])
                                    ->grid(1),
                            ])
                            ->hidden(fn (callable $get) => $get("type") != "select"),

                        Grid::make(4)
                            ->schema([
                                Grid::make(4)
                                    ->schema([
                                        Forms\Components\Toggle::make('required')
                                            ->label(__('filament-custom-fields::resource.custom_field.form.required.label'))
                                            ->columnSpan(1)->default(true),
                                        Forms\Components\Toggle::make('show_in_columns')
                                            ->label(__('filament-custom-fields::resource.custom_field.form.show_in_columns.label'))
                                            ->columnSpan(1)->default(true),
                                    ]),
                                Forms\Components\TextInput::make('default_value')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.default_value.label')),
                                Forms\Components\TextInput::make('column_span')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.column_span.label'))
                                    ->numeric()->maxValue(12)->minValue(1)->default(1),
                                Forms\Components\TextInput::make('order')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.order.label'))
                                    ->numeric()->default(1),
                                Forms\Components\TextInput::make('rules')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.rules.label')),
                            ]),
                    ])
                ]),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make("id")
                    ->label(__('filament-custom-fields::resource.custom_field.table.id.label'))
                    ->searchable(isIndividual: true)
                    ->sortable(),

                Tables\Columns\TextColumn::make("order")
                    ->label(__('filament-custom-fields::resource.custom_field.table.order.label'))
                    ->sortable(),

                Tables\Columns\TextColumn::make("title")
                    ->label(__('filament-custom-fields::resource.custom_field.table.title.label'))
                    ->searchable(isIndividual: true),

                Tables\Columns\TextColumn::make("type")
                    ->label(__('filament-custom-fields::resource.custom_field.table.type.label')),

                Tables\Columns\TextColumn::make("model_type")
                    ->label(__('filament-custom-fields::resource.custom_field.table.model_type.label'))
                    ->searchable(isIndividual: true)
                    ->formatStateUsing(function ($state) {
                        $display = $state;
                        foreach (config("filament-custom-fields.models") as $key => $value) {
                            if ($key == $state) {
                                $display = $value;
                                break;
                            }
                        }
                        return $display;
                    }),

                Tables\Columns\TextColumn::make("rules")
                    ->label(__('filament-custom-fields::resource.custom_field.table.rules.label')),
                Tables\Columns\IconColumn::make("required")
                    ->label(__('filament-custom-fields::resource.custom_field.table.required.label'))

                    ->boolean(),
                Tables\Columns\IconColumn::make("show_in_columns")
                    ->label(__('filament-custom-fields::resource.custom_field.table.show_in_columns.label'))
                    ->boolean(),
            ])
            ->filters([
                Tables\Filters\Filter::make('type_number')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_number_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'number')),

                Tables\Filters\Filter::make('type_text')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_text_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'text')),

                Tables\Filters\Filter::make('type_select')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_select_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'select')),

                Tables\Filters\Filter::make('type_textarea')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_textarea_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'textarea')),

                Tables\Filters\Filter::make('type_rich_editor')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_rich_editor_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'rich_editor')),

                Tables\Filters\Filter::make('type_toggle')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_toggle_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'toggle')),

            ])
            ->actions([
                ...static::getTableActions(),
            ])
            ->headerActions([
                // Spatie import!!!!
                Tables\Actions\Action::make('import')
                    ->label(__('Import'))
                    ->action(fn () => static::getEloquentQuery())
                    ->requiresConfirmation()
                    ->modalContent(function () {
                        return Html::div('aaa');
                    })
                    // ->modalCancelAction()
                    // ->modalHeading()
                    // ->modalSubheading()
                    // ->modalActions([
                    //     //
                    // ])
                    ->form([
                        Forms\Components\Grid::make()->schema([
                            Forms\Components\Select::make('model_type')
                                ->label(__('filament-custom-fields::resource.custom_field.form.model_type.label'))
                                ->options(config("filament-custom-fields.models"))
                                ->required(),
                            Forms\Components\TextInput::make('email'),
                        ])
                    ])
                    ->closeModalByClickingAway(false)
                    ->mountUsing(function (?\Filament\Forms\ComponentContainer $form = null): void {
                        if (! $form) {
                            return;
                        }
                        $data = [
                            'email' => 'inited',
                        ];

                        \Log::info([__FILE__ . ':' . __LINE__]);

                        $form->fill($data);
                    })
                    // ->mountUsing(function () {
                    //     /* na abertura da modal */
                    //     return [
                    //         'email' => __LINE__ . 'aaa@sss.com',
                    //         'name' => 'algo',
                    //     ];
                    // })
                    ->mutateFormDataUsing(function (array $data): array {
                        /* aqui eu já tenho os dados do formulário e posso mudar os valores */
                        $data['user_id'] = auth()->id();
                        $data['line_' . __LINE__] = 'log';

                        return $data;
                    })
                    ->before(function (array $data = []) {
                        /* aqui já tenho os dados do formulário e tratados */
                        // use Spatie\SimpleExcel\SimpleExcelReader;

                        // $rows is an instance of Illuminate\Support\LazyCollection
                        $rows = SimpleExcelReader::create($pathToCsv)->getRows();

                        $rows->each(function(array $rowProperties) {
                        // in the first pass $rowProperties will contain
                        // ['email' => 'john@example.com', 'first_name' => 'john']
                        });

                        $data['line_' . __LINE__] = 'log';
                        return $data;
                    })
                    ->after(function (array $data = []) {
                        /* depois da ação ('depois do que?) */
                        $data['line_' . __LINE__] = 'log';
                        return $data;
                    })
                    // ->successNotification(fn() => 'Success')
                    // ->successNotificationTitle(fn() => 'Success title')
                    ->tooltip(__('Import data')),
            ])
            ->bulkActions([
                Tables\Actions\DeleteBulkAction::make(),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getTableActions(): array
    {
        return [
            Tables\Actions\EditAction::make(),
            Tables\Actions\ViewAction::make(),
            Tables\Actions\DeleteAction::make(),
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListCustomFields::route('/'),
            'create' => Pages\CreateCustomField::route('/create'),
            'edit' => Pages\EditCustomField::route('/{record}/edit'),
        ];
    }

    /**
     * resourceKey function
     *
     * @return ?string
     */
    public static function resourceKey(): ?string
    {
        return static::$resourceKey ?? null;
    }
}

///////////////////////

<?php

namespace Yemenpoint\FilamentCustomFields\Resources;

use Closure;
use Filament\Forms;
use Filament\Tables;
use Illuminate\Support\Str;
use Filament\Resources\Form;
use Filament\Resources\Table;
use Spatie\Html\Facades\Html;
use Filament\Resources\Resource;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Illuminate\Database\Eloquent\Model;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Builder;
use Spatie\SimpleExcel\SimpleExcelReader;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Yemenpoint\FilamentCustomFields\Models\CustomField;
use Yemenpoint\FilamentCustomFields\CustomFields\PermissionsHelper;
use Yemenpoint\FilamentCustomFields\Resources\CustomFieldResource\Pages;
use Yemenpoint\FilamentCustomFields\CustomFields\FilamentCustomFieldsHelper;

class CustomFieldResource extends Resource
{
    use PermissionsHelper;

    protected static ?string $resourceKey = 'custom_fields';

    protected static array $options = [];

    protected static ?string $model = CustomField::class;

    protected static ?string $navigationIcon = 'heroicon-o-collection';

    protected static function getNavigationGroup(): ?string
    {
        return __('filament-custom-fields::resource.navigation_group');
    }

    public static function getPluralModelLabel(): string
    {
        return __('filament-custom-fields::resource.custom_field_plural_label');
    }

    public static function getModelLabel(): string
    {
        return __('filament-custom-fields::resource.custom_field_label');
    }

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Card::make()->schema([
                    Forms\Components\Grid::make()->schema([
                        Forms\Components\Select::make('model_type')
                            ->label(__('filament-custom-fields::resource.custom_field.form.model_type.label'))
                            ->options(config("filament-custom-fields.models"))
                            ->required(),

                        Forms\Components\Select::make('type')
                            ->label(__('filament-custom-fields::resource.custom_field.form.type.label'))
                            ->reactive()
                            ->options(FilamentCustomFieldsHelper::getTypes())->default("text")
                            ->required(),

                        Forms\Components\TextInput::make('title')
                            ->label(__('filament-custom-fields::resource.custom_field.form.title.label'))
                            ->required(),
                        Forms\Components\TextInput::make('hint')
                            ->label(__('filament-custom-fields::resource.custom_field.form.hint.label')),

                        \Filament\Forms\Components\Fieldset::make('options_fieldset')
                            ->label(__('filament-custom-fields::resource.custom_field.form.select.options_fieldset.label'))
                            ->schema([
                                Forms\Components\Repeater::make('options')
                                    ->disableLabel()
                                    ->before(function (?Model $record) {
                                        static::$options = (array) ($record?->options ?? []);
                                    })
                                    ->columnSpan("full")
                                    ->hidden(fn (callable $get) => $get("type") != "select")
                                    ->schema([
                                        Grid::make(2)
                                            ->schema([
                                                Forms\Components\Hidden::make('updatedAt')
                                                    ->disabled()
                                                    ->dehydrateStateUsing(fn () => now()->format('c')),

                                                Forms\Components\TextInput::make('label')
                                                    ->label(__('filament-custom-fields::resource.custom_field.form.select.label.label'))
                                                    ->required()
                                                    ->reactive()
                                                    ->afterStateUpdated(
                                                        function (
                                                            ?string $state,
                                                            callable $set,
                                                            callable $get,
                                                            string $context,
                                                            ?Model $record,
                                                        ) {
                                                            if (($context != 'create') && $get('updatedAt')) {
                                                                return;
                                                            }

                                                            $count = collect($record?->options)
                                                                ->where('value', $state)->count();

                                                            $set('value', str($state)->slug()->append(
                                                                $count ? '_' . ($count + 1) : ''
                                                            ));
                                                        }
                                                    )
                                                    ->columnSpan(1),

                                                Forms\Components\TextInput::make('value')
                                                    ->label(__('filament-custom-fields::resource.custom_field.form.select.value.label'))
                                                    ->string()
                                                    ->required()
                                                    ->reactive()
                                                    ->afterStateUpdated(
                                                        function (
                                                            ?string $state,
                                                            ?string $old,
                                                            callable $get,
                                                            callable $set,
                                                            ?Model $record,
                                                        ) {
                                                            $state = trim((string) $state);

                                                            if ($get('updatedAt') || !($state && collect($record?->options)
                                                                ->where('value', $state)->count())) {
                                                                return;
                                                            }

                                                            Notification::make()
                                                                ->danger()
                                                                ->title(
                                                                    __('filament-custom-fields::resource.custom_field.form.select.value.validation.duplicated.title')
                                                                )
                                                                ->body(
                                                                    __('filament-custom-fields::resource.custom_field.form.select.value.validation.duplicated.body')
                                                                )
                                                                ->seconds(3)
                                                                ->id('select.value.validation.duplicated') // prevent duplication
                                                                ->send();

                                                            $set('value', $old ?: '');
                                                        }
                                                    )
                                                    ->disabled(function (?string $state, callable $get, ?Model $record) {
                                                        return $state && collect($record?->options)
                                                            ->where('value', $state)->count() && $get('updatedAt');
                                                    })
                                                    ->columnSpan(1),
                                            ]),
                                    ])
                                    ->grid(1),
                            ])
                            ->hidden(fn (callable $get) => $get("type") != "select"),

                        Grid::make(4)
                            ->schema([
                                Grid::make(4)
                                    ->schema([
                                        Forms\Components\Toggle::make('required')
                                            ->label(__('filament-custom-fields::resource.custom_field.form.required.label'))
                                            ->columnSpan(1)->default(true),
                                        Forms\Components\Toggle::make('show_in_columns')
                                            ->label(__('filament-custom-fields::resource.custom_field.form.show_in_columns.label'))
                                            ->columnSpan(1)->default(true),
                                    ]),
                                Forms\Components\TextInput::make('default_value')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.default_value.label')),
                                Forms\Components\TextInput::make('column_span')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.column_span.label'))
                                    ->numeric()->maxValue(12)->minValue(1)->default(1),
                                Forms\Components\TextInput::make('order')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.order.label'))
                                    ->numeric()->default(1),
                                Forms\Components\TextInput::make('rules')
                                    ->label(__('filament-custom-fields::resource.custom_field.form.rules.label')),
                            ]),
                    ])
                ]),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make("id")
                    ->label(__('filament-custom-fields::resource.custom_field.table.id.label'))
                    ->searchable(isIndividual: true)
                    ->sortable(),

                Tables\Columns\TextColumn::make("order")
                    ->label(__('filament-custom-fields::resource.custom_field.table.order.label'))
                    ->sortable(),

                Tables\Columns\TextColumn::make("title")
                    ->label(__('filament-custom-fields::resource.custom_field.table.title.label'))
                    ->searchable(isIndividual: true),

                Tables\Columns\TextColumn::make("type")
                    ->label(__('filament-custom-fields::resource.custom_field.table.type.label')),

                Tables\Columns\TextColumn::make("model_type")
                    ->label(__('filament-custom-fields::resource.custom_field.table.model_type.label'))
                    ->searchable(isIndividual: true)
                    ->formatStateUsing(function ($state) {
                        $display = $state;
                        foreach (config("filament-custom-fields.models") as $key => $value) {
                            if ($key == $state) {
                                $display = $value;
                                break;
                            }
                        }
                        return $display;
                    }),

                Tables\Columns\TextColumn::make("rules")
                    ->label(__('filament-custom-fields::resource.custom_field.table.rules.label')),
                Tables\Columns\IconColumn::make("required")
                    ->label(__('filament-custom-fields::resource.custom_field.table.required.label'))

                    ->boolean(),
                Tables\Columns\IconColumn::make("show_in_columns")
                    ->label(__('filament-custom-fields::resource.custom_field.table.show_in_columns.label'))
                    ->boolean(),
            ])
            ->filters([
                Tables\Filters\Filter::make('type_number')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_number_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'number')),

                Tables\Filters\Filter::make('type_text')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_text_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'text')),

                Tables\Filters\Filter::make('type_select')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_select_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'select')),

                Tables\Filters\Filter::make('type_textarea')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_textarea_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'textarea')),

                Tables\Filters\Filter::make('type_rich_editor')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_rich_editor_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'rich_editor')),

                Tables\Filters\Filter::make('type_toggle')
                    ->label(__('filament-custom-fields::resource.custom_field.filters.type_toggle_label'))
                    ->query(fn (Builder $query): Builder => $query->where('type', 'toggle')),

            ])
            ->actions([
                ...static::getTableActions(),
            ])
            ->headerActions([
                // Spatie import!!!!
                Tables\Actions\Action::make('import')
                    ->label(__('Import'))
                    ->action(fn () => static::getEloquentQuery())
                    ->requiresConfirmation()
                    ->modalContent(function () {
                        return Html::div('aaa');
                    })
                    // ->modalCancelAction()
                    // ->modalHeading()
                    // ->modalSubheading()
                    // ->modalActions([
                    //     //
                    // ])
                    ->form([
                        Forms\Components\Grid::make()->schema([
                            // Forms\Components\Select::make('model_type')
                            //     ->label(__('filament-custom-fields::resource.custom_field.form.model_type.label'))
                            //     ->options(config("filament-custom-fields.models"))
                            //     ->required(),
                            // Forms\Components\TextInput::make('email'),


                            \Filament\Forms\Components\FileUpload::make('attachment')
                                ->getUploadedFileNameForStorageUsing(function (\Livewire\TemporaryUploadedFile $file): string {
                                    return (string) str($file->getClientOriginalName())->prepend('custom-prefix-');
                                }),

                            // ->acceptedFileTypes(['application/pdf'])
                            // \Filament\Forms\Components\FileUpload::make('attachment'),

                            // \Filament\Forms\Components\FileUpload::make('attachment')
                            //     // ->disk('s3')
                            //     ->directory('form-attachments')
                            //     ->visibility('private'),
                        ])
                    ])
                    ->closeModalByClickingAway(false)
                    ->mountUsing(function (?\Filament\Forms\ComponentContainer $form = null): void {
                        if (! $form) {
                            return;
                        }
                        $data = [
                            'email' => 'inited',
                        ];

                        \Log::info([__FILE__ . ':' . __LINE__]);

                        $form->fill($data);
                    })
                    // ->mountUsing(function () {
                    //     /* na abertura da modal */
                    //     return [
                    //         'email' => __LINE__ . 'aaa@sss.com',
                    //         'name' => 'algo',
                    //     ];
                    // })
                    ->mutateFormDataUsing(function (array $data): array {
                        /* aqui eu já tenho os dados do formulário e posso mudar os valores */

                        // $rows is an instance of Illuminate\Support\LazyCollection
                        $rows = SimpleExcelReader::create($data['attachment'], 'csv')
                            ->useDelimiter(';')
                            ->getRows();

                        $rows->each(function(array $rowProperties)use (&$data) {
                            $data['lines'][] = $rowProperties;
                            // in the first pass $rowProperties will contain
                            // ['email' => 'john@example.com', 'first_name' => 'john']
                        });
                        $data['user_id'] = auth()->id();
                        $data['line_' . __LINE__] = 'log';

                        return $data;
                    })
                    ->before(function (array $data = []) {
                        sleep(1);
                        /* aqui já tenho os dados do formulário e tratados */

                        $data['line_' . __LINE__] = 'log';
                        return $data;
                    })
                    ->after(function (array $data = []) {
                        sleep(1);
                        /* depois da ação ('depois do que?) */
                        $data['line_' . __LINE__] = 'log';
                        return $data;
                    })
                    // ->successNotification(fn() => 'Success')
                    // ->successNotificationTitle(fn() => 'Success title')
                    ->tooltip(__('Import data')),
            ])
            ->bulkActions([
                Tables\Actions\DeleteBulkAction::make(),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getTableActions(): array
    {
        return [
            Tables\Actions\EditAction::make(),
            Tables\Actions\ViewAction::make(),
            Tables\Actions\DeleteAction::make(),
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListCustomFields::route('/'),
            'create' => Pages\CreateCustomField::route('/create'),
            'edit' => Pages\EditCustomField::route('/{record}/edit'),
        ];
    }

    /**
     * resourceKey function
     *
     * @return ?string
     */
    public static function resourceKey(): ?string
    {
        return static::$resourceKey ?? null;
    }
}
->actions([
                \Filament\Tables\Actions\EditAction::make(),
                \Filament\Tables\Actions\DeleteAction::make()
                    ->before(function (DeleteAction $action) {
                        $record = $action->getRecord();
                        if (!$record) {
                            return;
                        }

                        if ($record->can_be_deleted) {
                            Notification::make()
                                ->warning()
                                ->title('You don\'t have an active subscription!')
                                ->body('Choose a plan to continue.')
                                // ->persistent()
                                // ->actions([
                                //     Action::make('subscribe')
                                //         ->button()
                                //         ->url(route('subscribe'), shouldOpenInNewTab: true),
                                // ])
                                ->send();

                            $action->halt();
                        }
                    }),
            ])
// Service provider

Filament::serving( function() {

    $color = TenantHelper::getTheme();

    Filament::registerStyles([
        asset('css/'.$color.'.css')
    ]);
    Filament::registerViteTheme('resources/css/app.css');
});
// Page

class LayoutConfiguration extends Page implements HasForms
{
    use HasPageShield;

    protected static bool $shouldRegisterNavigation = false;

    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    protected static string $view = 'filament.pages.layout-configuration';

    protected static ?string $navigationLabel = 'Configurações';

    protected static ?string $title = 'Configurações';

    protected static ?string $slug = 'configurations';

    public static function canView(): bool
    {
        return Filament::auth()->user()->can(static::getPermissionName());
    }

    public function mount()
    {
        $fillArray = [];
        $fillArray['color'] = tenant()->color ?? null;

        $this->form->fill($fillArray);
    }

    protected function getFormSchema(): array
    {

        return [
            Card::make()
                ->schema([
                    Select::make('color')
                        ->label('Cor')
                        ->options([
                            'amber' => 'amber',
                            'blue' => 'blue',
                            'cyan' => 'cyan',
                            'emerald' => 'emeral',
                            'fuchsia' => 'fucshia',
                            'gray' => 'gray',
                            'green' => 'green',
                            'indigo' => 'indigo',
                            'lime' => 'lime',
                            'neutral' => 'neutral',
                            'orange' => 'orange',
                            'pink' => 'pink',
                            'purple' => 'purple',
                            'red' => 'red',
                            'rose' => 'rose',
                            'sky' => 'sky',
                            'slate' => 'slate',
                            'stone' => 'stone',
                            'teal' => 'teal',
                            'violet' => 'violet',
                            'yellow' => 'yellow',
                            'zinc' => 'zinc'
                        ])
                ]),
        ];
    }

    /** ... */
    tenant()->update([
        'color' => $formState['color'],
    ]);

    Cache::set('color', $formState['color']);
    /** ... */
}

CSS Color files

public/tenancy/assets/css/amber.css
public/tenancy/assets/css/app.css
public/tenancy/assets/css/blue.css
public/tenancy/assets/css/cyan.css
public/tenancy/assets/css/emerald.css
public/tenancy/assets/css/fuchsia.css
public/tenancy/assets/css/gray.css
public/tenancy/assets/css/green.css
public/tenancy/assets/css/indigo.css
public/tenancy/assets/css/lime.css
public/tenancy/assets/css/neutral.css
public/tenancy/assets/css/orange.css
public/tenancy/assets/css/pink.css
public/tenancy/assets/css/purple.css
public/tenancy/assets/css/red.css
public/tenancy/assets/css/rose.css
public/tenancy/assets/css/sky.css
public/tenancy/assets/css/slate.css
public/tenancy/assets/css/stone.css
public/tenancy/assets/css/teal.css
public/tenancy/assets/css/violet.css
public/tenancy/assets/css/yellow.css
public/tenancy/assets/css/zinc.css

:root {
--color-primary-50: 255 251 235;
--color-primary-100: 254 243 199;
--color-primary-200: 253 230 138;
--color-primary-300: 252 211 77;
--color-primary-400: 251 191 36;
--color-primary-500: 245 158 11;
--color-primary-600: 217 119 6;
--color-primary-700: 180 83 9;
--color-primary-800: 146 64 14;
--color-primary-900: 120 53 15;
}
@import './../../vendor/filament/filament/resources/css/app.css';
:root {
--color-primary-50: 239 246 255;
--color-primary-100: 219 234 254;
--color-primary-200: 191 219 254;
--color-primary-300: 147 197 253;
--color-primary-400: 96 165 250;
--color-primary-500: 59 130 246;
--color-primary-600: 37 99 235;
--color-primary-700: 29 78 216;
--color-primary-800: 30 64 175;
--color-primary-900: 30 58 138;
}
:root {
--color-primary-50: 236 254 255;
--color-primary-100: 207 250 254;
--color-primary-200: 165 243 252;
--color-primary-300: 103 232 249;
--color-primary-400: 34 211 238;
--color-primary-500: 6 182 212;
--color-primary-600: 8 145 178;
--color-primary-700: 14 116 144;
--color-primary-800: 21 94 117;
--color-primary-900: 22 78 99;
}
:root {
--color-primary-50: 236 253 245;
--color-primary-100: 209 250 229;
--color-primary-200: 167 243 208;
--color-primary-300: 110 231 183;
--color-primary-400: 52 211 153;
--color-primary-500: 16 185 129;
--color-primary-600: 5 150 105;
--color-primary-700: 4 120 87;
--color-primary-800: 6 95 70;
--color-primary-900: 6 78 59;
}
:root {
--color-primary-50: 253 244 255;
--color-primary-100: 250 232 255;
--color-primary-200: 245 208 254;
--color-primary-300: 240 171 252;
--color-primary-400: 232 121 249;
--color-primary-500: 217 70 239;
--color-primary-600: 192 38 211;
--color-primary-700: 162 28 175;
--color-primary-800: 134 25 143;
--color-primary-900: 112 26 117;
}
:root {
--color-primary-50: 249 250 251;
--color-primary-100: 243 244 246;
--color-primary-200: 229 231 235;
--color-primary-300: 209 213 219;
--color-primary-400: 156 163 175;
--color-primary-500: 107 114 128;
--color-primary-600: 75 85 99;
--color-primary-700: 55 65 81;
--color-primary-800: 31 41 55;
--color-primary-900: 31 41 55;
}
:root {
--color-primary-50: 240 253 244;
--color-primary-100: 220 252 231;
--color-primary-200: 187 247 208;
--color-primary-300: 134 239 172;
--color-primary-400: 74 222 128;
--color-primary-500: 34 197 94;
--color-primary-600: 22 163 74;
--color-primary-700: 21 128 61;
--color-primary-800: 22 101 52;
--color-primary-900: 20 83 45;
}
:root {
--color-primary-50: 238 242 255;
--color-primary-100: 224 231 255;
--color-primary-200: 199 210 254;
--color-primary-300: 165 180 252;
--color-primary-400: 129 140 248;
--color-primary-500: 99 102 241;
--color-primary-600: 79 70 229;
--color-primary-700: 67 56 202;
--color-primary-800: 55 48 163;
--color-primary-900: 49 4 6 129;
}
:root {
--color-primary-50: 247 254 231;
--color-primary-100: 236 252 203;
--color-primary-200: 217 249 157;
--color-primary-300: 190 242 100;
--color-primary-400: 163 230 53;
--color-primary-500: 132 204 22;
--color-primary-600: 101 163 13;
--color-primary-700: 77 124 15;
--color-primary-800: 63 98 18;
--color-primary-900: 54 83 20;
}
:root {
--color-primary-50: 250 250 250;
--color-primary-100: 245 245 245;
--color-primary-200: 229 229 229;
--color-primary-300: 212 212 212;
--color-primary-400: 163 163 163;
--color-primary-500: 115 115 115;
--color-primary-600: 82 82 82;
--color-primary-700: 64 64 64;
--color-primary-800: 38 38 38;
--color-primary-900: 23 23 23;
}
:root {
--color-primary-50: 255 247 237;
--color-primary-100: 255 237 213;
--color-primary-200: 254 215 170;
--color-primary-300: 253 186 116;
--color-primary-400: 251 146 60;
--color-primary-500: 249 115 22;
--color-primary-600: 234 88 12;
--color-primary-700: 194 65 12;
--color-primary-800: 154 52 18;
--color-primary-900: 124 45 18;
}
:root {
--color-primary-50: 253 242 248;
--color-primary-100: 252 231 243;
--color-primary-200: 251 207 232;
--color-primary-300: 249 168 212;
--color-primary-400: 244 114 182;
--color-primary-500: 236 72 153;
--color-primary-600: 219 39 119;
--color-primary-700: 190 24 93;
--color-primary-800: 157 23 77;
--color-primary-900: 131 24 67;
}
:root {
--color-primary-50: 250 245 255;
--color-primary-100: 243 232 255;
--color-primary-200: 233 213 255;
--color-primary-300: 216 180 254;
--color-primary-400: 192 132 252;
--color-primary-500: 168 85 247;
--color-primary-600: 147 51 234;
--color-primary-700: 126 34 206;
--color-primary-800: 107 33 168;
--color-primary-900: 88 28 135;
}
:root {
--color-primary-50: 254 242 242;
--color-primary-100: 254 226 226;
--color-primary-200: 254 202 202;
--color-primary-300: 252 165 165;
--color-primary-400: 248 113 113;
--color-primary-500: 239 68 68;
--color-primary-600: 220 38 38;
--color-primary-700: 185 28 28;
--color-primary-800: 153 27 27;
--color-primary-900: 127 29 29;
}
:root {
--color-primary-50: 255 241 242;
--color-primary-100: 255 228 230;
--color-primary-200: 254 205 211;
--color-primary-300: 253 164 175;
--color-primary-400: 251 113 133;
--color-primary-500: 251 113 133;
--color-primary-600: 225 29 72;
--color-primary-700: 190 18 60;
--color-primary-800: 159 18 57;
--color-primary-900: 136 19 55;
}
:root {
--color-primary-50: 240 249 255;
--color-primary-100: 224 242 254;
--color-primary-200: 186 230 253;
--color-primary-300: 125 211 252;
--color-primary-400: 56 189 248;
--color-primary-500: 14 165 233;
--color-primary-600: 2 132 199;
--color-primary-700: 3 105 161;
--color-primary-800: 7 89 133;
--color-primary-900: 12 74 110;
}
:root {
--color-primary-50: 248 250 252;
--color-primary-100: 241 245 249;
--color-primary-200: 226 232 240;
--color-primary-300: 203 213 225;
--color-primary-400: 148 163 184;
--color-primary-500: 100 116 139;
--color-primary-600: 71 85 105;
--color-primary-700: 51 65 85;
--color-primary-800: 30 41 59;
--color-primary-900: 15 23 42;
}
:root {
--color-primary-50: 250 250 249;
--color-primary-100: 245 245 244;
--color-primary-200: 231 229 228;
--color-primary-300: 214 211 209;
--color-primary-400: 168 162 158;
--color-primary-500: 120 113 108;
--color-primary-600: 87 83 78;
--color-primary-700: 68 64 60;
--color-primary-800: 41 37 36;
--color-primary-900: 28 25 23;
}
:root {
--color-primary-50: 240 253 250;
--color-primary-100: 204 251 241;
--color-primary-200: 153 246 228;
--color-primary-300: 94 234 212;
--color-primary-400: 45 212 191;
--color-primary-500: 20 184 166;
--color-primary-600: 13 148 136;
--color-primary-700: 15 118 110;
--color-primary-800: 17 94 89;
--color-primary-900: 19 78 74;
}
:root {
--color-primary-50: 245 243 255;
--color-primary-100: 237 233 254;
--color-primary-200: 221 214 254;
--color-primary-300: 196 181 253;
--color-primary-400: 167 139 250;
--color-primary-500: 139 92 246;
--color-primary-600: 124 58 237;
--color-primary-700: 109 40 217;
--color-primary-800: 91 33 182;
--color-primary-900: 76 29 149;
}
:root {
--color-primary-50: 254 252 232;
--color-primary-100: 254 249 195;
--color-primary-200: 254 240 138;
--color-primary-300: 253 224 71;
--color-primary-400: 250 204 21;
--color-primary-500: 234 179 8;
--color-primary-600: 202 138 4;
--color-primary-700: 161 98 7;
--color-primary-800: 133 77 14;
--color-primary-900: 113 63 18;
}
:root {
--color-primary-50: 250 250 250;
--color-primary-100: 244 244 245;
--color-primary-200: 228 228 231;
--color-primary-300: 212 212 216;
--color-primary-400: 161 161 170;
--color-primary-500: 113 113 122;
--color-primary-600: 82 82 91;
--color-primary-700: 63 63 70;
--color-primary-800: 39 39 42;
--color-primary-900: 24 24 27;
}
<?php
namespace App\Filament\Resources\ImportExportRequestResource\Pages;
use Exception;
use Throwable;
use Livewire\Livewire;
use App\Models\User\User;
use Filament\Pages\Actions;
use Filament\Facades\Filament;
use Filament\Forms\ComponentContainer;
use Illuminate\Database\Eloquent\Model;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords;
use Filament\Notifications\Actions\Action;
use Filament\Notifications\Actions\ActionGroup;
use App\Filament\Resources\ImportExportRequestResource;
class ListImportExportRequests extends ListRecords
{
protected static string $resource = ImportExportRequestResource::class;
protected function getActions(): array
{
return [
// \Filament\Pages\Actions\CreateAction::make()
// \Filament\Pages\Actions\Action::make('create_request')
\Filament\Pages\Actions\CreateAction::make('create_request')
->form([
\Filament\Forms\Components\TextInput::make('message')->statePath('message')
])
->submit('aaaaa') //NOCOMMIT
->beforeFormFilled(function ($data) {
$data['beforeFormFilled'] = 'beforeFormFilled';
$data['message'] = ($data['message'] ?? '') . 'beforeFormFilled';
\Log::info([$data, 'beforeFormFilled', microtime(true), __FILE__ . ':' . __LINE__]);//NOCOMMIT 1
static::sendNotification(
'beforeFormFilled',
'beforeFormFilled',
user: Filament::auth()->user()
);
return $data;
})
->afterFormFilled(function ($data) {
$data['afterFormFilled'] = 'afterFormFilled';
$data['message'] = ($data['message'] ?? '') . 'afterFormFilled';
\Log::info([$data, 'afterFormFilled', microtime(true), __FILE__ . ':' . __LINE__]);//NOCOMMIT 2
static::sendNotification(
'afterFormFilled',
'afterFormFilled',
user: Filament::auth()->user()
);
return $data;
})
->afterFormValidated(function ($data) {
$data['afterFormValidated'] = 'afterFormValidated';
$data['message'] = ($data['message'] ?? '') . 'afterFormValidated';
\Log::info([$data, 'afterFormValidated', microtime(true), __FILE__ . ':' . __LINE__]);//NOCOMMIT 3
static::sendNotification(
'afterFormValidated',
'afterFormValidated',
user: Filament::auth()->user()
);
return $data;
})
->mutateFormDataUsing(function ($data) {
$data['mutateFormDataUsing'] = 'mutateFormDataUsing';
$data['message'] = ($data['message'] ?? '') . 'mutateFormDataUsing';
return $data;
})
->before(function ($data) {
$data['before'] = 'before';
$data['message'] = ($data['message'] ?? '') . 'before';
\Log::info([$data, 'before', microtime(true), __FILE__ . ':' . __LINE__]);//NOCOMMIT 4
static::sendNotification(
'before',
'before',
user: Filament::auth()->user()
);
return $data;
})
->action(function ($data,ComponentContainer $form) {
// dd($data,__FILE__ . ':' . __LINE__);
// $this->formData(array_merge($data, [
// 'action' => 'action',
// ]));
$data['message'] = ($data['message'] ?? '') . 'action';
\Log::info([$data, 'action', microtime(true), __FILE__ . ':' . __LINE__]);//NOCOMMIT 5
static::sendNotification(
'action',
'action',
user: Filament::auth()->user()
);
return $data;
})
->after(function ($data) {
static::sendNotification(
'after',
'after',
);
// redirect()->intended(Filament::getUrl());
return $data;
}),
];
}
/**
* function sendNotification
*
* @param string $title
* @param string $body
* @param string $color
* @param ?User $user
* @param null|array|ActionGroup|Closure $actions
*
* @return void
*/
public static function sendNotification(
string $title,
string $body,
string $color = 'success',
?User $user = null,
null|array|ActionGroup|Closure $actions = null,
): void {
if (!$title || !$body) {
return;
}
$notification = Notification::make()
->title($title)
->body($body);
$color = in_array($color, ['success', 'danger']) ? $color : 'success';
$notification = $notification
->{$color}();
if ($actions) {
$notification = $notification->actions($actions);
}
if ($user) {
$notification = $notification->sendToDatabase($user);
return;
}
$notification->send();
}
}
->beforeStateDehydrated // Antes de salvar no banco

Custom query on select

  • vendor/filament/forms/docs/03-fields.md v2
Select::make('authorId')
    ->searchable()
    ->getSearchResultsUsing(fn (string $search) => User::where('name', 'like', "%{$search}%")->limit(50)->pluck('name', 'id'))
    ->getOptionLabelUsing(fn ($value): ?string => User::find($value)?->name),

Selecionar ou criar um novo (útil para clientes, fornecedores, produtos etc)

    // Fica com um + na frente da seleção (abre uma modal para cadastro de um novo item)
    // Tem o editOptionForm() também
    Forms\Components\Select::make('wallet_id')
        ->relationship('wallet', 'id')
        ->searchable()
        ->preload()
        ->createOptionForm([
            Forms\Components\TextInput::make('name')
                ->required()
                ->maxLength(255),
            Forms\Components\TextInput::make('email')
                ->label('Email address')
                ->email()
                ->required()
                ->maxLength(255),
            Forms\Components\TextInput::make('phone')
                ->label('Phone number')
                ->tel()
                ->required(),
        ])
        ->required(),
// On resource...
public static function table(Table $table): Table
{
    return $table
        ->columns([
            //
        ])
        ->filters([
            //
        ])
        ->actions([
            \Filament\Tables\Actions\ActionGroup::make([
                \Filament\Tables\Actions\ViewAction::make(),
                \Filament\Tables\Actions\EditAction::make(),
                \Filament\Tables\Actions\DeleteAction::make(),
            ]),
        ])
        ->bulkActions([
            //
        ]);
}

Customizando a label da opções de um select

Forms\Components\Select::make('composicaoReferencia')
    ->hidden(fn (callable $get) => !$get('temComposicaoRef'))
    ->relationship('composicaoReferencia', 'descricao_curta')
    ->getOptionLabelFromRecordUsing(fn(Model $record) => $record?->descricao_curta . ' - ' . $record?->id)
    ->columnSpanFull()
    ->searchable(),

Select search (v3)

Forms\Components\Select::make('visible_to_type_user')
    ->label(__('User'))
    ->live()
    ->visible(
        fn(callable $get) => boolval(
            $get('visible_to_type') == DocumentVisibleToType::USER->value
        )
    )
    ->searchable()
    ->getSearchResultsUsing(
        fn(string $search): array => User::where('name', 'like', "%{$search}%")
            ->limit(30)
            ->pluck('name', 'id')
            ->toArray()
    )
    ->options(
        fn(): array => User::limit(10)
            ->pluck('name', 'id')
            ->toArray()
    )
    ->preload()
    ->getOptionLabelUsing(fn($value): ?string => User::find($value)?->name),

Auto generated slug

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\TextInput::make('name')
                    ->label('Nome')
                    ->required()
                    ->maxLength(255)
                    ->live(onBlur: true)
                    ->afterStateUpdated(function (string $operation, $state, Forms\Set $set) {
                        if ($operation !== 'create') {
                            return;
                        }

                        $set('slug', str($state)->slug()->prepend('-')->prepend(uniqid())->slug());
                    })
                    ->columnSpan(2),

                Forms\Components\TextInput::make('slug')
                    ->label('UID')
                    ->disabled()
                    ->dehydrated()
                    ->required()
                    ->maxLength(255)
                    ->unique(Form::class, 'slug', ignoreRecord: true)
                    ->columnSpan(2),
            ]);
    }
new \Illuminate\Support\HtmlString('<div>Content</div>');
$heroicons = [
    'boolean' => [
        'heroicon-o-badge-check',
        'heroicon-o-check-circle',
        'heroicon-o-check',
        'heroicon-o-x',
        'heroicon-o-x-circle',
    ],
];

composer require guava/filament-icon-picker

Dizer qual será a coluna usada para identificar o Record

// app/Filament/Resources/ImportExportRequestResource/Pages/ListImportExportRequests.php
use Illuminate\Database\Eloquent\Model;

class ListImportExportRequests extends ListRecords
{
    protected static string $resource = ImportExportRequestResource::class;

    public function getTableRecordKey(Model $record): string
    {
        return 'uuid';
    }
}

Muito útil quando nossa query é fora do padrão do filament como a abaixo

// app/Filament/Resources/ImportExportRequestResource.php
use Illuminate\Database\Eloquent\Builder;
class ImportExportRequestResource extends Resource
{
    protected static ?string $model = ImportExportRequest::class;
    public static function getEloquentQuery(): Builder
    {
        /**
         * @var Builder $query
         */
        $query = static::getModel()::query()
            ->select([
                // 'id',
                'uuid',
            ]);

        return $query;
    }
}

// .../grupo-gps/.../comptrade-web.../app/Filament/Resources/Book/BookResource/Pages/CreateBook.php ~250
protected function getTableBulkActions(): array
    {
        return [
            Tables\Actions\BulkAction::make('gerar')
                ->requiresConfirmation()
                ->deselectRecordsAfterCompletion()
                ->modalHeading('Gerar Book de PPT')
                ->label('Gerar Book de Power Point')
                ->modalContent(fn () => new HtmlString('<div>Antes de prosseguir, preencha o campo abaixo:</div>'))
                ->modalSubheading('Máximo de registros permitidos por book: 300')
                ->size(200)
                ->icon('heroicon-s-presentation-chart-line')
                ->form([
                    TextInput::make('name')
                        ->label('Nome do Book')
                        ->required(),

                    Forms\Components\Select::make('book_template_id')
                        ->label('Template')
                        ->required()
                        ->options(BookTemplate::pluck('nome', 'id'))
                        ->searchable(),
                ])
                ->deselectRecordsAfterCompletion(false)
                ->action(function (Collection $records, array $data) {
                    if(count($records) > 300){
                        Notification::make()
                            ->title('Registros selecionados atingiu o valor máximo.')
                            ->icon('heroicon-o-clock')
                            ->danger()
                            ->body('Você só pode gerar books de até 300 registros.')
                            ->iconColor('warning')
                            ->send()
                            ->sendToDatabase(auth()->user());
                        return;
                    }
                    DB::beginTransaction();

                    try {
                        $book = Book::query()->create([
                            'nome' => $data['name'],
                            'status' => 1,
                            'book_template_id' => $data['book_template_id'],
                        ]);

                        foreach ($records as $record) {
                            BookImage::query()->firstOrCreate([
                                'book_id' => $book['id'],
                                'file_id' => $record->id,
                            ]);
                        }
                    } catch (\Exception $exception) {
                        DB::rollBack();
                        dd($exception->getMessage());
                    }
                    DB::commit();

                    Notification::make()
                        ->title('Seu book está sendo gerado.')
                        ->icon('heroicon-o-clock')
                        ->warning()
                        ->body('Você será notificado quando terminarmos :)')
                        ->iconColor('warning')
                        ->send()
                        ->sendToDatabase(auth()->user());

                    ProcessBook::dispatch($book, auth()->user());
                })
            ->successNotificationTitle('Seu book está sendo gerado'),
        ];
    }
class CreateBook extends \Filament\Resources\Pages\CreateRecord
{
    protected function getTableQuery()
    {
        return File::query()
            ->select([
                //...
            ]);
    }

    //...
    protected function getDefaultTableSortColumn(): ?string
    {
        return 'roteiros.visitado_em';
    }

    protected function getDefaultTableSortDirection(): ?string
    {
        return 'desc';
    }
}

getEloquentQuery

class UserResource extends \Filament\Resources\Resource
{
    public static function getEloquentQuery(): Builder
    {
        return static::getModel()::query()
            ->select([
                //..
            ]);
    }
}
    public static function getModelLabel(): string
    {
        return __('resources.category.label.singular');
    }

    public static function getPluralModelLabel(): string
    {
        return __('resources.category.label.plural');
    }
  • Rotas dinâmicas usando as resources do Filament:
    $this->getResource()::getUrl('index');
    $this->getResource()::getUrl('view', ['record' => $this->record]);
    $this->getResource()::getUrl('edit', ['record' => $this->record]);

    // Ou
    MinhaResource::getUrl('view', ['record' => $this->record]);
    MinhaResource::getUrl('edit', ['record' => $this->record]);


    public static function getPages(): array
    {
        return [
            'index' => Pages\ListAlgumItem::route('/'),
            'create' => Pages\CreatAlgumItem::route('/create'),
            'edit' => Pages\EdiAlgumItem::route('/{record}/edit'),
            'view' => Pages\EdiAlgumItem::route('/{record}/view'),
        ];
    }
    // vendor/ryangjchandler/filament-feature-flags/src/Resources/FeatureFlagResource.php
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Group::make([
                    //
                ])
                    ->columnSpan(4),
                Card::make([
                    //
                ])
                    ->columnSpan(2),
            ])
            ->columns(6);
    }
FileUpload::make('Thumb')
    // ->image()
    ->acceptedFileTypes([
        'image/*', // O mesmo que efeito que->image()
    ])
// https://filamentphp.com/docs/2.x/forms/fields#date-time-picker
\Filament\Forms\Components\DatePicker::make('date_of_birth')
    ->minDate(now()->subYears(150))
    ->maxDate(now()),

    use Filament\Forms\Components\DateTimePicker;

DateTimePicker::make('date')
    ->label('Appointment date')
    ->minDate(now())
    ->maxDate(Carbon::now()->addDays(30))
    ->disabledDates(['2022-10-02', '2022-10-05', '2022-10-15'])
// Com opção 'Select all'
\Filament\Forms\Components\CheckboxList::make('technologies')
->options([
    'tailwind' => 'Tailwind CSS',
    'alpine' => 'Alpine.js',
    'laravel' => 'Laravel',
    'livewire' => 'Laravel Livewire',
])
->bulkToggleable(),

Grid

use Filament\Forms\Components\Grid;

Grid::make(1) // Força grids com 1 coluna apenas (full)
    ->schema([
        //
    ]),

Grid::make(3) // Força grids com 3 colunas
    ->schema([
        //
    ]),
Grid::make() // Grids responsivas com 2 colunas em md e lg
    ->schema([
        //
    ]),

Input full

Grid::make(3)
->schema([
    TextInput::make('slug')
        ->columnSpanFull() // Pega a coluna inteira
        ->unique(Post::class, 'slug')
        ->disabled(fn (Page $livewire) => $livewire instanceof EditRecord)
        ->dehydrated(fn (Page $livewire) => $livewire instanceof EditRecord),
]),

Código HTML

Placeholder::make('open_child_modal')
    ->disableLabel()
    ->content(
        new HtmlString('Click <button onclick="Livewire.emit(\'modal:open\', \'create-user-child\')" type="button" class="text-primary-500">here</button> to open a child modal🤩')
    ),

Input mask

https://filamentphp.com/docs/2.x/forms/fields#input-masking

use Filament\Forms\Components\TextInput;

TextInput::make('name')
    ->mask(fn (TextInput\Mask $mask) => $mask->pattern('+{7}(000)000-00-00'))

// TEM MAIS LÁ
// Enum mask
// Money mask
// etc

Páginas customizadas (alternativas ou adicionais ao edit/create/view etc)

// app/Filament/Resources/PostResource.php
public static function getPages(): array
{
    return [
        'index' => Pages\ListPosts::route('/'),
        'create' => Pages\CreatePost::route('/create'),
        'edit' => Pages\EditPost::route('/{record}/edit'),

        // Acessa: http://0.0.0.0:8000/admin/posts/1/custom
        'custom' => Pages\CustomPagePost::route('/{record}/custom'), // <<<<<====
    ];
}

Custom View

// app/Filament/Resources/PostResource/Pages/CustomPagePost.php

// Forma #1 - via atributo:
protected static string $view = 'my.custom.view';

// Forma #2 - via método render:
public function render(): View
{
    // Way 2.1
    return view(static::$view, $this->getViewData())
        ->layout(static::$layout, $this->getLayoutData());

    // Way 2.2
    return view('my.custom.view', [
        // 'data' => $this->data, // Optional???
    ])->layout(static::$layout, $this->getLayoutData());
}
public static function getPluralModelLabel(): string
{
    return __('filament/resources/customer.plural_label');
}
  • Rotas dinâmicas usando as resources do Filament:
$this->getResource()::getUrl('view', ['record' => $this->record]);


MinhaResource::getUrl('view', ['record' => $this->record]);
// vendor/filament/tables/src/Concerns/CanPaginateRecords.php:46 ~>
// vendor/filament/tables/src/Concerns/CanPaginateRecords.php:65 <~

    protected function getTableRecordsPerPageSelectOptions(): array
    {
        return config('tables.pagination.records_per_page_select_options') ?? [5, 10, 25, 50, -1];
    }

    protected function getDefaultTableRecordsPerPageSelectOption(): int
    {
        $perPage = session()->get(
            $this->getTablePerPageSessionKey(),
            $this->defaultTableRecordsPerPageSelectOption ?: config('tables.pagination.default_records_per_page'),
        );

        if (in_array($perPage, $this->getTableRecordsPerPageSelectOptions())) {
            return $perPage;
        }

        session()->remove($this->getTablePerPageSessionKey());

        return $this->getTableRecordsPerPageSelectOptions()[0];
    }

limit words and text

use Filament\Tables\Columns\TextColumn;

TextColumn::make('description')->limit(50);

TextColumn::make('description')->words(10);

Custom column view

// View column
// You may render a custom view for a cell using the view() method:

use Filament\Tables\Columns\ViewColumn;

ViewColumn::make('status')->view('filament.tables.columns.status-switcher');

// Inside your view, you may retrieve the state of the cell using the $getState() method:

<div>
    {{ $getState() }}
</div>

Render HTML (link,...) in a field label()

use Illuminate\Support\HtmlString;

Checkbox::make('accept')
    ->label(fn () => new HtmlString('I accept the <a href="" target="_blank">terms and conditions</a>'))
    ->required(),

Roles/permissins/policies

// ...
use Spatie\Permission\Models\Permission;
class RolesAndPermissionsSeeder extends Seeder
{
    public function run()
    {
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
        Permission::firstOrCreate(['name' => 'access filament']);
    }
}
// ...


class User extends Authenticatable implements \Filament\Models\Contracts\FilamentUser
{
    public function canAccessFilament(): bool
    {
        return $this->can('access filament');
    }
}
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Blade;
Filament::registerRenderHook('scripts.end', fn () => Blade::render("@livewire('livewire-ui-spotlight')"));

Alterar a estrutura de um componente/resource/input

->tap(function($instance) {
    $instance->macro('getType', fn() => 'getType');
    dd($instance?->getType(), $instance);//NOCOMMIT
    return $instance;
})
// vendor/filament/support/src/Components/Component.php
namespace Filament\Support\Components;

use Filament\Support\Concerns\Configurable;
use Filament\Support\Concerns\EvaluatesClosures;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Support\Traits\Tappable;

abstract class Component
{
    use Configurable;
    use EvaluatesClosures;
    use Macroable;
    use Tappable;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment