👌

[Laravel/Filament]超高速で管理画面を作る!

2023/01/09に公開

はじめに

Laravelで管理画面を実装する場合、いろいろな選択肢があると思います。スクラッチから作るというケースもあれば、AdminLTEなどのCSSテンプレートを使うケースもあるでしょう。また、SPA or MPAによっても状況は変わるでしょう。いずれにせよ、スクラッチから作るのは稀で、なんらかのテンプレートやFWを利用するのではないでしょうか?

本記事では、Filamentを紹介したいと思います。Filamentを使えば、ほぼノーコードでSPAライクな管理画面を実装することが可能です。

Filamentの公式デモサイトを見てもらえれば、その雰囲気や操作性が感じられるでしょう。

対象の読者

Laravelプロジェクトをスクラッチで構築できる程度のレベルを想定しています。

Filamentとは

FilamentはTALL技術を基盤とするLaravelの拡張パッケージの1つです。TALLとは、以下の4つの技術の頭文字を取ったものです。

  • Tailwind CSS
  • Alpine.JS
  • Laravel
  • Livewire

Tailwind CSSやLaravelは皆さんお馴染みですね。LivewireはLaravelのViewコンポーネントのみでVueやReactなどを使わずにSPAライクな画面を構築できる仕組みです。Alpine.JSは、軽量なJavaScriptのライブラリで、HTMLを動的に変更することができます。公式ドキュメントにあるように、現代版のjQueryとも言えます。

Admin Panel

Filamentは以下の独立した3つのコンポーネントの集まりです。これら3つのコンポーネントはそれぞれ個別に利用することも可能です。(詳しくは公式のドキュメントを参照してください)

管理画面を実装するには、Admin Panelを利用します。Admin Panelは上記3つのコンポーネントを利用したライブラリです。

必須条件

公式サイトにもあるように、Admin Panelを利用するには以下の条件(公式からの抜粋)が必須です。

  • PHP 8.0+
  • Laravel v8.0+
  • Livewire v2.0+

Laravel9では使えないの?

上記のように、公式のドキュメント上ではLaravel8系のみのサポートとなっています。ただし、GitHub上でLaravel9のテストを行なっていることに加え、私自身がLaravel9でも問題なく動作することを確認しています。

※あくまで私個人での確認ですので、Laravel9を使う際は自己責任でお願いします。

作ってみる

Filamentを利用して簡単な管理画面を作成してみましょう。

前提

開発環境(MacやDockerなど)に以下のPHP8以上がインストールされていること、および、データベース環境が構築されていることが前提となります。また、Composerもインストール済の前提で話を進めます。

インストール

まずはComposerを使ってLaravelプロジェクトを作成しましょう。適当なディレクトリで以下のコマンドを実行します。エラーなくfilament-exampleディレクトリが作成されると成功です。

composer create-project laravel/laravel filament-example

つぎに、filamentをインストールしましょう。下記の一連のコマンドを実行します。

cd filament-example
composer require filament/filament:"^2.0"

では起動確認してみましょう。Laravelの開発サーバを以下のartisanコマンドで起動します。

php artisan serve

