#07 FilamentPHP基礎
カスタムページとウィジェット——ダッシュボードを作る
ウィジェットとカスタムページの概要
Filamentのダッシュボードはウィジェットの集まりです。ウィジェットにはKPIカードを表示する StatsOverviewWidget とグラフを表示する ChartWidget の2種類があります。
ダッシュボード
├── StatsOverviewWidget → 数値KPIカード
├── ChartWidget → 折れ線・棒・円グラフ
└── TableWidget → 一覧テーブル(任意)
また make:filament-page で完全にカスタマイズされたページを作ることもできます。
StatsOverview ウィジェットを作る
php artisan make:filament-widget StatsOverview --stats-overview
生成されるファイル:app/Filament/Widgets/StatsOverview.php
<?php
// 📁 app/Filament/Widgets/StatsOverview.php
namespace App\Filament\Widgets;
use App\Models\Post;
use App\Models\Comment;
use App\Models\User;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
class StatsOverview extends BaseWidget
{
// 自動更新の間隔(秒)。null で無効
protected static ?string $pollingInterval = '15s';
protected function getStats(): array
{
return [
// 基本的なKPIカード
Stat::make('記事数', Post::count())
->description('公開済み: ' . Post::where('is_published', true)->count() . '件')
->descriptionIcon('heroicon-o-document-text')
->color('primary'),
// 増減を示すトレンド
Stat::make('今月のコメント', Comment::whereMonth('created_at', now()->month)->count())
->description('先月比 +12%')
->descriptionIcon('heroicon-m-arrow-trending-up')
->color('success'),
// チャートデータ付き(過去7日間の推移)
Stat::make('登録ユーザー数', User::count())
->description('今週 +' . User::whereBetween('created_at', [now()->startOfWeek(), now()])->count() . '件')
->chart(
// 過去7日間の登録数グラフ
collect(range(6, 0))->map(
fn ($days) => User::whereDate('created_at', now()->subDays($days))->count()
)->toArray()
)
->color('warning'),
];
}
}
Stat のオプション
Stat::make('ラベル', '値')
->description('補足テキスト') // 説明文
->descriptionIcon('heroicon-o-...') // 説明横のアイコン
->color('success') // カードの色
->chart([7, 3, 4, 5, 6, 3, 5, 3]) // 小さなスパークラインチャート
->url(route('filament.admin.resources.posts.index')) // クリックで遷移
->extraAttributes(['class' => 'cursor-pointer']), // 追加HTMLクラス
ChartWidget を作る
php artisan make:filament-widget RevenueChart --chart
生成されるファイル:app/Filament/Widgets/RevenueChart.php
<?php
// 📁 app/Filament/Widgets/RevenueChart.php
namespace App\Filament\Widgets;
use App\Models\Post;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Carbon;
class RevenueChart extends ChartWidget
{
protected static ?string $heading = '月別投稿数';
// チャートの種類: line / bar / pie / doughnut / polarArea / radar
protected static string $color = 'info';
protected function getType(): string
{
return 'bar'; // 棒グラフ
}
protected function getData(): array
{
// 過去12か月のデータを取得
$data = collect(range(11, 0))->map(function ($monthsAgo) {
$date = now()->subMonths($monthsAgo);
return Post::whereYear('created_at', $date->year)
->whereMonth('created_at', $date->month)
->count();
});
$labels = collect(range(11, 0))->map(
fn ($monthsAgo) => now()->subMonths($monthsAgo)->format('Y/m')
);
return [
'datasets' => [
[
'label' => '投稿数',
'data' => $data->toArray(),
'backgroundColor' => 'rgba(59, 130, 246, 0.5)',
'borderColor' => 'rgb(59, 130, 246)',
'borderWidth' => 1,
],
],
'labels' => $labels->toArray(),
];
}
}
折れ線グラフ(LineChart)
protected function getType(): string
{
return 'line';
}
protected function getData(): array
{
$labels = collect(range(6, 0))->map(
fn ($days) => now()->subDays($days)->format('m/d')
);
$published = collect(range(6, 0))->map(
fn ($days) => Post::where('is_published', true)
->whereDate('created_at', now()->subDays($days))
->count()
);
$draft = collect(range(6, 0))->map(
fn ($days) => Post::where('is_published', false)
->whereDate('created_at', now()->subDays($days))
->count()
);
return [
'datasets' => [
[
'label' => '公開済み',
'data' => $published->toArray(),
'borderColor' => 'rgb(34, 197, 94)',
'fill' => false,
],
[
'label' => '下書き',
'data' => $draft->toArray(),
'borderColor' => 'rgb(156, 163, 175)',
'fill' => false,
],
],
'labels' => $labels->toArray(),
];
}
円グラフ(PieChart)
protected function getType(): string
{
return 'pie';
}
protected function getData(): array
{
$published = Post::where('is_published', true)->count();
$draft = Post::where('is_published', false)->count();
return [
'datasets' => [
[
'data' => [$published, $draft],
'backgroundColor' => [
'rgb(34, 197, 94)',
'rgb(156, 163, 175)',
],
],
],
'labels' => ['公開済み', '下書き'],
];
}
ウィジェットを表示順と幅を設定する
PanelProvider でウィジェットを登録
AdminPanelProvider.php の ->widgets() に追加します(discoverWidgets() を使っている場合は自動検出されます)。
// 📁 app/Providers/Filament/AdminPanelProvider.php
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
ウィジェット側でソート順を指定
class StatsOverview extends BaseWidget
{
// 数値が小さいほど上に表示
protected static ?int $sort = 1;
}
class RevenueChart extends ChartWidget
{
protected static ?int $sort = 2;
}
ウィジェットの横幅
// full(全幅)/ half(半幅)/ デフォルトは自動
protected int | string | array $columnSpan = 'full';
// レスポンシブ設定
protected int | string | array $columnSpan = [
'md' => 2, // md以上で2カラム幅
'xl' => 3, // xl以上で3カラム幅
];
カスタムページを作る
完全にカスタマイズされたページを作成します。
php artisan make:filament-page Dashboard
生成されるファイル:
app/Filament/Pages/Dashboard.php
resources/views/filament/pages/dashboard.blade.php
<?php
// 📁 app/Filament/Pages/Dashboard.php
namespace App\Filament\Pages;
use App\Filament\Widgets\RevenueChart;
use App\Filament\Widgets\StatsOverview;
use Filament\Pages\Page;
class Dashboard extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-home';
protected static ?string $navigationLabel = 'ダッシュボード';
protected static ?string $title = 'ダッシュボード';
protected static ?int $navigationSort = -2; // サイドバーの一番上
// このページで表示するウィジェットクラス
protected function getHeaderWidgets(): array
{
return [
StatsOverview::class,
];
}
protected function getFooterWidgets(): array
{
return [
RevenueChart::class,
];
}
}
Bladeファイルは最小限でOKです。
{{-- 📁 resources/views/filament/pages/dashboard.blade.php --}}
<x-filament-panels::page>
<p class="text-gray-500">
管理画面へようこそ。最新の状況は上のウィジェットで確認できます。
</p>
</x-filament-panels::page>
デフォルトのDashboardページをカスタマイズ
Filamentが提供するデフォルトのDashboardをカスタマイズする場合は、Filament\Pages\Dashboard を継承します。
<?php
// 📁 app/Filament/Pages/Dashboard.php
namespace App\Filament\Pages;
class Dashboard extends \Filament\Pages\Dashboard
{
// ウィジェットの幅(カラム数)
public function getColumns(): int | string | array
{
return 2;
}
// 表示するウィジェットを指定
public function getWidgets(): array
{
return [
\App\Filament\Widgets\StatsOverview::class,
\App\Filament\Widgets\RevenueChart::class,
];
}
}
ナビゲーションへのカスタムページ追加
$navigationIcon と $navigationLabel を設定するだけで、サイドバーに自動追加されます。
class Reports extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-chart-bar';
protected static ?string $navigationLabel = 'レポート';
protected static ?string $navigationGroup = '分析'; // グループに入れる
protected static ?int $navigationSort = 1;
}
アクセス制限が必要な場合:
public static function canAccess(): bool
{
return auth()->user()?->is_admin ?? false;
}
まとめ
php artisan make:filament-widget StatsOverview --stats-overviewでKPIカードウィジェットを生成Stat::make('ラベル', 値)でカードを追加、->chart()でスパークライン表示php artisan make:filament-widget RevenueChart --chartでグラフウィジェットを生成getType()でline/bar/pieを指定getData()でChart.js形式のデータを返すprotected static ?int $sortでウィジェットの表示順を制御php artisan make:filament-page Dashboardでカスタムページを生成getHeaderWidgets()/getFooterWidgets()でページ内のウィジェットを指定
次回は認証とアクセス制御を学びます。