基于 Laravel 和 Filament 搭建内容管理系统(CMS)指南
利用 Laravel 与 Filament 搭建 CMS 系统,不仅高效,还兼具灵活性。Filament 所提供的现代化管理后台界面,让内容管理变得既直观又高效。下面是从零开始搭建功能完备的 CMS 系统的详细步骤。
目录
- 项目初始化
- 安装 Filament
- 定义数据模型
- 创建 Filament 资源
- 配置权限和角色
- 创建内容管理功能
- 前端集成(可选)
- 额外功能
- 部署
- 参考资源
- 总结
1. 项目初始化
1.1 创建新的 Laravel 项目
要是还没创建Laravel项目,借助Composer就能轻松搞定:
composer create-project laravel/laravel cms-system
随后进入项目目录:
cd cms-system
1.2 设置数据库连接
在 .env
文件里配置数据库相关参数:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=cms_system
DB_USERNAME=root
DB_PASSWORD=your_password
接着创建数据库(以MySQL为例):
CREATE DATABASE cms_system;
1.3 运行迁移
运行初始迁移,生成必要的数据表:
php artisan migrate
2. 安装 Filament
2.1 使用 Composer 安装 Filament
执行如下命令:
composer require filament/filament
2.2 运行 Filament 安装命令
php artisan filament:install
安装期间,Filament会提示创建管理员用户,按提示操作完成安装。
2.3 构建前端资源
先安装前端依赖,再构建资源:
npm install
npm run build
处于开发环境时,可使用:
npm run dev
要确保 public/build/manifest.json
文件存在。
3. 定义数据模型
依据 CMS 系统的需求,明确要管理的内容,比如文章(Posts)、分类(Categories)、标签(Tags)等。
3.1 创建 Eloquent 模型和迁移
以文章(Post)为例:
php artisan make:model Post -m
编辑迁移文件 database/migrations/xxxx_xx_xx_create_posts_table.php
:
public function up()
{
Schema::create('posts', function (Blueprint table) {table->id();
table->string('title');table->text('content');
table->foreignId('category_id')->constrained()->onDelete('cascade');table->timestamps();
});
}
同样地,为分类(Category)创建模型与迁移:
php artisan make:model Category -m
编辑迁移文件 database/migrations/xxxx_xx_xx_create_categories_table.php
:
public function up()
{
Schema::create('categories', function (Blueprint table) {table->id();
table->string('name');table->timestamps();
});
}
最后运行迁移:
php artisan migrate
3.2 定义模型关系
在 App\Models\Post.php
里:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected fillable = ['title', 'content', 'category_id'];
public function category()
{
returnthis->belongsTo(Category::class);
}
}
在 App\Models\Category.php
中:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
protected fillable = ['name'];
public function posts()
{
returnthis->hasMany(Post::class);
}
}
4. 创建 Filament 资源
4.1 创建 Post 资源
用 Filament 提供的 Artisan 命令生成资源:
php artisan make:filament-resource Post
这会在 app/Filament/Resources/PostResource
目录下生成所需文件。
4.2 配置 Post 资源
编辑 app/Filament/Resources/PostResource.php
:
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PostResource\Pages;
use App\Models\Post;
use Filament\Forms;
use Filament\Tables;
use Filament\Resources\Resource;
class PostResource extends Resource
{
protected static?string model = Post::class;
protected static?stringnavigationIcon = 'heroicon-o-document-text';
protected static?int navigationSort = 1;
public static function form(Forms\Formform): Forms\Form
{
return form
->schema([
Forms\Components\TextInput::make('title')
->required()
->maxLength(255),
Forms\Components\Select::make('category_id')
->relationship('category', 'name')
->required(),
Forms\Components\RichEditor::make('content')
->required(),
]);
}
public static function table(Tables\Tabletable): Tables\Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')->sortable(),
Tables\Columns\TextColumn::make('title')->sortable()->searchable(),
Tables\Columns\TextColumn::make('category.name')->label('Category')->sortable()->searchable(),
Tables\Columns\TextColumn::make('created_at')->dateTime(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListPosts::route('/'),
'create' => Pages\CreatePost::route('/create'),
'edit' => Pages\EditPost::route('/{record}/edit'),
];
}
}
4.3 创建 Category 资源
同样的流程,创建并配置分类资源:
php artisan make:filament-resource Category
编辑 app/Filament/Resources/CategoryResource.php
:
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\CategoryResource\Pages;
use App\Models\Category;
use Filament\Forms;
use Filament\Tables;
use Filament\Resources\Resource;
class CategoryResource extends Resource
{
protected static?string model = Category::class;
protected static?stringnavigationIcon = 'heroicon-o-collection';
protected static?int navigationSort = 2;
public static function form(Forms\Formform): Forms\Form
{
return form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
]);
}
public static function table(Tables\Tabletable): Tables\Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')->sortable(),
Tables\Columns\TextColumn::make('name')->sortable()->searchable(),
Tables\Columns\TextColumn::make('created_at')->dateTime(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListCategories::route('/'),
'create' => Pages\CreateCategory::route('/create'),
'edit' => Pages\EditCategory::route('/{record}/edit'),
];
}
}
4.4 创建其他资源
按需创建更多资源,像是标签(Tags)、用户(Users)、媒体(Media) 等。
5. 配置权限和角色
为保障只有授权用户能访问、管理 CMS 内容,推荐使用 Spatie Laravel Permission 包管理角色和权限。
5.1 安装 Spatie Laravel Permission
composer require spatie/laravel-permission
5.2 发布配置和迁移
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
5.3 配置 User 模型
在 App\Models\User.php
中添加 HasRoles
trait:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// 其他代码...
}
5.4 创建角色和权限
用 Tinker 或编写 Seeder 来创建角色与权限:
php artisan tinker
在 Tinker 里:
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use App\Models\User;
// 创建角色
adminRole = Role::create(['name' => 'admin']);editorRole = Role::create(['name' => 'editor']);
// 创建权限
managePosts = Permission::create(['name' => 'manage posts']);manageCategories = Permission::create(['name' => 'manage categories']);
// 分配权限给角色
adminRole->givePermissionTo(['manage posts', 'manage categories']);editorRole->givePermissionTo(['manage posts']);
// 查找用户并分配角色
user = User::where('email', 'admin@example.com')->first();
if (user) {
user->assignRole('admin');
} else {user = User::create([
'name' => 'Admin User',
'email' => 'admin@example.com',
'password' => bcrypt('password'), // 请用更安全的密码
]);
$user->assignRole('admin');
}
5.5 配置 Filament 中间件
在 config/filament.php
中,限定 Filament 仅允许特定角色用户访问后台:
'auth' => [
'guard' => 'web',
'passwords' => 'users',
'middleware' => [
'web',
'auth',
function (request,next) {
if (!request->user() ||!request->user()->hasRole('admin')) {
abort(403);
}
return next(request);
},
],
],
6. 创建内容管理功能
依据 CMS 需求,创建更多内容管理资源,如页面(Pages)、媒体(Media)、菜单(Menus)等。
示例:创建 Page 资源
php artisan make:model Page -m
php artisan make:filament-resource Page
编辑 database/migrations/xxxx_xx_xx_create_pages_table.php
:
public function up()
{
Schema::create('pages', function (Blueprint table) {table->id();
table->string('title');table->string('slug')->unique();
table->text('content');table->timestamps();
});
}
运行迁移:
php artisan migrate
编辑 app/Filament/Resources/PageResource.php
:
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\PageResource\Pages;
use App\Models\Page;
use Filament\Forms;
use Filament\Tables;
use Filament\Resources\Resource;
class PageResource extends Resource
{
protected static?string model = Page::class;
protected static?stringnavigationIcon = 'heroicon-o-document';
protected static?int navigationSort = 3;
public static function form(Forms\Formform): Forms\Form
{
return form
->schema([
Forms\Components\TextInput::make('title')
->required()
->maxLength(255),
Forms\Components\TextInput::make('slug')
->required()
->maxLength(255)
->unique(ignoreRecord: true),
Forms\Components\RichEditor::make('content')
->required(),
]);
}
public static function table(Tables\Tabletable): Tables\Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')->sortable(),
Tables\Columns\TextColumn::make('title')->sortable()->searchable(),
Tables\Columns\TextColumn::make('slug')->sortable()->searchable(),
Tables\Columns\TextColumn::make('created_at')->dateTime(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListPages::route('/'),
'create' => Pages\CreatePage::route('/create'),
'edit' => Pages\EditPage::route('/{record}/edit'),
];
}
}
7. 前端集成(可选)
要是需要在前端展示 CMS 内容,能用 Blade 模板,也能构建 API 端点。
7.1 使用 Blade 模板
创建前端视图展示 CMS 内容,比如在 resources/views/pages.blade.php
里:
@extends('layouts.app')
@section('content')
<h1>Pages</h1>
@foreach(pages aspage)
<div>
<h2>{{ page->title }}</h2>
<div>{!!page->content!!}</div>
</div>
@endforeach
@endsection
在控制器里获取数据:
<?php
namespace App\Http\Controllers;
use App\Models\Page;
class PageController extends Controller
{
public function index()
{
pages = Page::all();
return view('pages', compact('pages'));
}
public function show(slug)
{
page = Page::where('slug',slug)->firstOrFail();
return view('page', compact('page'));
}
}
定义路由:
use App\Http\Controllers\PageController;
Route::get('/pages', [PageController::class, 'index']);
Route::get('/pages/{slug}', [PageController::class, 'show']);
7.2 构建 API
要是前端用 JavaScript 框架(如 Vue.js、React),就构建 API 端点。
创建 API 资源:
php artisan make:controller Api/PageController --api
编辑 app/Http/Controllers/Api/PageController.php
:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\PageResource;
use App\Models\Page;
use Illuminate\Http\Request;
class PageController extends Controller
{
public function index()
{
return PageResource::collection(Page::all());
}
public function show(slug)
{page = Page::where('slug', slug)->firstOrFail();
return new PageResource(page);
}
}
创建资源类:
php artisan make:resource PageResource
编辑 app/Http/Resources/PageResource.php
:
“`php
this->id,
‘title’ =>this->title,
‘slug’ => this->slug,
‘content’ =>this->content,
‘created_at’ => $this->created_at,
‘updated_at’