[Laravel/Filament]超高速で管理画面を作る!
はじめに
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を利用している場合など、各自の環境で適当に変更してください)
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
マイグレーションファイル変更
次に、それぞれのマイグレーションファイルをテーブル定義に従って変更します。
商品カテゴリテーブル
(ファイル名は例です。タイムスタンプは各自の環境で異なります)
<?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');
}
};
商品テーブル
(ファイル名は例です。タイムスタンプは各自の環境で異なります)
<?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
プロパティは空にして全てのフィールドの更新を許可します。
商品カテゴリモデル
<?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);
}
}
商品モデル
<?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
メソッドを以下のように修正しましょう。
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では、モデルとマイグレーションファイルの修正のみで、
上記の通り、お手軽に管理画面を超高速で構築したい!という方はかなりおすすめかと思います。
ただし、ノーコード、ローコードツールなどの例に漏れず、Filamentも簡単なCRUD処理は表題の通りに超高速で実装できますが、凝った画面を実装するためにはカスタマイズする必要があります。上述したとおり、FilamentはTALL技術を基盤としているため、カスタマイズを実現するにはこれらの技術に対する知識が必要となります。特に、Livewire
とAlpine.JS
に対する深い知識が求められます。また、カスタマイズに関してはドキュメントがまだ充実していないため、Filament
のソースコードを時に読む必要性が生じるでしょう。
Discussion