#02 FilamentPHP基礎

はじめてのリソース——テーブルとフォームを作る

リソースとは何か

Filamentにおけるリソース(Resource)は、Laravelのモデルに対応するCRUD操作をまとめたクラスです。1つのリソースが「一覧・作成・編集・削除」という4つの操作を担います。

PostResource
├── 一覧ページ (ListPosts)    → GET /admin/posts
├── 作成ページ (CreatePost)   → GET /admin/posts/create
├── 編集ページ (EditPost)     → GET /admin/posts/{record}/edit
└── 削除ボタン               → DELETE /admin/posts/{record}

Railsの scaffold やLaravel Novaの Resource と似た概念ですが、Filamentのリソースは PHPコードだけで完結 するのが特徴です。Bladeテンプレートを書く必要はありません。


Postモデルを準備する

まずリソースの土台となるモデルとマイグレーションを作成します。

php artisan make:model Post -m

マイグレーションファイルを編集します。

<?php
// 📁 database/migrations/xxxx_create_posts_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content')->nullable();
            $table->boolean('is_published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
php artisan migrate

Postモデルに fillable を設定します。

<?php
// 📁 app/Models/Post.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title',
        'content',
        'is_published',
        'published_at',
    ];

    protected $casts = [
        'is_published' => 'boolean',
        'published_at' => 'datetime',
    ];
}

リソースを生成する

php artisan make:filament-resource Post --generate

--generate オプションを付けると、モデルのカラムをもとにフォームとテーブルを自動生成してくれます。

生成されるファイル:

app/Filament/Resources/
└── PostResource/
    ├── PostResource.php          ← メインファイル
    └── Pages/
        ├── ListPosts.php         ← 一覧ページ
        ├── CreatePost.php        ← 作成ページ
        └── EditPost.php          ← 編集ページ

PostResource.php の構造

生成された PostResource.php を確認しましょう。

<?php
// 📁 app/Filament/Resources/PostResource.php

namespace App\Filament\Resources;

use App\Filament\Resources\PostResource\Pages;
use App\Models\Post;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;

class PostResource extends Resource
{
    // 対応するEloquentモデル
    protected static ?string $model = Post::class;

    // サイドバーに表示するアイコン(Heroicons)
    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    // フォームの定義
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\TextInput::make('title')
                    ->required()
                    ->maxLength(255),
                Forms\Components\Textarea::make('content')
                    ->columnSpanFull(),
                Forms\Components\Toggle::make('is_published'),
                Forms\Components\DateTimePicker::make('published_at'),
            ]);
    }

    // テーブル(一覧)の定義
    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('title')
                    ->searchable(),
                Tables\Columns\IconColumn::make('is_published')
                    ->boolean(),
                Tables\Columns\TextColumn::make('published_at')
                    ->dateTime()
                    ->sortable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                //
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    // 関連するページクラスを登録
    public static function getPages(): array
    {
        return [
            'index'  => Pages\ListPosts::route('/'),
            'create' => Pages\CreatePost::route('/create'),
            'edit'   => Pages\EditPost::route('/{record}/edit'),
        ];
    }
}

3つのメソッドの役割

メソッド役割
form()作成・編集画面のフォームを定義
table()一覧画面のテーブルを定義
getPages()ルートとページクラスの対応を定義

フォームフィールドを整える

自動生成されたフォームを実用的に改良します。

public static function form(Form $form): Form
{
    return $form
        ->schema([
            // タイトル入力欄
            Forms\Components\TextInput::make('title')
                ->label('タイトル')
                ->required()
                ->maxLength(255)
                ->placeholder('記事タイトルを入力してください'),

            // 本文テキストエリア
            Forms\Components\Textarea::make('content')
                ->label('本文')
                ->rows(8)
                ->columnSpanFull(), // 2カラムレイアウトでも全幅表示

            // 公開フラグ(トグルスイッチ)
            Forms\Components\Toggle::make('is_published')
                ->label('公開する')
                ->default(false),

            // 公開日時
            Forms\Components\DateTimePicker::make('published_at')
                ->label('公開日時')
                ->nullable(),
        ]);
}

主要なフォームフィールド

