我最近一直在尝试的一件事是使用模型作为标志,并取得了积极的成果。当你需要以某种方式标记你的一个模型时,你可以在表中添加一个布尔值来指示某种状态。例如,假设你向应用程序添加了一个停用用户的功能。你可以使用如下迁移来更改用户表:
php
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_deactivated')->default(false);
});
太棒了!现在,您可以更新is_deactivated数据库中的列,并 $user->is_deactivated在需要处理用户停用状态时检查代码。这是我刚开始时使用的模式,对于很多用例来说,这非常有效。
使用时间戳作为标志
然而,几年前,我在 Twitter 上看到一条帖子(遗憾的是我记不清是谁写的了,抱歉!)建议我们使用时间戳,而不是布尔标志:
php
Schema::table('users', function (Blueprint $table) {
$table->timestamp('deactivated_at')->nullable();
});
这还有一个额外的好处,就是可以让你看到用户何时被停用,而不需要太多的权衡(除了数据库存储的几个额外字节)。在应用此模式时,我倾向于isDeactivated在我的模型上添加一个方法,以确保代码仍然读起来很好。
php
public function isDeactivated(): bool
{
return $this->deactivated_at !== null;
}
简单标志的限制
在数据库中使用简单标志(无论是布尔值还是时间戳)的缺点是,我们可用的数据非常有限。在第一种情况下,我们对问题只有"是"或"否"的答案,在后一种情况下,则需要添加少量时间戳(如果我们决定再次激活用户,该时间戳将被删除)。
但是如果我们需要知道是谁停用了用户怎么办?当然,我们可以添加类似这样的内容 deactivated_by,在大多数情况下,这样就可以了。但也许我们想附加一个文本字段,执行停用的人可以添加原因或其他内容。
使用模型作为标志
我最近开始探索的解决方案是使用模型作为标志,这其实没什么神奇的。这就像添加一个与您想要标记的模型有关系的新模型一样简单。在上面能够停用用户的示例中,我们可以简单地添加一个Deactivation模型并定义两者之间的关系:
php
Schema::create('deactivations', function (Blueprint $table) {
$table->id();
$table->text('reason')->nullable();
$table->foreignId('user_id');
$table->foreignId('admin_id');
$table->timestamps();
$table->softDeletes();
});
php
public function deactivations(): HasMany
{
return $this->hasMany(Deactivation::class);
}
现在我们基本上可以添加任何我们想要的数据。通过在停用模型上启用软删除,我们还可以额外获得用户停用和重新激活的历史视图。
我们甚至可以更进一步,使关系多态并将功能提取为Deactivatable特征,从而让我们可以在几乎任何我们想要的模型上使用它。
php
Schema::create('deactivations', function (Blueprint $table) {
$table->id();
$table->text('reason')->nullable();
$table->morphs('deactivatable');
$table->timestamps();
$table->softDeletes();
});
php
trait Deactivatable
{
public function deactivations()
{
return $this->morphMany(Deactivation::class, 'deactivatable');
}
public function isDeactivated()
{
return $this->deactivations->exists();
}
// Additional helper methods
}