Code cùng Khánh

Chia sẻ kiến thức code Khánh đang học và đang dùng

Hướng dẫn cài đặt và sử dụng Filament với Laravel

cài đặt và sử dụng Filament v5 với Laravel 12 tạo admin panel cực nhanh

FilamentPHP là gì? Vì sao chúng ta nên dùng nó?

Thông thường, khi mình khởi tạo một dự án mới, sẽ tốn rất nhiều thời gian cho việc làm admin panel cũng như là làm các phần CRUD cho các bảng của mình, nhiều lúc sẽ có trường hợp mình lay hoay không biết làm sao cho đẹp, và thông thường thì kết quả nhìn cũng không được đẹp lắm dù tốn thời gian kinh khủng.

FilamentPHP (gọi tắt là Filament) ra đời để giải quyết vấn đề đó. Đây là một công cụ mã nguồn mở (mình nghĩ là có thể gọi là UI framework cũng được) dựa trên TALL stack bao gồm Tailwindcss, Alpine.js , Laravel, Livewire, cho phép bạn tạo ra một trang quản trị đầy đủ chức năng — từ form, bảng, tìm kiếm, phân trang cho tới tích hợp các plugin biểu đồ, tương tác được — chỉ bằng cách viết file cấu hình PHP mà không cần phải đụng tới HTML hay CSS, đặc biệt là Javascript (trừ khi bạn muốn tuỳ chỉnh sâu hơn)

Filament v5 là phiên bản mới nhất hiện tại, mình nghĩ đây là thời điểm tốt nhất để học Filament nếu bạn chưa từng thử qua.

Filament rất phù hợp nếu bạn đang xây dựng các trang quản lý nội dung (CMS), hệ thống quản lý đơn hàng, dashboard nội bộ cho khách hàng, hoặc bất kỳ dự án nào cần một trang admin được làm nhanh nhưng vẫn chuyên nghiệp. Ngoài ra thì Filament cũng cho phép tạo các component tuỳ chỉnh để có thể tạo giao diện khác với những component có sẵn, nhưng sẽ cần 1 chút kiến thức về component và Livewire của Laravel.

Môi trường yêu cầu

PHP        >= 8.2
Composer   >= 2.x
Laravel    >= 12.x
MySQL      >= 8.x  (hoặc MariaDB, PostgreSQL)
Node.js    >= 20.x (cho Vite)

Trong bài này mình sẽ dùng phiên bản Laravel 12, các bạn có thể dùng bản mới nhất là Laravel 13 nếu có PHP >=8.3

Bước 1: Cài đặt Laravel 12

Đầu tiên mình sẽ tạo một dự án Laravel mới bằng lệnh composer ở terminal (hoặc cmd ở máy tính Window)

# Tạo project Laravel mới
composer create-project laravel/laravel filament-demo

# Mở project bằng VS Code
code filament-demo

Lưu ý: các bạn có thể sử dụng lệnh laravel new để cài đặt cũng được, nhưng lệnh composer sẽ cho mình bỏ qua tất cả các lựa chọn cài đặt Starter Kit và AI Boost của Laravel.

Tiếp theo cấu hình file .env để kết nối với database, chỉnh phần DB_CONNECTION thành mysql (hoặc mariadb/postgres). Nhập các phần tên database, username và password tương ứng với database của bạn.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=filament-demo
DB_USERNAME=root
DB_PASSWORD=

Tiếp theo ở terminal chạy các lệnh sau

# Tạo các bảng database mặc định
php artisan migrate

#cài đặt package npm
npm install

# Khởi động server Laravel và chạy npm run dev cùng lúc
composer run dev

Lưu ý: composer run dev sẽ chạy đồng thời cả PHP server lẫn Vite, tiết kiệm thời gian hơn so với chạy từng lệnh riêng.

Bước 2: Cài đặt Filament

Chúng ta dùng lệnh sau ở Terminal để tiến hành cài đặt Filament

composer require filament/filament

Tiếp theo là cài đặt Admin Panel đầu tiên

