ASCII码 ASCII码

领略 Laravel 和 Filament 后台的魔力

发布于:2022-07-06 14:30:57  栏目:技术文档

本教程将通过创建一个后台面板的过程,带你一起领略 Laravel 的魔力,了解 Filament 后台项目。

如果你此前没接触过 Filament,就以此来作为第一个项目吧。同时,我也会为刚刚刚接触Laravel 和Livewire的信任尽量提供一些有用信息。

我们就先从复制,粘贴开始,尽快完成一个作品吧。

PHP 工具LaravelLaravel 是用于创建网页应用的PHP框架。像其他框架一样,Laravel 刚开始也有一个陡峭的学习曲线,不过一旦你入门了,你很快就能创建一个网页应用。

LivewireLivewire 是一个让前端界面和后端代码贴合的粘合剂。你可以借此创建响应式界面,不用刷新页面就能处理数据。你只需使用你学过的Laravel知识就可以使用它。

Filament AdminFilament 就像炼金术士,将以上两个元素组合,使开发者可以花费更少的时间编写后台面板。你可能会因为发现第一天居然就能做这么多东西而万分吃惊。

准备一个空的项目框架全新安装Laravel首先是从无到有创建一个全新的Laravel项目。你可以自己选择项目名,这里使用的是 magic-admin

  1. composer create-project laravel/laravel magic-admin
  2. cd magic-admin

该命令会下载最新版的 Laravel。

文档: 第一个Laravel项目

Laravel Breeze 用于用户认证使用以下命令添加完整的用户认证系统:

  1. composer require laravel/breeze --dev

注意: —dev 标志只会在开发模式下安装这个包。难道生产环境中就不需要用户认证吗?不是的。当运行以下命令安装这个包后,包里的文件都会复制到应用下面:

  1. php artisan breeze:install

请注意,如果刚接触Laravel: artisan 命令是Laravel带来一个魔法。你可以运行 php artisan list 命令查看它能做的所有事情。

Breeze 将提供完整的用户认证,也包括注册和登录表单、退出和密码重置处理。1分钟完成!

文档: Breeze Starter Kit

安装 Filament 后台接下来安装 Filament 后台:

  1. composer require filament/filament

数据库安装无论你使用的是什么样的环境,你需要为应用准备一个数据库连接。你可以在你的Laravel项目的根目录的 .env 文件中找到这些设置:

  1. DB_CONNECTION=mysql
  2. DB_HOST=127.0.0.1
  3. DB_PORT=3306
  4. DB_DATABASE=laravel
  5. DB_USERNAME=root
  6. DB_PASSWORD=

迁移文件包含了创建数据库的指令。 migrate 命令用来初始化数据库,创建像users、password_reset这样的表格等:

  1. php artisan migrate

不生效?如果命令报错,请再检查以下 .env 文件下的数据库连接配置。

文档: 执行迁移

编译javascript 和 CSS在浏览器中加载网站前,需要先将使用的 CSS 和 Javascript 进行编译。本教程将使用默认配置,此命令将会生成 app.css 和 app.js 文件:

  1. npm install
  2. npm run dev

文档: Laravel Mix

新项目状态检查安装了Laravel, Breeze 和 Filament 之后,我们便有了真实网页应用的骨架。

Laravel 标准的欢迎页面位于域名根目录 /Breeze 认证页面在 /login 和 /register 下(其他还有 /dashboard )Filament 将自己放在需要登录的 /admin 之后一旦注册登录,你就可以在 /admin 看到后台面板

Filament 的魔力第一次使用 Filament 创建后台的时候,我是真的惊呆了。先添加这个包到你的项目中:

  1. composer require doctrine/dbal

这能让 Filament 读取你的数据库结构。

现在,我们开始施法吧:

  1. php artisan make:filament-resource User --generate

这一 artisan 命令会基于 Breeze 创建的 User 模型生成 Filament Resource 代码。— generate 标志会读取现有的 users 表格在后台资源中自动生成匹配的字段。

功能齐全!小手一挥,你就可以创建、读取、更新和删除用户了。

现在想象一下,像这样为整个应用自动生成资源。你可以在几分钟内完成后台面板 80% 的工作量。

之所以说是 80%,因为你还需要花点时间去修补和调整自动生成的资源。这是本教程余下的时间要做的事情。涉及的魔法会随着我们的深入而减少,不过仍然有一些好玩的小诀窍。

生成假用户我们来使用Laravel 模型工厂为CRUD创建一些数据吧。这一假用户生成器也会在安装Breeze的时候为我们创建好。

首先,进入 tinker 模式,在这里可以快速运行PHP 代码:

  1. php artisan tinker

这里产生一个新命令窗口,你可以输入以下命令生成20个随机用户:

  1. User::factory()->count(20)->create();

你可以输入 quit 退出 tinker 命令行。

自定义Filament资源自动生成的 Filament 资源 有两个主要的组件:table 定义了 用户展示列表,form 定义了如何创建和编辑用户。

两者都在 app/Filament/Resources/UserResource.php 文件中定义。

调整用户列表以下就是自动生成的表格:

  1. public static function table(Table $table): Table
  2. {
  3. return $table
  4. ->columns([
  5. Tables\Columns\TextColumn::make('name'),
  6. Tables\Columns\TextColumn::make('email'),
  7. Tables\Columns\TextColumn::make('email_verified_at')
  8. ->dateTime(),
  9. Tables\Columns\TextColumn::make('created_at')
  10. ->dateTime(),
  11. Tables\Columns\TextColumn::make('updated_at')
  12. ->dateTime(),
  13. ])
  14. ->filters([
  15. //
  16. ]);
  17. }

让列表可搜索你看多简单!只要在你要搜索的字段中添加searchable()。

  1. Tables\Columns\TextColumn::make('name')->searchable(),
  2. Tables\Columns\TextColumn::make('email')->searchable(),

刷新页面后搜索框会出现在表格的顶部。很神奇吧!

文档: Filament Searchable 字段

修改 email 验证为布尔值我不关心什么时候验证,不过想知道是否已经验证了。我们可以将 TextColumn 改为 BooleanColumn。

  1. // 修改前
  2. Tables\Columns\TextColumn::make('email_verified_at')->dateTime(),
  3. // 修改后
  4. Tables\Columns\BooleanColumn::make('email_verified_at'),

它会把所有日期作为true在表格中显示为绿色的勾号。

文档: Boolean 字段

修改字段标签Email verified at 标签不再适用。我们可以设置一个自定义标签:

  1. Tables\Columns\BooleanColumn::make('email_verified_at')->label('Verified'),

文档: 设置标签

添加过滤器 Filter我们可以为表格添加过滤器,来筛选展示的记录。接下来,我们添加一个复选框用户过滤显示验证过的用户。

  1. // 在 table 方法中找到空的 filters 方法
  2. ->filters([
  3. //
  4. ]);
  5. // 你需要在顶部引入 Builder 类
  6. use Illuminate\Database\Eloquent\Builder;
  7. // 然后就可以添加 filter 了
  8. ->filters([
  9. Tables\Filters\Filter::make('verified')
  10. ->query(fn (Builder $query): Builder => $query->whereNotNull('email_verified_at')),
  11. ]);

刷新后你会在搜索框旁边看到一个小的烟囱图标。点击就可以选择只显示验证用户了。

那么再添加一个过滤器只显示未验证用户吧。

  1. ->filters([
  2. Tables\Filters\Filter::make('verified')
  3. ->query(fn (Builder $query): Builder => $query->whereNotNull('email_verified_at')),
  4. Tables\Filters\Filter::make('unverified')
  5. ->query(fn (Builder $query): Builder => $query->whereNull('email_verified_at')),
  6. ]);

文档: 表格过滤器 Filters

修改显示日期默认datetime字段会显示像 Dec 27, 2021 23:08:03 这样的日期。我们可以用标准的PHP日期格式将其改成可读性更强的格式。

  1. // 此处将显示'Dec 21, 2021',而不显示时间
  2. Tables\Columns\TextColumn::make('created_at')
  3. ->dateTime('M j, Y'),
  4. Tables\Columns\TextColumn::make('updated_at')
  5. ->dateTime('M j, Y'),

文档: Text Column 格式化

根据日期排序如果我们从新到旧对日期进行排序会很方便。使用 sortable()

  1. Tables\Columns\TextColumn::make('created_at')
  2. ->dateTime('M j, Y')
  3. ->sortable(),
  4. Tables\Columns\TextColumn::make('updated_at')
  5. ->dateTime('M j, Y')
  6. ->sortable(),

