🦁

Filament で部分カスタマイズページを作成する

2023/11/06に公開

この記事について

  • Filamentで自動生成した画面に対して、カスタマイズ方法やカスタマイズページの作成方法がわからず、いろいろ調査してわかったことについて記載しました
  • 同様にカスタマイズ方法に悩んでいる方の参考になれば幸いです

使用マシン/ツール

macOS Sonoma ver14.0
Docker Desktop ver4.23.0
Laravel Framework ver10.28.0
Filament ver2.17.53

環境構築

Filamentの環境構築については、下記記事で紹介してますのでご参考ください。
https://zenn.dev/egstock_inc/articles/23f00d24b574dd

Filamentについて

Filament の構成は

  • Tailwind
  • Alpine.js
  • Laravel
  • Livewire

といった感じになっています。(頭文字をとってTALL stackと呼ぶらしいです)
個人的には、特にLivewireについてある程度理解しておくと、実装がしやすくなるかなと思います。

Livewireについては下記記事でも触れていますので、興味のある方はご参考ください。
https://zenn.dev/egstock_inc/articles/1c5bb3e7918df6

※ 実装に動いているコードが見たい方はこちらから
https://github.com/eg-knakamura/study-filament

ひとえに カスタマイズ といっても

  • 自動生成ページへの部分カスタマイズ
  • 新規カスタマイズしたページを作成する

の2通りがあるのでそれぞれ掘り下げてみます

自動生成したページを部分カスタマイズする

ページを自動生成する

まずは検証用のページを自動生成機能を使って生成します。
流れは下記になります。

  • 顧客情報を表示するページを自動生成で作成
  • 顧客と紐づいている商品マスタデータをカスタマイズで表示する

下記コマンドでマイグレーションとモデルを作成します。

php artisan make:model -m Customer -- 顧客情報
php artisan make:model -m MstItem -- 商品マスタデータ

上記コマンドを実行すると、app/Models/database/migrations/にファイルが生成されます。
マイグレーションファイルをそれぞれ下記のように編集します。

database/migrations/create_customers_table.php
    public function up(): void
    {
        Schema::create("customers", function (Blueprint $table) {
            $table->id();
            $table->string("name_sei")->comment("名前(性)");
            $table->string("name_mei")->comment("名前(名)");
            $table->integer("mst_item_id")->comment("マスタアイテムID");
            $table->timestamps();
        });

        \DB::table("customers")->insert([
            0 => [
                "id" => 1,
                "name_sei" => "山田",
                "name_mei" => "太郎",
                "mst_item_id" => "1",
                "created_at" => "2023-10-20 02:16:04",
                "updated_at" => "2023-10-20 02:16:04",
            ],
            [
                "id" => 2,
                "name_sei" => "山田",
                "name_mei" => "大",
                "mst_item_id" => "1",
                "created_at" => "2023-10-20 02:16:04",
                "updated_at" => "2023-10-20 02:16:04",
            ],
            [
                "id" => 3,
                "name_sei" => "山田",
                "name_mei" => "大吾",
                "mst_item_id" => "1",
                "created_at" => "2023-10-20 02:16:04",
                "updated_at" => "2023-10-20 02:16:04",
            ],
            [
                "id" => 4,
                "name_sei" => "山田",
                "name_mei" => "大吾郎",
                "mst_item_id" => "1",
                "created_at" => "2023-10-20 02:16:04",
                "updated_at" => "2023-10-20 02:16:04",
            ],
        ]);
    }
database/migrations/create_mst_items_table.php
        Schema::create("mst_items", function (Blueprint $table) {
            $table->id();
            $table->string("name")->comment("アイテム名");
            $table->timestamps();
        });

        \DB::table("mst_items")->insert([
            0 => [
                "id" => 1,
                "name" => "アイテム1",
                "created_at" => "2023-10-20 02:16:04",
                "updated_at" => "2023-10-20 02:16:04",
            ],
        ]);

マイグレーション実行とモデルクラス編集後、下記コマンドで顧客ページのリソースクラスを生成します。

php artisan make:filament-resource Customer --generate

あとは、必要に応じて少し編集してみます。
今回は下記の画面のようにしてみました。

このページに対して、商品マスタデータを顧客テーブルの下に表示してみます。

部分カスタマイズする

公式ドキュメントの下記ページを参考にしています。
https://filamentphp.com/docs/2.x/admin/resources/widgets
対象ページに対してウィジェットというコンポーネント設置するようなイメージです。
(実際はちょっと違うと思いますので、あくまでイメージです)

下記コマンドを実行します。

php artisan make:filament-widget MstItemOverview --resource=CustomerResource

実行後、下記ファイルが生成されます。

  • src/app/Filament/Resources/CustomerResource/Widgets/MstItemOverview.php
  • src/resources/views/filament/resources/customer-resource/widgets/mst-item-overview.blade.php

一旦この時点でMstItemを表示させてみたいと思います。
今回は一覧ページに表示させるので、src/app/Filament/Resources/CustomerResource/Pages/ListCustomers.phpを編集します。
(もし作成ページに表示させたい場合は/Pages/CreateCustomers.phpを、編集ページに表示させたい場合は/Pages/EditCustomers.phpを編集します)

src/app/Filament/Resources/CustomerResource/Pages/ListCustomers.php
+    protected function getHeaderWidgets(): array
+    {
+        return [
+            CustomerResource\Widgets\MstItemOverview::class
+        ];
+    }

+    protected function getFooterWidgets(): array
+    {
+        return [
+            CustomerResource\Widgets\MstItemOverview::class
+        ];
+    }

getHeaderWidgetsはページ上部に、getFooterWidgetsはページ下部に表示されます。

表示している内容をわかりやすくするためにmst-item-overview.blade.phpを編集します。

src/resources/views/filament/resources/customer-resource/widgets/mst-item-overview.blade.php
<x-filament::widget>
    <x-filament::card>
-        {{-- Widget content --}}
+        <p style="color: #ff0099; font-size: 1.125rem; line-height: 1.75rem;">MstItemウィジェット表示</p>
+        <table style="border-width: 2px; text-align: center">
+            <tr>
+                <th style="border-width: 2px; width: 150px">id</th><th style="border-width: 2px; width: 300px">商品名</th>
+            </tr>
+            <tr>
+                <td style="border-width: 2px; width: 150px">1</td><td style="border-width: 2px; width: 300px">test</td>
+            </tr>
+        </table>
    </x-filament::card>
</x-filament::widget>

ここまで記述すると、顧客テーブルの上部と下部に表示されます。

表示は問題なさそうなので、実際にMstItemのデータを取得して表示してみます。
MstItemOverview.phpに下記メソッドを追加します。

src/app/Filament/Resources/CustomerResource/Widgets/MstItemOverview.php
    public function getViewData(): array
    {
        $mstItems = MstItem::query()
            ->select("id", "name")
            ->get()
            ->toArray();

        return [
            "items" => $mstItems,
        ];
    }

getViewDataメソッドは、テンプレート側に渡すデータを定義するメソッドです。
make:filament-widgetで生成したクラスはWidgetクラスを継承しており、WidgetクラスにはgetViewDataメソッドが定義されていて、これをオーバーライドしています。
他にも定義済みのメソッドがあるので、必要に応じてオーバーライドなど使用する形になると思います。

次に、mst-item-overview.blade.phpを下記のように変更します。

src/resources/views/filament/resources/customer-resource/widgets/mst-item-overview.blade.php
        <table style="border-width: 2px; text-align: center">
            <tr>
                <th style="border-width: 2px; width: 150px">id</th><th style="border-width: 2px; width: 300px">商品名</th>
            </tr>
-            <tr>
-                <td style="border-width: 2px; width: 150px">1</td><td style="border-width: 2px; width: 300px">test</td>
-            </tr>
+            @foreach($items as $item)
+                <tr>
+                    <td style="border-width: 2px; width: 150px">{{$item['id']}}</td><td style="border-width: 2px; width: 300px">{{$item['name']}}</td>
+                </tr>
+            @endforeach
        </table>

これで実際にマスタデータを表示できました。

今回はテンプレート側も自作しましたが、コマンドの指定によってはテンプレートも自動生成されるようです。
https://filamentphp.com/docs/2.x/admin/dashboard/tables

今回は簡単なテーブル表示を作成しましたが、フォームの作成など用途に応じてカスタマイズすることは可能かなと思います。
フォーム用のコンポーネントを生成するコマンドや、テーブル用のコンポーネントを生成するコマンドなどが用意されているので、これを使ってカスタマイズしていく形になると思います。

https://filamentphp.com/docs/2.x/forms/getting-started#preparing-your-livewire-component
https://filamentphp.com/docs/2.x/tables/getting-started#preparing-your-livewire-component

ここまでの感想

  • カスタマイズで生成したクラスはLivewireのコンポーネントとして扱う感じなので、Livewireの知見があるとFilamentは結構とっつきやすくなる印象がありました。
  • 部分的にカスタマイズができるなら、Filamentを使っていくメリットは大きそうです。
  • 次回は新規カスタマイズページについて検証してみたいと思います。

参考

https://qiita.com/sgrs38/items/b4834954b20ccfbf88e9

EGSTOCK,Inc.

Discussion