# Cài đặt Filament Panel (Admin Panel mặc định)
php artisan filament:install --panels

Lệnh này sẽ tạo file AdminPanelProvider trong thư mục app/Providers/Filament/AdminPanelProvider. Đây sẽ là nơi để cấu hình toàn bộ admin panel của bạn.

Lưu ý: Ở đây hệ thống sẽ hỏi bạn muốn panel là gì, mặc dịnh sẽ là admin với url truy cập là <host của bạn>/admin (ví dụ http://localhost:8000/admin), bạn có thể tuỳ ý thay đổi admin thành các tên khác, Filament sẽ tự thay đổi url và tên PanelProvider tương ứng theo.

Kế đến, chúng ta sẽ tạo user đầu tiên bằng Filament luôn mà không cần cài thêm starter kit khác bằng lệnh

php artisan make:filament-user

Hệ thống sẽ hỏi bạn các thông tin gồm username, email, password. Bạn có thể thoải mái nhập các thông tin user mình muốn tạo ở đây.

Sau khi tạo User, chúng ta truy cập vào Admin Panel bằng link

#tuỳ chỉnh localhost:800 cho đúng với host của bạn
http://localhost:8000/admin/login

Giờ đây sau khi truy cập vào giao diện admin, các bạn sẽ thấy 1 trang gồm 2 plugin Filament chọn sẵn, cùng với giao diện khá đẹp (theo cảm nhận của mình), cùng với đó là chức năng đăng xuất user, chức năng thay đổi Dark/Light mode cũng đã có sãn. Rất nhanh phải không!

Bước 3: Tạo CRUD đầu tiên bằng lệnh Filament Resource

Bước 3.1. Tạo model và migration cho Post

Đầu tiên, chúng ta cần tạo model và migration cho resouce cần tạo, trong bài này mình sẽ dùng Post (Bài viết) để dễ hình dung

Chạy lệnh sau trong terminal

# Tạo Model Post kèm Migration
php artisan make:model Post -m

Tuỳ chỉnh file migration trong thư mục database/migration/…create_posts_….php và sửa phần up

#phần này là kiến thức cơ bản của Laravel nên mình không giải thích sâu, chủ yếu là để tạo 1 bảng "posts" trong database với các cột từ $table->
public function up(): void
{
    Schema::create('posts', function (Blueprint $table)    {
        $table->id();
        $table->string('title');         
        $table->text('content');   
        $table->timestamps();
    });
}

Tiếp theo chạy lệnh php artisan migrate để hệ thống đọc cái file kia và tạo bảng trong database, nếu lệnh chạy không lỗi là tạo thành công, nếu lỗi thì các bạn cứ bình luận cho mình xem và hướng dẫn gỡ nha.

Các bạn có thể truy cập vào database để coi có tạo được bảng posts trong database của mình chưa

Tiếp đó, các bạn vào app/Models/Post.php để cấu hình $fillable cho model này (bắt buộc để Filament có thể thêm dữ liệu vào cột được)

class Post extends Model {
    public $fillable = ['title','content'];
}

Bước 3.2. Tạo Filament Resource (Post CRUD)

Chạy lệnh sau trong terminal để tạo ra PostResource

php artisan make:filament-resource Post 

Hệ thống sẽ hỏi lại bạn các lựa chọn bao gồm có muốn map với cột trong databse không (nên chọn Yes), có muốn page View riêng không (tạm thời chọn No), tiêu đề của model này là gì – tiêu đề này sẽ hiển thị ở các phần liên quan khác, các bạn cứ gõ title hoặc tạm thời để mặc định cũng được.

Ở đây có thể thêm tuỳ chọn –generate sau Post (nhớ cách khoảng) để resource tự map với các cột trong database, hoặc thêm –simple nếu các bạn muốn create và edit là dạng popup (modal) thay vì 1 trang riêng. Nhưng tạm thời hãy đi cùng mình không chọn gì

Lệnh này sẽ tạo ra thư mục app/Filament/Resources/PostResource/ gồm các file và thư mục sau

app/Filament/Resources/
└── PostResource/
    ├── PostResource.php       # Cấu hình chính của Post
    ├── Pages/
    │   ├── ListPosts.php      # Trang danh sách
    │   ├── CreatePost.php     # Trang tạo mới
    │   └── EditPost.php       # Trang chỉnh sửa
    └── Schemas/
        ├── PostForm.php       # Cấu hình Form
        └── PostTable.php      # Cấu hình Table

Các bạn có thể truy cập lại trang admin và sẽ nhìn thấy một phần mới là Post đã nằm trên sidebar, vào để thử nghiệm thêm, sửa thoải mái vì Filament đã làm sẵn các phần cơ bản cho chúng ta rồi.

Bước 4: Tuỳ chỉnh trong Filament

Mặc định khi lưu lại ở Create và Edit thì sẽ bị điều hướng về trang Edit. Để thay đổi cái này, các bạn có thể thêm hàm sau vào file CreatePost hoặc EditPost

protected function getRedirectUrl(): string
{
    return $this->getResource()::getUrl('index');
}

Hoặc cấu hình cho toàn bộ AdminPanel bằng cách tuỳ chỉnh trong file AdminPanelProvider

#thêm ở đâu sau panel cũng được
return $panel
->resourceCreatePageRedirect("index")
->resourceEditPageRedirect("index")
->....các dòng tiếp..;

Tiếp theo để tuỳ chỉnh ngôn ngữ cho table, các bạn có thể thêm ->label() trong các phần TextColumn của file PostTable.php

public static function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('title')
                ->label('Tiêu đề')
                ->searchable()    // Cho phép tìm kiếm
                ->sortable(),     // Cho phép sắp xếp

            TextColumn::make('content')
                ->label('Nội dung')
                ->toggleable(),   // Ẩn/hiện được

            TextColumn::make('created_at')
                ->label('Ngày tạo')
                ->dateTime('d/m/Y'), // Định dạng ngày
        ])
        ->actions([
            Tables\Actions\EditAction::make(),
            Tables\Actions\DeleteAction::make(), // Nút xóa có confirm
        ]);
}

