🧬《模型与迁移:Flarum 数据世界的基因密码》
“在 Flarum 的宇宙中,数据是恒星,模型是引力,迁移是星图。掌握它们,你就能塑造属于自己的星系。”
🧠 宏观视角:模型与迁移的意义
Flarum 是一个围绕数据构建的论坛系统:用户、讨论、帖子、通知、权限……一切都源于数据。要扩展它,我们必须理解如何创建、修改和访问这些数据。
Flarum 使用 Laravel 的数据库组件作为底层基础,因此如果你熟悉 Laravel 的迁移和 Eloquent 模型,你会如鱼得水。
⚙️ 迁移(Migrations):数据库的时间机器
迁移是数据库结构的版本控制系统。它们允许你:
- 创建或修改表结构
- 添加或删除列
- 设置默认配置或权限
- 插入初始数据
🧱 迁移结构
Flarum 的迁移文件返回一个包含 up 和 down 两个函数的数组:
use Illuminate\Database\Schema\Builder;
return [
'up' => function (Builder [imath:0]schema) {
// 执行迁移操作
},
'down' => function (Builder [/imath:0]schema) {
// 回滚迁移操作
}
];
你可以使用 Laravel 的 Schema Builder 来定义表结构,也可以使用 Flarum 提供的 Migration 助手方法。
🏗️ 创建表
use Flarum\Database\Migration;
use Illuminate\Database\Schema\Blueprint;
return Migration::createTable('books', function (Blueprint [imath:0]table) {
$table->increments('id');
$table->string('title');
$table->timestamps();
});
✂️ 添加/删除列
添加列:
return Migration::addColumns('users', [
'nickname' => ['string', 'length' => 100, 'nullable' => true],
'age' => ['integer', 'unsigned' => true]
]);
删除列:
return Migration::dropColumns('users', [
'nickname' => ['string'],
'age' => ['integer']
]);
🔄 重命名表或列
重命名表:
return Migration::renameTable('old_table', 'new_table');
重命名列:
return Migration::renameColumns('users', [
'old_column' => 'new_column'
]);
🧩 设置默认配置和权限
添加默认设置:
return Migration::addSettings([
'my-extension.default_color' => 'blue'
]);
添加默认权限:
use Flarum\Group\Group;
return Migration::addPermissions([
'my-extension.can_edit' => Group::MODERATOR_ID
]);
⚠️ 注意:这些操作只适用于新增设置或权限,已有配置不会被覆盖。
🧬 数据迁移(高级)
迁移不仅能改结构,也能改数据。例如:
use Flarum\User\User;
return [
'up' => function () {
User::whereNull('nickname')->update(['nickname' => '匿名用户']);
},
'down' => function () {
// 可选的回滚逻辑
}
];
🧱 后端模型:数据的守门人
Flarum 使用 Eloquent 模型来操作数据库中的数据。你可以:
- 添加新的模型类(用于新表)
- 扩展已有模型(添加字段、默认值、关系)
🆕 添加新模型
新模型应继承 Flarum\Database\AbstractModel,而不是 Laravel 原生的 Model:
use Flarum\Database\AbstractModel;
class Book extends AbstractModel
{
protected $table = 'books';
}
🧩 扩展已有模型
使用 Extend\Model:
use Flarum\Extend;
use Flarum\User\User;
return [
(new Extend\Model(User::class))
->default('is_alive', true)
->cast('suspended_until', 'datetime')
->cast('is_admin', 'boolean')
];
🔗 添加关系
你可以为模型添加 hasOne、hasMany、belongsTo、belongsToMany 等关系:
(new Extend\Model(User::class))
->hasOne('phone', App\Phone::class, 'user_id', 'id')
->belongsTo('country', App\Country::class, 'country_id')
->hasMany('comments', App\Comment::class, 'user_id')
->belongsToMany('roles', App\Role::class, 'role_user', 'user_id', 'role_id');
甚至可以定义自定义关系:
->relationship('mobile', App\Phone::class, function ([/imath:0]user) {
return $user->belongsToMany(Discussion::class, 'recipients')
->withTimestamps()
->wherePivot('removed_at', null);
});
🌐 前端模型:API 数据的镜像
Flarum 前端使用 Mithril 构建,并通过 JSON:API 与后端通信。前端模型是对 API 资源的封装。
📦 获取数据
使用 app.store.find:
// 获取所有 discussions,按创建时间排序
app.store.find('discussions', { sort: 'createdAt' }).then(console.log);
// 获取 ID 为 123 的 discussion
app.store.find('discussions', 123).then(console.log);
缓存后的数据可以通过 all 或 getById 获取:
const allDiscussions = app.store.all('discussions');
const oneDiscussion = app.store.getById('discussions', 123);
🆕 添加新模型
定义模型类:
import Model from 'flarum/common/Model';
export default class Tag extends Model {
title = Model.attribute('title');
createdAt = Model.attribute('createdAt', Model.transformDate);
parent = Model.hasOne('parent');
discussions = Model.hasMany('discussions');
}
注册模型:
import Extend from 'flarum/common/extenders';
import Tag from './models/Tag';
export default [
new Extend.Store().add('tags', Tag)
];
🧩 扩展已有模型
new Extend.Model(Discussion)
.attribute('slug')
.hasOne('user')
.hasMany('posts');
💾 保存数据
保存属性:
discussion.save({ title: 'Hello, world!' }).then(console.log);
保存关系:
user.save({
relationships: {
groups: [
app.store.getById('groups', 1),
app.store.getById('groups', 2)
]
}
});
创建新资源:
const discussion = app.store.createRecord('discussions');
discussion.save({ title: 'New Topic' });
删除资源:
discussion.delete().then(() => console.log('Deleted'));
🔄 后端模型 vs 前端模型:一体两面
对比维度 | 后端模型 | 前端模型 |
来源 | 数据库表结构 | API Serializer 输出 |
继承基类 | AbstractModel (Eloquent) | flarum/common/Model |
作用 | 直接操作数据库 | 与 API 通信、缓存、渲染 |
保存数据 | 直接写入数据库 | 发送 API 请求 |
字段命名 | 与数据库字段一致 | 可与后端不同,由 Serializer 决定 |
🧾 结语:掌握模型与迁移,驭数据如风
Flarum 的模型与迁移系统,是其扩展机制的核心。它既继承了 Laravel 的强大,又通过 Extender 系统提供了灵活的扩展能力。无论你是要添加一个字段,还是构建一整套新功能,掌握模型与迁移的使用,是你成为 Flarum 高阶开发者的必经之路。
所以,别再犹豫,拿起你的键盘,开始塑造属于你的数据世界吧!
📚 参考资料
- Flarum 官方文档 - Models and Migrations:https://docs.flarum.org/extend/models
- Laravel Eloquent ORM:https://laravel.com/docs/eloquent
- Laravel Migrations:https://laravel.com/docs/migrations
- JSON:API 标准:https://jsonapi.org/
- Flarum API 文档:https://docs.flarum.org/internal/api/