#04 FilamentPHP基礎

テーブルカラムとフィルター——一覧画面を強化する

テーブルの構成要素

Filamentのテーブルは table() メソッドの中で以下の要素を定義します。

Table
├── columns()      → 表示カラム
├── filters()      → フィルター(絞り込み)
├── actions()      → 行アクション(編集・削除ボタン等)
└── bulkActions()  → 一括アクション(一括削除等)

すべて Tables\ColumnsTables\FiltersTables\Actions 名前空間以下にあります。


TextColumn

最も基本的なカラムです。

use Filament\Tables\Columns\TextColumn;

// 基本
TextColumn::make('title')
    ->label('タイトル'),

// 検索・ソート対応
TextColumn::make('title')
    ->label('タイトル')
    ->searchable()      // テーブル上部に検索ボックスが表示される
    ->sortable(),       // ヘッダークリックでソート

// 文字数制限
TextColumn::make('content')
    ->label('本文')
    ->limit(80)         // 80文字で切り捨て
    ->tooltip(fn ($record) => $record->content), // ホバーで全文表示

// 折り返し表示
TextColumn::make('description')
    ->wrap(),           // テキストを折り返す

// フォーマット
TextColumn::make('price')
    ->money('JPY'),     // ¥1,000 形式

TextColumn::make('published_at')
    ->dateTime('Y/m/d H:i')  // 日時フォーマット
    ->since(),               // "3時間前" のような相対表示

// 複数カラムを合わせて検索
TextColumn::make('name')
    ->searchable(query: function ($query, string $search) {
        $query->where('first_name', 'like', "%{$search}%")
              ->orWhere('last_name', 'like', "%{$search}%");
    }),

BadgeColumn(TextColumnのバッジ表示)

v5ではTextColumnに ->badge() を追加することでバッジ表示ができます。

TextColumn::make('status')
    ->label('ステータス')
    ->badge()
    ->color(fn (string $state): string => match ($state) {
        'draft'     => 'gray',
        'review'    => 'warning',
        'published' => 'success',
        'archived'  => 'danger',
    })
    ->formatStateUsing(fn (string $state): string => match ($state) {
        'draft'     => '下書き',
        'review'    => 'レビュー中',
        'published' => '公開',
        'archived'  => 'アーカイブ',
        default     => $state,
    }),

バッジに使えるカラー:primary / secondary / success / warning / danger / info / gray


ImageColumn

use Filament\Tables\Columns\ImageColumn;

ImageColumn::make('thumbnail')
    ->label('サムネイル')
    ->disk('public')
    ->size(60)              // 幅・高さ60px(正方形)
    ->square(),             // 正方形クリップ

// アバター(円形)
ImageColumn::make('avatar')
    ->circular(),

// サイズ個別指定
ImageColumn::make('thumbnail')
    ->width(120)
    ->height(80),

IconColumn

真偽値や状態をアイコンで表示します。

use Filament\Tables\Columns\IconColumn;

// 真偽値(チェック/バツ)
IconColumn::make('is_published')
    ->label('公開')
    ->boolean(),

// カスタムアイコンと色
IconColumn::make('status')
    ->icon(fn (string $state): string => match ($state) {
        'draft'     => 'heroicon-o-pencil',
        'published' => 'heroicon-o-check-circle',
        'archived'  => 'heroicon-o-archive-box',
    })
    ->color(fn (string $state): string => match ($state) {
        'draft'     => 'gray',
        'published' => 'success',
        'archived'  => 'warning',
    }),

ToggleColumn

一覧画面上で直接真偽値を切り替えられるカラムです。

use Filament\Tables\Columns\ToggleColumn;

ToggleColumn::make('is_active')
    ->label('有効'),

これだけでテーブル上にトグルスイッチが表示され、クリックするとその場でDBが更新されます。


searchable と sortable の詳細

// 関連テーブルのカラムも検索可能
TextColumn::make('author.name')
    ->label('著者')
    ->searchable(isIndividual: true),  // 個別の検索ボックスを表示

// カスタムソート
TextColumn::make('full_name')
    ->sortable(query: function ($query, string $direction) {
        $query->orderBy('last_name', $direction)
              ->orderBy('first_name', $direction);
    }),

フィルター

->filters() でテーブルの絞り込み機能を追加します。

SelectFilter

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('status')
    ->label('ステータス')
    ->options([
        'draft'     => '下書き',
        'published' => '公開',
        'archived'  => 'アーカイブ',
    ]),