Tương tự Form cũng có thể thay đổi trong PostForm. Ở phần content thay vì dùng TextArea, các bạn có thể dùng RichEditor để thấy một cái editor xịn mịn mà không cần phải xài thêm package nào như thông thường

Ngoài ra các bạn có thể thay đổi cách hiển thị tên Resource ở side bar và cái chỗ tiêu đề của Index hay các vị trí khác bằng cách thay đổi cấu hình sau trong file PostResource

protected static ?string $modelLabel = 'Bài viết';
protected static ?string $pluralModelLabel = 'Danh sách bài viết';

Để đổi toàn bộ các chỗ tiếng Anh mặc định của Filament sang tiếng Việt, các bạn có thể thay đổi APP_LOCALE ở file .env thành vi.

APP_LOCALE=vi

Sau đó xoá config để Filament nhận đúng cấu hình và tự thay đổi

php artisan config:clear

Bước 5: Tạo trường chọn mối quan hệ cho Form

Bước 5.1. Tạo model và migration cho Category, mối quan hệ (relationship) cho Post.

Ở bước này mình sẽ thêm 1 model là Category và file migration của nó và lệnh alter table để thêm category_id vào bảng posts do trước đó mình chưa tạo cột này bằng lệnh

#tạo category model và file migration
php artisan make:model Category -m

#tạo migration cho alter_column trong posts
php artisan make:migration alter_posts_id_category_table
#cái phần alter_post... các bạn có thể đặt tuỳ ý miễn sao dễ nhớ dễ hiểu

Tiếp theo cấu hình các cột cho Category trong file create_categories_table