コマンドが正常に実行されると、以下のようなログがコンソールに表示されます。

   INFO  Server running on [http://127.0.0.1:8000].

※上記は8000ポートですが、皆さんの環境によっては異なる可能性があります。

では、ブラウザのURLにlocalhost:8000/adminを入力してみましょう。以下のようなログイン画面が表示されるはずです。(adminパスを忘れないように)

ここまでノーコードでログイン画面を作成することができました!

データベース環境

ここでは、Dockerを利用してMySQL8.0のデータベース環境を構築します。すでにデータベース環境が構築されている場合や自力で構築できる場合はマイグレーション実行までスキップしてください。

MySQLコンテナ起動

まず、以下のコマンドでMySQLのDockerコンテナをデーモン起動します。

docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -p 4000:3306 -d mysql:8.0

補足すると、コンテナ名はmysql、rootユーザのパスワードはpassword、ホスト側ポートは4000としています。

データベース(スキーマ)作成

起動したMySQLのDockerコンテナでデータベースを作成します。ここではデータベース名はfilament_exampleとします。

まずは先ほど起動したDockerコンテナ内に以下のコマンドで入ります。

docker exec -it mysql bash

次に、Dockerコンテナ内で以下のコマンドを実行して、MySQLサーバに接続します。

mysql -u root -p

パスワードが求められるので(先ほど設定したパスワードを)入力します。

MySQLサーバに接続ができたのち、以下のコマンドでデータベースを作成しましょう。

create database filament_example

.envファイル設定

Laravelプロジェクト直下にある.env.exampleファイルをコピーして.envファイルを作成します。上記で作成したDBの情報を以下のように設定します。(Webサーバ側もDockerを利用している場合など、各自の環境で適当に変更してください)

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=4000
DB_DATABASE=filament_example
DB_USERNAME=root
DB_PASSWORD=password

マイグレーション実行

以下のartisanコマンドでマイグレーションを実行します。

php artisan migrate

データベースの設定が正しく行われている場合は以下のようなログが出力されるはずです。

   INFO  Preparing database.

  Creating migration table .................................. 17ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ...................... 26ms DONE
  2014_10_12_100000_create_password_resets_table ............ 29ms DONE
  2019_08_19_000000_create_failed_jobs_table ................ 22ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ..... 31ms DONE

何らかのエラーが発生した場合は、設定ファイル(.env)の内容を再度確認してみましょう。また、以下のコマンドでLaravelがキャッシュしているconfigの内容もクリアしてみましょう。

php artisan config:clear

このような対応を行ってもマイグレーションが失敗する場合は、データベースが正しく起動しているか、データベース名が間違っていないか、ホスト側ポートが正しいかなどを確認してみましょう。

ユーザ追加とログイン

Filamentは認証(データベース認証)の仕組みもデフォルトで用意されています。以下のartisanコマンドでユーザを追加しましょう。

php artisan make:filament-user --name=test --email=test@example.com --password=password

上記のコマンドにより、ユーザ名がtest、メールアドレスがtest@example.com、パスワードがpasswordのユーザを追加しました。

ではさっそく、先ほど表示確認したログイン画面から、上記のユーザでログインしてみましょう。
次のような管理画面のダッシュボードが表示されれば成功です。

ここまでノーコードでユーザを追加して管理画面にログインすることができました!

管理画面の追加

では簡単なテーブルをデータベースに追加し、その管理画面を作成してみましょう。テーブルは商品カテゴリ商品の2つだけとします。

マイグレーションファイル生成

まずは、以下のartisanコマンドで各テーブルのマイグレーションファイルを作成します。

php artisan make:migration CreateProductCategoriesTable
php artisan make:migration CreateProductsTable

マイグレーションファイル変更

次に、それぞれのマイグレーションファイルをテーブル定義に従って変更します。

商品カテゴリテーブル

(ファイル名は例です。タイムスタンプは各自の環境で異なります)

database/migrations/2023_01_09_074123_create_product_categories_table.php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('product_categories', function (Blueprint $table) {
            $table->id();
            $table->string('name')->comment('商品カテゴリ名');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('product_categories');
    }
};

商品テーブル

(ファイル名は例です。タイムスタンプは各自の環境で異なります)

database/migrations/2023_01_09_074129_create_products_table.php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name')->comment('商品名');
            $table->foreignId('category_id');
            $table->unsignedInteger('price')->comment('価格');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};

マイグレーション実行

以下のartisanコマンドでマイグレーションを実行します。

php artisan migrate

モデル作成

モデル生成

以下のartisanコマンドで商品カテゴリと商品のモデルを作成します。

php artisan make:model ProductCategory
php artisan make:model Product

モデル修正

それぞれのモデルにguardedプロパティとリレーションを追加します。Filamenでは、guardedもしくはfillableが設定されてないと更新時にエラーとなります。 今回の例では、簡単のためにguardedプロパティは空にして全てのフィールドの更新を許可します。

商品カテゴリモデル

app/Models/ProductCategory.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ProductCategory extends Model
{
    use HasFactory;
    
    protected $guarded = [];

    public function propertys(): HasMany
    {
        return $this->hasMany(Propert::class);
    }    
}

商品モデル

app/Models/Product.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $guarded = [];

    public function productCategory(): BelongsTo
    {
        return $this->belongsTo(ProductCategory::class);
    }    
}

Filamentリソース作成

Filamentのリソース(Resource)とは、各モデルのCRUDを管理するクラスのことです。このリソースでCRUDの内容を定義します。

まずはDoctrine DBALパッケージをインストールします。

composer require doctrine/dbal --dev

次に、以下のartisanコマンドを実行して商品カテゴリおよび商品のリソースをそれぞれ作成します。

php artisan make:filament-resource ProductCategory --generate
php artisan make:filament-resource Product --generate

以下のように、app/Filament/Resourcesディレクトリ配下にFilamentのリソースが作成されます。

画面確認

管理画面のダッシュボードをリフレッシュしてみましょう。以下のように、商品カテゴリと商品のメニューが追加されています。(以下、メニュー名、フィールド名、ボタンなどが英語表記ですが、日本語にすることも当然できますが、今回は割愛します)

カテゴリメニューをクリックするとカテゴリ一覧画面が表示されます。当然、まだデータは登録されていません。

カテゴリを追加してみましょう。一覧画面右上の「New product category」ボタンをクリックすると以下のフォーム画面が表示されます。

商品カテゴリとして「飲み物」を登録後に、一覧画面にもどると以下のように商品カテゴリが追加されていることを確認できます。

ここまで、マイグレーションファイルとモデルの修正のみでCRUD画面を生成することができました!

リレーションの設定

初期設定では、商品のフォーム画面は以下のようになっています。

商品カテゴリID(Category_id)はテキストフィールドとなっていますが、登録した商品カテゴリから選択するセレクトボックスが望ましいところです。これを実現するために、商品カテゴリのリソースクラスのformメソッドを以下のように修正しましょう。

app/Filament/Resources/ProductResource.php
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\TextInput::make('name')
                    ->required()
                    ->maxLength(255),
                //Forms\Components\TextInput::make('category_id')  修正前
                Forms\Components\Select::make('category_id')
                    ->relationship('productCategory', 'name') 
                    ->required(),
                Forms\Components\TextInput::make('price')
                    ->required(),
            ]);
    }

すると、次のように商品カテゴリフィールドがセレクトボックスとなります。これは、Productモデルのリレーション(BelongsTo)を通して実現されています。

まとめ

今回は、Laravelの管理画面を超高速で実装できるFilamentを紹介しました。

  • Filamentではユーザ認証機能が組み込まれており、ユーザの追加はartisanコマンドで簡単に行えます。
  • 商品カテゴリと商品の2つのテーブルのみの簡単な例を通して、Filamentの使い方を提示しました。
    • Filamentでは、モデルとマイグレーションファイルの修正のみで、artisanコマンドを利用してCRUD画面を作成することができました。
    • モデルのリレーションをフォームに設定することで、簡単にセレクトボックスを実現できました。

上記の通り、お手軽に管理画面を超高速で構築したい!という方はかなりおすすめかと思います。

ただし、ノーコード、ローコードツールなどの例に漏れず、Filamentも簡単なCRUD処理は表題の通りに超高速で実装できますが、凝った画面を実装するためにはカスタマイズする必要があります。上述したとおり、FilamentはTALL技術を基盤としているため、カスタマイズを実現するにはこれらの技術に対する知識が必要となります。特に、LivewireAlpine.JSに対する深い知識が求められます。また、カスタマイズに関してはドキュメントがまだ充実していないため、Filamentのソースコードを時に読む必要性が生じるでしょう。

Discussion