// リレーションから選択肢を生成
SelectFilter::make('category_id')
    ->label('カテゴリ')
    ->relationship('category', 'name')
    ->searchable()
    ->preload(),

// 複数選択フィルター
SelectFilter::make('tags')
    ->relationship('tags', 'name')
    ->multiple()
    ->preload(),

TernaryFilter

3択(すべて/はい/いいえ)のフィルターです。

use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('is_published')
    ->label('公開状態')
    ->trueLabel('公開のみ')
    ->falseLabel('未公開のみ')
    ->nullable(),       // null値も扱う場合

// カスタムクエリ
TernaryFilter::make('has_thumbnail')
    ->label('サムネイル')
    ->trueLabel('あり')
    ->falseLabel('なし')
    ->queries(
        true:  fn ($query) => $query->whereNotNull('thumbnail'),
        false: fn ($query) => $query->whereNull('thumbnail'),
    ),

TrashedFilter(ソフトデリート対応)

use Filament\Tables\Filters\TrashedFilter;

// Postモデルに SoftDeletes を使っている場合
TrashedFilter::make(),

モデル側の準備:

// 📁 app/Models/Post.php
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
    // ...
}

マイグレーションに softDeletes() も追加します。

$table->softDeletes(); // deleted_at カラムを追加

フィルターをまとめて定義する

public static function table(Table $table): Table
{
    return $table
        ->columns([...])
        ->filters([
            SelectFilter::make('status')
                ->options([
                    'draft'     => '下書き',
                    'published' => '公開',
                ]),

            SelectFilter::make('category_id')
                ->relationship('category', 'name')
                ->label('カテゴリ'),

            TernaryFilter::make('is_published')
                ->label('公開'),

            TrashedFilter::make(),
        ])
        ->filtersLayout(FiltersLayout::AboveContent); // フィルターを表の上に表示
}

デフォルトソートとページネーション

->defaultSort('created_at', 'desc')  // デフォルトは作成日降順

->paginated([10, 25, 50, 100])       // ページあたりの件数の選択肢
->defaultPaginationPageOption(25)    // デフォルトは25件

// ページネーション無効(全件表示)
->paginated(false)

一括アクション(BulkAction)

チェックボックスで複数行を選択して一括操作するボタンです。

->bulkActions([
    Tables\Actions\BulkActionGroup::make([
        // 一括削除(標準)
        Tables\Actions\DeleteBulkAction::make(),

        // ソフトデリートの復元
        Tables\Actions\RestoreBulkAction::make(),
        Tables\Actions\ForceDeleteBulkAction::make(),

        // カスタム一括アクション
        Tables\Actions\BulkAction::make('publish')
            ->label('一括公開')
            ->icon('heroicon-o-check')
            ->color('success')
            ->action(function (Collection $records) {
                $records->each(function ($record) {
                    $record->update(['is_published' => true]);
                });
            })
            ->requiresConfirmation()  // 確認ダイアログを表示
            ->deselectRecordsAfterCompletion(),
    ]),
])

行アクション(Action)

各行の右端に表示されるボタンです。

->actions([
    Tables\Actions\ViewAction::make(),   // 詳細表示
    Tables\Actions\EditAction::make(),   // 編集
    Tables\Actions\DeleteAction::make(), // 削除

    // カスタムアクション
    Tables\Actions\Action::make('publish')
        ->label('公開')
        ->icon('heroicon-o-check-circle')
        ->color('success')
        ->visible(fn ($record) => ! $record->is_published)
        ->action(function ($record) {
            $record->update([
                'is_published' => true,
                'published_at' => now(),
            ]);
        })
        ->requiresConfirmation()
        ->modalHeading('記事を公開しますか?')
        ->modalDescription('公開すると一般ユーザーに表示されます。')
        ->modalSubmitActionLabel('公開する'),
])

まとめ

  • TextColumn->searchable() / ->sortable() / ->limit() / ->money() などで表示を制御
  • ->badge() でバッジ表示、->color() で条件付きカラー
  • ImageColumn->circular() でアバター表示
  • ToggleColumn で一覧上から直接値を編集できる
  • SelectFilter / TernaryFilter / TrashedFilter で絞り込み
  • ->defaultSort() / ->paginated() でテーブルの動作を設定
  • BulkAction で複数行への一括操作ボタンを追加

次回はリレーションを持つリソースの扱い方を学びます。