//trong ví dụ này category của mình chỉ có name thôi
public function up(): void {
  Schema::create('categories', function (Blueprint $table) {
    $table->unsignedInteger('id')->autoIncrement();
    $table->string('name');
    $table->timestamps();
  }
}

Tiếp tục là khoá ngoại cho file alter_posts

//thêm cột và khoá ngoại cho bảng posts
public function up(): void {
  Schema::table('posts', function (Blueprint $table) {
    $table->unsignedInteger('category_id')->nullable();
    $table->foreign('category_id', 'fk_post_category')
                ->on('categories')
                ->references('id')
                ->cascadeOnUpdate()
                ->restrictOnDelete();
  }
}
/*thêm bỏ khoá ngoại và cột category và down() để đảm bảo khi chạy migrate:rollback, cột sẽ được xoá.*/
public function down(): void{
  Schema::table('posts', function (Blueprint $table) {
    $table->dropForeign('fk_post_category');
    $table->dropColumn('category_id');
  }
}

Kế đến, chạy lệnh php artisan migrate trong terminal để tạo bảng categories và cột category_id là khoá ngoại trong bảng posts.

Tương tự với Post, các bạn truy cập Category model và thêm name vào $fillable để có thể sử dụng CRUD của Filament

Sau đó vào model Post để cấu hình fillable cho category_id và tên mối quan hệ (relationship) cho nó

public $fillable = [
    'title', 
    'content', 
    'category_id'
];
//relationship cho category
public function category(): BelongsTo
{
    return $this->belongsTo(Category::class);
}

Bước 5.2. Tạo Category Resource

Cách tạo Category Resource cũng tương tự như Post, mình sẽ dùng lệnh bên dưới để tạo ra 1 resource không có trang create và edit riêng (–simple)

php artisan make:filament-resource Category --simple --generate

Các bạn có thể tuỳ chỉnh như cách mình đã hướng dẫn với PostResource ở trên

Bước 5.3. Tạo Select Category cho PostForm

Ở phần PostForm, bên dưới TextArea hoặc RichEditor của phần content, mình sẽ bổ sung thêm đoạn sau

Select::make('category_id')
    ->label('Chuyên mục')
    ->relationship('category', 'name') 
    ->required()
    ->createOptionForm([           
        TextInput::make('name')
            ->label('Tên chuyên mục')
            ->required(),
    ]),

Đoạn code này cho phép mình lấy trực tiếp chuyên mục theo relationship mình đặt trong Post model, hiển thị label theo cột name của Category. Ngoài ra, mình cũng thêm phần tuỳ chọn createOptionForm để có thể thêm trực tiếp chuyên mục mình muốn vào trong database nếu như trong chỗ chọn chưa có.

Bước 5.4. Hiển thị chuyên mục trong PostTable (trang index/list)

Các bạn có thể bổ sung 1 cột TextColumn ở bất kì vị trí nào mình muốn trong phần columns([]) để hiển thị cột chuyên mục này

return $table
   ->columns([
      ....
      TextColumn::make('category.name')
        ->label('Chuyên mục')
        ->sortable()
        ->searchable(),
      .....
   ]);

Cú pháp category.name là cách Filament truy cập dữ liệu trong relationship liên quan, nếu có thêm hình ảnh hay slug, các bạn cũng có thể dùng cách này để lấy thêm thông tin từ bảng liên kết. Filament đã tối ưu sẵn phần load model nên sẽ không xuất hiện tình trạng query N+1 bằng cách lấy dữ liệu này.

Tổng kết

Qua bài này, mình đã hướng dẫn các bạn cách cài đặt Filament v5 trên Laravel 12, tạo ra các Resource CRUD, cũng như tuỳ chỉnh một số Table/Form hay chuyển ngôn ngữ. Ngoài ra còn có cách hiển thị theo mối quan hệ giữa các model. Bằng cách sử dụng Filament, mình tin rằng việc xây dựng admin panel sẽ được rút ngắn đáng kể.

Nếu các bạn có câu hỏi hoặc thắc mắc gì, có thể để lại cho mình ở phần bình luận hoặc tại đây. Các bạn cũng có thể xem thêm các video về chủ đề này tại đây

Tài liệu tham khảo

1/ FilamentPHP: Tài liệu chính thức của FilamentPHP

2/ Laravel: Tài liệu Laravel phiên bản 12

3/ Hướng dẫn tạo CRUD siêu nhanh bằng Filament

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *