laravel+filament搭建cms系统

由 Jefsky 发布于 2024-10-10

使用 LaravelFilament 搭建一个内容管理系统(CMS)是一个高效且灵活的选择。Filament 提供了现代化的管理后台界面,使内容管理变得直观和高效。以下是一个详细的步骤指南,帮助您从零开始搭建一个功能强大的 CMS 系统。

目录

  1. 项目初始化
  2. 安装 Filament
  3. 定义数据模型
  4. 创建 Filament 资源
  5. 配置权限和角色
  6. 创建内容管理功能
  7. 前端集成(可选)
  8. 额外功能
  9. 部署
  10. 参考资源
  11. 总结

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()
    {
        return $this->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()
    {
        return $this->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 ?string $navigationIcon = 'heroicon-o-document-text';

    protected static ?int $navigationSort = 1;

    public static function form(Forms\Form $form): 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\Table $table): 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 ?string $navigationIcon = 'heroicon-o-collection';

    protected static ?int $navigationSort = 2;

    public static function form(Forms\Form $form): Forms\Form
    {
        return $form
            ->schema([
                Forms\Components\TextInput::make('name')
                    ->required()
                    ->maxLength(255),
            ]);
    }

    public static function table(Tables\Table $table): 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 ?string $navigationIcon = 'heroicon-o-document';

    protected static ?int $navigationSort = 3;

    public static function form(Forms\Form $form): 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\Table $table): 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 as $page)
        <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

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class PageResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'slug' => $this->slug,
            'content' => $this->content,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

定义 API 路由:

use App\Http\Controllers\Api\PageController;

Route::prefix('api')->group(function () {
    Route::get('/pages', [PageController::class, 'index']);
    Route::get('/pages/{slug}', [PageController::class, 'show']);
});

8. 额外功能

8.1 媒体管理

Filament 提供了一个强大的媒体库,可以管理上传的文件。

8.2 用户角色与权限

进一步配置用户角色和权限,以满足 CMS 的访问控制需求。

8.3 搜索和过滤

在 Filament 资源中添加搜索和过滤功能,以便更高效地管理内容。

9. 部署

在开发完成后,将 CMS 系统部署到生产环境。确保前端资源已构建,并且服务器配置正确。

9.1 构建前端资源

npm run build

9.2 运行迁移

php artisan migrate --force

9.3 清理和缓存

php artisan config:cache
php artisan route:cache
php artisan view:cache

9.4 设置文件权限

确保 storagebootstrap/cache 目录具有正确的权限。

chmod -R 755 storage
chmod -R 755 bootstrap/cache
chown -R www-data:www-data storage
chown -R www-data:www-data bootstrap/cache

10. 参考资源

11. 总结

通过以上步骤,您可以使用 LaravelFilament 搭建一个功能强大的 CMS 系统。Filament 提供了一个现代化的后台管理界面,使内容管理变得更加高效和直观。结合 Laravel 的强大功能和扩展生态系统,您可以根据需求进一步定制和扩展 CMS 的功能。

关键步骤回顾:

  1. 项目初始化:创建 Laravel 项目并配置数据库。
  2. 安装 Filament:使用 Composer 安装 Filament 并运行安装命令。
  3. 定义数据模型:创建 Eloquent 模型和迁移,定义模型关系。
  4. 创建 Filament 资源:生成并配置 Filament 资源以管理内容。
  5. 配置权限和角色:使用 Spatie Laravel Permission 管理用户角色和权限。
  6. 创建内容管理功能:根据需求创建更多的内容管理资源。
  7. 前端集成:使用 Blade 模板或构建 API 端点展示内容。
  8. 额外功能:实现媒体管理、搜索过滤等高级功能。
  9. 部署:构建前端资源,运行迁移,设置文件权限并部署到生产环境。

如果在搭建过程中遇到任何问题或需要进一步的帮助,请随时提问,我将乐意为您提供更多的指导和支持!

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:JefskyWong ——程序猿甜品店
链接:https://www.jefsky.com/blog/346
来源:https://www.jefsky.com/