#12 FilamentPHP応用

カスタムテーブルカラムを作る——AbstractColumnを継承した独自列表示

カスタムテーブルカラムが必要な場面

標準のTextColumnImageColumnBadgeColumnでは表現しきれないUIが必要になる場合があります。例えばプログレスバー・スター評価・カラーチップ・複合的な情報をコンパクトに表示するカラムなどです。

カスタムカラムを作ることで、テーブル定義のコードを簡潔に保ちながら独自のUI表現が実現できます。

生成コマンドとファイル構成

php artisan make:filament-table-column ProgressBarColumn

生成ファイル:

app/Tables/Columns/ProgressBarColumn.php
resources/views/tables/columns/progress-bar-column.blade.php

Columnクラスの実装

namespace App\Tables\Columns;

use Filament\Tables\Columns\Column;

class ProgressBarColumn extends Column
{
    protected string $view = 'tables.columns.progress-bar-column';

    // 最大値(デフォルト100)
    protected int|float $maxValue = 100;

    // 色の閾値設定
    protected array $colorThresholds = [];

    public function maxValue(int|float $max): static
    {
        $this->maxValue = $max;
        return $this;
    }

    /**
     * 値に応じた色を設定
     * 例: ->colorThresholds(['danger' => 30, 'warning' => 70, 'success' => 100])
     */
    public function colorThresholds(array $thresholds): static
    {
        $this->colorThresholds = $thresholds;
        return $this;
    }

    public function getMaxValue(): int|float
    {
        return $this->maxValue;
    }

    public function getColorThresholds(): array
    {
        return $this->colorThresholds;
    }
}

Bladeテンプレートの実装

@php
    $state = $getState() ?? 0;
    $maxValue = $getMaxValue();
    $percentage = $maxValue > 0 ? min(100, ($state / $maxValue) * 100) : 0;
    $thresholds = $getColorThresholds();

    // 閾値から色を決定
    $color = 'primary';
    foreach ($thresholds as $colorName => $threshold) {
        if ($percentage <= $threshold) {
            $color = $colorName;
            break;
        }
    }

    $colorClasses = match($color) {
        'danger'  => 'bg-danger-500',
        'warning' => 'bg-warning-500',
        'success' => 'bg-success-500',
        'info'    => 'bg-info-500',
        default   => 'bg-primary-500',
    };
@endphp

<div class="w-full min-w-[80px]">
    <div class="flex items-center gap-2">
        <div class="flex-1 bg-gray-200 dark:bg-gray-700 rounded-full h-2">
            <div
                class="{{ $colorClasses }} h-2 rounded-full transition-all duration-300"
                style="width: {{ $percentage }}%"
            ></div>
        </div>
        <span class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
            {{ number_format($state) }} / {{ number_format($maxValue) }}
        </span>
    </div>
</div>

使用例

use App\Tables\Columns\ProgressBarColumn;

public function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('name')
                ->label('タスク名')
                ->searchable(),

            ProgressBarColumn::make('progress')
                ->label('進捗')
                ->maxValue(100)
                ->colorThresholds([
                    'danger'  => 30,
                    'warning' => 70,
                    'success' => 100,
                ])
                ->sortable(),

            ProgressBarColumn::make('score')
                ->label('スコア')
                ->maxValue(1000)
                ->sortable(),
        ]);
}

ソートのサポート

カラムが->sortable()に対応するためには、対応するデータベースカラムが存在している必要があります。カスタムカラムでもデフォルトの->sortable()は標準で機能します。

複雑なソートが必要な場合:

ProgressBarColumn::make('progress')
    ->sortable(query: function (Builder $query, string $direction): Builder {
        return $query->orderBy('progress', $direction)
                     ->orderBy('updated_at', $direction);
    })

仮想カラム(計算値)への対応

データベースにない計算値を表示したい場合は->state()と組み合わせます。

ProgressBarColumn::make('completion_rate')
    ->label('完了率')
    ->state(fn (Project $record): float =>
        $record->tasks_total > 0
            ? ($record->tasks_done / $record->tasks_total) * 100
            : 0
    )
    ->maxValue(100)
    ->colorThresholds(['danger' => 30, 'warning' => 70, 'success' => 100])

コツ・注意点・ハマりポイント

コツ: Bladeテンプレート内では$getState()nullを返す可能性があるため、常にnullチェックやデフォルト値を設定してください。

注意点: カスタムカラムのBladeは行ごとに繰り返しレンダリングされます。複雑なPHP計算をBlade内に書くとパフォーマンスに影響するため、重い処理はモデルのアクセサやEloquentスコープに移してください。

ハマりポイント: カラムのビューパスはresources/views/からの相対パスをドット記法で指定します。tables/columns/progress-bar-column.blade.phpなら'tables.columns.progress-bar-column'です。パッケージとして公開する場合はビューのネームスペースを設定してください。

まとめ

Columnクラスを継承してBladeテンプレートを実装するだけで、テーブルに独自の列表示を追加できます。プログレスバー・評価スター・カスタムバッジなど、標準カラムでは難しい表現もFluentAPIで直感的に設定できます。