前提
- Laravel Version11
- Docker for Windows Desktop
- Ubuntu環境下でLaravel Sailを使用
- 過去記事「Filamentを使ってみた」の状態(既にadmin用のパネルをインストール済)
- 過去記事「Laravelでモデルの定義をしてみた」の設定済(掲示板モデルの定義)
- 過去記事「Laravelでデータベースのテーブル定義をしてみた」の設定済(掲示板テーブルの定義)
概要
Laravel Filamentは管理画面を簡単に作成できるという記事が多いのですが、通常のユーザー画面も簡単に作れないかと思って試して見ました。
課題
- アクセスしているユーザーに認可されているデータのみを表示・編集・削除可能とし、それ以外のデータは表示・編集・削除不可とする必要がある。
- 認可・非認可データの制御やセキュリティ対策はFilament公式ページにも記載されている通り、自己責任でお願いします。
作業
- 1.ユーザー用パネルのインストール
- 2.リソース作成
- 3.リソース/モデル設定
1.ユーザー用パネルのインストール
参考: https://filamentphp.com/docs/3.x/panels/installation
./vendor/bin/sail php artisan filament:install --panels
┌ What is the ID? ─────────────────────────────────────────────┐
│ admin │
└──────────────────────────────────────────────────────────────┘
既にadminのIDでパネルをインストールしているので、今回はcustomerとしてインストールしてみました。
┌ What is the ID? ─────────────────────────────────────────────┐
│ customer │
└──────────────────────────────────────────────────────────────┘
ログイン画面が管理者用とユーザー用とで異なる
管理者用ログイン画面(http://localhost/admin/)
ユーザー用ログイン画面(http://localhost/customer/)
最初にインストールしたパネルのIDが管理者用、後でインストールしたパネルのIDが通常のログイン画面
2つのパネルのログイン画面が違ったので、Laravelをまっさらな状態にし直し、Filamentのパネルをインストールする際、最初にIDをcustomerとして、2回目のIDをadminとしてインストールしてみたところ、最初にインストールしたIDが管理者用になって、その後でインストールした場合のIDは通常のログイン画面になるようです。
2.リソースの作成
掲示板モデルのリソースを作成します。
./vendor/bin/sail php artisan make:filament-resource -G Board
┌ Which panel would you like to create this in? ───────────────┐
│ › ● admin │
│ ○ customer │
└──────────────────────────────────────────────────────────────┘
どちらのパネルIDに設定するか聞いてきましたので、customerを選択しました。
管理者パネルにもBoardリソースを作成します。
上と同じコマンドを実行し、adminパネルを選択して作成します。
3.リソース/モデル設定
このままだと、ログインできる全てのユーザーが、自分以外のIDの新規投稿や変更、削除が出来てしまいます。
3.1 画面上に表示されるuser_idを非表示
新規作成画面でuser_idをユーザーが入力できるのは問題ですので非表示にします。
また、一覧画面ではユーザー自身の投稿一覧のみを表示するので、ユーザー名表示を非表示にします。
同様に一覧画面のcreated_at項目とupdated_at項目の表示設定を非表示にします。
public static function form(Form $form): Form
{
return $form
->schema([
// Forms\Components\Select::make('user_id')
// ->relationship('user', 'name')
// ->required(),
Forms\Components\TextInput::make('title')
->required()
->maxLength(100),
・・・
public static function table(Table $table): Table
{
return $table
->columns([
// Tables\Columns\TextColumn::make('user.name')
// ->numeric()
// ->sortable(),
Tables\Columns\TextColumn::make('title')
->searchable(),
Tables\Columns\TextColumn::make('category')
->searchable(),
Tables\Columns\TextColumn::make('texts')
->searchable(),
Tables\Columns\TextColumn::make('date_expiry')
->date()
->sortable(),
// Tables\Columns\TextColumn::make('created_at')
// ->dateTime()
// ->sortable()
// ->toggleable(isToggledHiddenByDefault: true),
// Tables\Columns\TextColumn::make('updated_at')
// ->dateTime()
// ->sortable()
// ->toggleable(isToggledHiddenByDefault: true),
])
3.2 新規登録/編集時にuser_idを設定
上のままだと、新規登録/編集画面でuser_idの値が入らず、データベースに保存されないので、保存時にuser_idが設定されるようにします。
use Illuminate\Support\Facades\Auth;
class CreateBoard extends CreateRecord
{
protected static string $resource = BoardResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = Auth::id();
return $data;
}
}
use Illuminate\Support\Facades\Auth;
class EditBoard extends EditRecord
{
protected static string $resource = BoardResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
protected function mutateFormDataBeforeFill(array $data): array
{
$data['user_id'] = Auth::id();
return $data;
}
3.3 一覧画面で自身のデータのみにする設定
現在の状態だと一覧画面で自分以外のデータも表示されてしまうので、自分のデータしかアクセスできないよう設定します。
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
class Board extends Model
{
protected static function booted(): void
{
static::addGlobalScope('team', function (Builder $query) {
if (Auth::hasUser()) {
$query->where('user_id', Auth::user()->id);
}
});
}
上の設定をすると管理者用パネルで問題が起こります。
管理者パネルでは全てのレコードを表示対象にしたいのに、そのようにならなくなります。
そのため管理者パネルでは、モデルに設定されたグローバルスコープを除外するようにします。
public static function table(Table $table): Table
{
return $table
->modifyQueryUsing(fn(Builder $query) => $query->withoutGlobalScopes())
->columns([
Tables\Columns\TextColumn::make('user.name')
->numeric()
->sortable(),
ただし、これだと管理者パネルのBoards一覧画面で全てのレコードが表示されますが、ユーザーが作成したレコードに対して編集を行おうとしても編集画面が開きません。
$tableに対してmodifyQueryUsing()を設定するのを元に戻して、BoardResourceに以下の設定をします。
class BoardResource extends Resource
{
・・・
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes();
}
以上で、基本的なところは使えそうなユーザー画面になりました。
- 認可・非認可データの制御やセキュリティ対策は自己責任でお願いします。