// テキスト入力
Forms\Components\TextInput::make('name')
    ->label('名前')
    ->required();

// 複数行テキスト
Forms\Components\Textarea::make('description')
    ->rows(4);

// トグル(真偽値)
Forms\Components\Toggle::make('is_active');

// セレクトボックス
Forms\Components\Select::make('status')
    ->options([
        'draft'     => '下書き',
        'published' => '公開',
        'archived'  => 'アーカイブ',
    ]);

// 日時ピッカー
Forms\Components\DateTimePicker::make('published_at');

テーブルカラムを整える

public static function table(Table $table): Table
{
    return $table
        ->columns([
            // テキストカラム(検索・ソート対応)
            Tables\Columns\TextColumn::make('title')
                ->label('タイトル')
                ->searchable()
                ->sortable()
                ->limit(50), // 50文字で切り捨て

            // 真偽値カラム(アイコン表示)
            Tables\Columns\IconColumn::make('is_published')
                ->label('公開')
                ->boolean(), // true=チェック, false=バツ

            // 日時カラム
            Tables\Columns\TextColumn::make('published_at')
                ->label('公開日時')
                ->dateTime('Y/m/d H:i')
                ->sortable(),

            // 作成日(デフォルトで非表示)
            Tables\Columns\TextColumn::make('created_at')
                ->label('作成日')
                ->dateTime('Y/m/d')
                ->sortable()
                ->toggleable(isToggledHiddenByDefault: true),
        ])
        ->defaultSort('created_at', 'desc') // デフォルトのソート順
        ->actions([
            Tables\Actions\EditAction::make(),
            Tables\Actions\DeleteAction::make(),
        ])
        ->bulkActions([
            Tables\Actions\BulkActionGroup::make([
                Tables\Actions\DeleteBulkAction::make(),
            ]),
        ]);
}

ページクラスの役割

ListPosts.php(一覧ページ)

<?php
// 📁 app/Filament/Resources/PostResource/Pages/ListPosts.php

namespace App\Filament\Resources\PostResource\Pages;

use App\Filament\Resources\PostResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;

class ListPosts extends ListRecords
{
    protected static string $resource = PostResource::class;

    // 右上に「新規作成」ボタンを追加
    protected function getHeaderActions(): array
    {
        return [
            Actions\CreateAction::make(),
        ];
    }
}

CreatePost.php(作成ページ)

<?php
// 📁 app/Filament/Resources/PostResource/Pages/CreatePost.php

namespace App\Filament\Resources\PostResource\Pages;

use App\Filament\Resources\PostResource;
use Filament\Resources\Pages\CreateRecord;

class CreatePost extends CreateRecord
{
    protected static string $resource = PostResource::class;

    // 作成後のリダイレクト先をカスタマイズ
    protected function getRedirectUrl(): string
    {
        return $this->getResource()::getUrl('index');
    }
}

EditPost.php(編集ページ)

<?php
// 📁 app/Filament/Resources/PostResource/Pages/EditPost.php

namespace App\Filament\Resources\PostResource\Pages;

use App\Filament\Resources\PostResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;

class EditPost extends EditRecord
{
    protected static string $resource = PostResource::class;

    // 右上に「削除」ボタンを追加
    protected function getHeaderActions(): array
    {
        return [
            Actions\DeleteAction::make(),
        ];
    }
}

動作確認

開発サーバーを起動して /admin/posts にアクセスします。

php artisan serve
  • http://localhost:8000/admin/posts → 一覧画面
  • http://localhost:8000/admin/posts/create → 作成画面

「新規投稿」ボタンをクリックしてタイトルと本文を入力し、「作成」ボタンを押してみましょう。一覧に追加されていれば成功です。


まとめ

  • Filamentのリソースはモデルに対応するCRUDのまとまり
  • php artisan make:filament-resource Post --generate で自動生成
  • form() でフォームを、table() でテーブルを定義
  • getPages() でURL→ページクラスの対応を管理
  • 3つのページクラス(List/Create/Edit)がそれぞれの画面を担う

次回はフォームフィールドを深掘りし、Select・DatePicker・FileUploadなどの使い方を学びます。