0

How do I implement a custom comparator function inside of the sortable() function in laravel filament? I have three priorities: high, medium and low and I want them to be sorted as high, medium and low or vice versa, not by ascending or descending order, which the orderBy function does. I want it to be within the BadgeColumn of the $table column.

<?php

namespace App\Filament\Resources;

use App\Filament\Resources\IdeaResource\Pages;
use App\Filament\Resources\IdeaResource\RelationManagers;
use App\Models\Idea;
use App\Models\User;
use DeepCopy\Filter\Filter;
use Filament\Forms;
use Filament\Forms\Components\Actions\Modal\Actions\Action;
use Filament\Forms\Components\Select;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Filament\Tables\Columns\BadgeColumn;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\DatePicker;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter as FiltersFilter;

class IdeaResource extends Resource
{
    protected static ?string $model = Idea::class;

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

public static function form(Form $form): Form
{
    return $form
        ->schema([
            Forms\Components\Card::make()
                ->schema([
                    Forms\Components\TextInput::make('title')
                        ->label('Title')
                        ->required(),

                    DatePicker::make('publishing_date')
                        ->label('Publishing Date')
                        ->minDate('today'),

                    // Forms\Components\MarkdownEditor::make('short_description')
                    //     ->label('Short Description')
                    //     ->columnSpan("full")
                    //     ->required(),

                    Select::make('priority')
                        ->options([
                            'high' => 'High',
                            'medium' => 'Medium',
                            'low' => 'Low'
                        ])->required(),
                ])
                ->columns(2)
                ->columnSpan(['lg' => fn (?Idea $record) => $record === null ? 3 : 2]),

            Forms\Components\Card::make()
                ->schema([
                    Forms\Components\Placeholder::make('created_at')
                        ->label('Created at')
                        ->content(fn (Idea $record): string => $record->created_at->diffForHumans()),

                    Forms\Components\Placeholder::make('updated_at')
                        ->label('Last modified at')
                        ->content(fn (Idea $record): string => $record->updated_at->diffForHumans()),
                ])
                ->columnSpan(['lg' => 1])
                ->hidden(fn (?Idea $record) => $record === null),
        ])
        ->columns(3);
}

public static function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('title')
                ->label('Title')
                ->searchable()
                ->sortable(),
            Tables\Columns\TextColumn::make('publishing_date')
                ->label('Publishing Date')
                ->searchable()
                ->date()
                ->sortable(),
            BadgeColumn::make('priority')
                ->label('Priority')
                ->colors([
                    'primary',
                    'danger' => 'high',
                    'warning' => 'medium',
                    'success' => 'low',
                ])->sortable(query: function (Builder $query, string $direction): Builder {
                    return $query
                    ->orderByRaw("FIELD(priority, 'high', 'medium', 'low') ASC");
                    // ->orderByRaw("FIELD(priority, 'low', 'medium', 'high') DESC");
                    // ->orderByCase("
                    //     WHEN priority='high' then 1
                    //     WHEN priority='medium' then 2
                    //     WHEN priority='low' then 3
                    //     ");
                    // ->orderBy('priority', 'asc');
                }),
            ])
        ->filters([
            // 
        ])
        ->actions([
            Tables\Actions\Action::make('Push To Task')
                ->url(fn (Idea $record): string => route('idea', $record))
                ->icon('heroicon-s-check'),
            Tables\Actions\EditAction::make()
                ->icon('heroicon-s-pencil'),
        ])
        ->bulkActions([
            Tables\Actions\DeleteBulkAction::make(),
        ]);
}

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

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

}

This is the priority column, needs to be sorted via high, medium and low when the user clicks the small button at the priority column.

  • I'm sure there is. But your question does not have enough information. I have no idea what this means: "depending on when the user clicks the button". I do not understand when the user is given the choice to select their desired priority. – Misunderstood Sep 16 '22 at 06:52
  • Edited the question, added the image of the column that I need to sort, please have a look. – Shreyes Srivastava Sep 16 '22 at 07:21
  • I saw the image before. But there is no correlation between the Priority selection and your code. When the Priority selection is made, what is the variable that is assigned the Priority value? What is the "small button"? Why are there two "low" priorities? – Misunderstood Sep 16 '22 at 07:51
  • Edited and included the whole code again. The two "low" priorities are just test posts that have been assigned low priority. – Shreyes Srivastava Sep 16 '22 at 09:18

1 Answers1

2

I don't think your logic makes sense, since sorting is generally used to scan a table in a certain way, I believe what you need is filtering based on a category related to your Idea model.

Filament has a ternary filter that can be used in your case to filter out the priorities.

Ternary filters allow you to quickly create a filter which has three states - usually true, false and blank.

Ternary filters

Example using your scenario would be as follows:

TernaryFilter::make('priority')
    ->placeholder('High')
    ->trueLabel('Medium')
    ->falseLabel('Low')
    ->queries(
        true: fn (Builder $query) => $query->where('priority', 'medium'),
        false: fn (Builder $query) => $query->where('priority', 'low'),
        blank: fn (Builder $query) => $query->where('priority', 'high'),
    )

Disclaimer: This method is not being used in its intended purpose, but could be useful in your case. Cheers.