现在字段名变成可点击的了。再次点击会换方向排序。请注意,随机生成的用户会再同一天创建,因此日期看起来是一样的。

文档: 字段排序

修改用户创建/编辑表单自动生成的表单让我们可以开箱即用修改用户name、email、password字段。

表单字段同样可以在 app/Filament/Resources/UserResource.php 文件中找到。

  1. public static function form(Form $form): Form
  2. {
  3. return $form
  4. ->schema([
  5. Forms\Components\TextInput::make('name')
  6. ->required()
  7. ->maxLength(255),
  8. Forms\Components\TextInput::make('email')
  9. ->email()
  10. ->required()
  11. ->maxLength(255),
  12. Forms\Components\TextInput::make('password')
  13. ->password()
  14. ->required()
  15. ->maxLength(255),
  16. ]);
  17. }

解决密码 Hash 问题这个用户表单中包含了一个密码字段。不过,如果你输入一个新密码,它在数据库中会以明文保存。Laravel 哈希加密所有密码,因此尝试用未哈希的密码登录会登录失败。

注意: 我通常的方案是,在用户模型中创建一个 setPasswordAttribute() 修改器。这样密码一修改,就会被自动哈希。不过,这也要修改标准的认证过程,移除所有调用Hash::make()的地方,否则会双重哈希。

我们来看看 Filament 视角下是如何修改的:

  1. // 需要引入此类
  2. use Illuminate\Support\Facades\Hash;
  3. Forms\Components\TextInput::make('password')
  4. ->password()
  5. ->required()
  6. ->maxLength(255)
  7. ->dehydrateStateUsing(fn ($state) => Hash::make($state)),

上述 dehydrate 指向了 数据修改的Livewire 生命周期。dehydrateStateUsing 函数会在输入改变时调用,对密码进行哈希加密。

创建新用户时这样没有问题,不过如果你更新现有用户时,没有修改密码,就会出现双重哈希。简单的方法是,让密码字段只在创建用户页面显示。

  1. // 需要引入
  2. use Livewire\Component;
  3. Forms\Components\TextInput::make('password')
  4. ->password()
  5. ->required()
  6. ->maxLength(255)
  7. ->dehydrateStateUsing(fn ($state) => Hash::make($state))
  8. ->visible(fn (Component $livewire): bool => $livewire instanceof Pages\CreateUser),

文档: 基于页面隐藏组件

添加 email_verified_at 字段这样就能手动验证用户。email_verified_at 字段要么是一个日期,要么是 null。

你可以在表单后面插入此代码:

  1. Forms\Components\DatePicker::make('email_verified_at'),

由于 email_verified_at 在数据库中是时间戳,我选择使用了 DatePicker 而非 DateTimePicker。这样将时间设置简化为 00:00:00。

文档: 日期时间选择器

我们并需要将此属性添加到 app/Models/User.php 中的 $fillable 数组:

  1. protected $fillable = [
  2. 'name',
  3. 'email',
  4. 'password',
  5. 'email_verified_at',
  6. ];

注意: 通常这一步是通过点击操作按钮调用 user()->markEmailAsVerified() 来实现,而非使用在表单中日期字段。不过,此处目的在于展示如何添加新的字段。

收尾我们已经展示了Laravel和Filament的魔力,它们能让你用惊人的速度搭建后台面板。我们还能继续花费数小时做些微调和自定义,不过我们暂且先这样吧。接下来还有一些事情需要处理才能上线。

管理Filament导航菜单当只有一个用户资源时可能不那么重要,不过随着项目的增长,你可能需要在导航菜单中重新组织一下这些资源。

在 app/Filament/Resources/UserResource.php 文件的顶部可对其进行设置:

  1. class UserResource extends Resource
  2. {
  3. protected static ?string $model = User::class;
  4. protected static ?string $navigationIcon = 'heroicon-o-collection';
  5. ...

我们为用户模型调整使用合适的图标。既然已涉及此,我们不妨也同时添加一个排序号,来定义该导航菜单的显示顺序:

  1. // 修改此项
  2. protected static ?string $navigationIcon = 'heroicon-o-users';
  3. // 添加此项
  4. protected static ?int $navigationSort = 1;

这样用户菜单就会排在前面。

文档: Filament 后台导航

后台管理面板安全Laravel 环境设置的是 local 时,所有的用户都能访问后面面板。不过如果你上线到生产(production)环境,包括你自己在内的所有人都会被锁住。要让用户获得授权,需要修改 app/Models/User.php 文件下的用户模型。

在类声明中实现 FilamentUser 接口引入 Filament\Models\Contracts\FilamentUser添加 canAccessFilament() 方法

  1. <?php
  2. namespace App\Models;
  3. use Filament\Models\Contracts\FilamentUser;
  4. use Illuminate\Foundation\Auth\User as Authenticatable;
  5. class User extends Authenticatable implements FilamentUser
  6. {
  7. // ...
  8. public function canAccessFilament(): bool
  9. {
  10. return $this->email == 'admin@laravel-filament.cn' && $this->hasVerifiedEmail();
  11. }
  12. }

最终结果这样,我们就安装好了 Filament 后台面板,并自定义了一个资源来管理用户。使用其他模型重复这么一个过程,你就能完成一个功能齐全的后台面板了!

当你使用关联连接资源时,你也能发现一些很有趣的功能实现。不过,本教程会先至于此。

这里是修改后完整的 UserResource.php 文件。(未包含 app/Models/User.php 模型文件)。

  1. <?php
  2. namespace App\Filament\Resources;
  3. use Closure;
  4. use Filament\Forms;
  5. use App\Models\User;
  6. use Filament\Tables;
  7. use Livewire\Component;
  8. use Filament\Resources\Form;
  9. use Filament\Resources\Table;
  10. use Filament\Resources\Resource;
  11. use Illuminate\Support\Facades\Hash;
  12. use Illuminate\Database\Eloquent\Builder;
  13. use App\Filament\Resources\UserResource\Pages;
  14. use App\Filament\Resources\UserResource\RelationManagers;
  15. class UserResource extends Resource
  16. {
  17. protected static ?string $model = User::class;
  18. protected static ?string $navigationIcon = 'heroicon-o-users';
  19. protected static ?int $navigationSort = 1;
  20. public static function form(Form $form): Form
  21. {
  22. return $form
  23. ->schema([
  24. Forms\Components\TextInput::make('name')
  25. ->required()
  26. ->maxLength(255),
  27. Forms\Components\TextInput::make('email')
  28. ->email()
  29. ->required()
  30. ->maxLength(255),
  31. Forms\Components\TextInput::make('password')
  32. ->password()
  33. ->required()
  34. ->maxLength(255)
  35. ->dehydrateStateUsing(fn ($state) => Hash::make($state))
  36. ->visible(fn (Component $livewire): bool => $livewire instanceof Pages\CreateUser),
  37. Forms\Components\DatePicker::make('email_verified_at'),
  38. ]);
  39. }
  40. public static function table(Table $table): Table
  41. {
  42. return $table
  43. ->columns([
  44. Tables\Columns\TextColumn::make('name')->searchable(),
  45. Tables\Columns\TextColumn::make('email')->searchable(),
  46. Tables\Columns\BooleanColumn::make('email_verified_at')->label('Verified'),
  47. Tables\Columns\TextColumn::make('created_at')
  48. ->dateTime('M j, Y')
  49. ->sortable(),
  50. Tables\Columns\TextColumn::make('updated_at')
  51. ->dateTime('M j, Y')
  52. ->sortable(),
  53. ])
  54. ->filters([
  55. Tables\Filters\Filter::make('verified')
  56. ->query(fn (Builder $query): Builder => $query->whereNotNull('email_verified_at')),
  57. Tables\Filters\Filter::make('unverified')
  58. ->query(fn (Builder $query): Builder => $query->whereNull('email_verified_at')),
  59. ]);
  60. }
  61. public static function getRelations(): array
  62. {
  63. return [
  64. //
  65. ];
  66. }
  67. public static function getPages(): array
  68. {
  69. return [
  70. 'index' => Pages\ListUsers::route('/'),
  71. 'create' => Pages\CreateUser::route('/create'),
  72. 'edit' => Pages\EditUser::route('/{record}/edit'),
  73. ];
  74. }
  75. }
相关推荐
阅读 +