Road to growth of rookie

Meaningful life is called life

0%

Laravel(Lumen) 5.X 修改时间字段为 INT 类型

Our predecessors have already encountered problems we may encounter, so it is very important to learn efficient Google

LaravelLumen 框架会自动维护模型 (对应数据库表) 的 created_atupdated_atdeleted_at 字段,三个字段非常好用且被框架原生支持,如果要自己实现的话非常的麻烦。但是三个字段在数据库中默认都是 timestampdatetime 类型的,记录一下将三个字段修改为 int 类型的过程。

关于为什么要将 datetimetimestamp 两种时间类型替换成 int 类型,可以看一下 CSDN 上的这篇文章: MYSQL数据库时间字段INT, TIMESTAMP, DATETIME性能效率比较

laravel

创建一个测试使用的表

1
2
3
4
5
6
7
CREATE TABLE `test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` int(10) unsigned NOT NULL DEFAULT '0',
`updated_at` int(10) unsigned NOT NULL DEFAULT '0',
`deleted_at` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='测试表';

修改模型中三个字段默认的时间格式

其实如果只是修改三个字段在数据库中保存的数据类型是非常简单的,这个也是被框架原生支持的。

Laravel (PS:以下的 Laravel 代表 LaravelLumen 两个框架,毕竟它们是差不多的) 的模型基类 Illuminate\Database\Eloquent\Model 中引入了很多 Trait, 其中有一个 Trait: Illuminate\Database\Eloquent\Concerns\HasAttributes,该 Trait 中定义了一个 $dateFormat 属性。该属性表示 Laravel 中三个时间字段和 Illuminate\Database\Eloquent\Concerns\HasAttributes$dates 属性所包含字段的时间格式。

默认的 $dateFormat 属性的时间格式为 Y-m-d H:i:s,该字段可被赋值的值的跟 date 函数的第一个值一样。所以如果将该属性的值设置为 'U' (详见 date 函数的 format 准换说明) 当通过模型 createsave 的方式创建或修改数据库内容时,created_atupdated_atdeleted_at 三个字段的值就会被转换为 UNIX 时间戳。

代码示例
  • 修改默认的时间格式后的模型定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

/**
* Class Test
* @package App
*/
class Test extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'test';

/**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat = 'U';
}
  • 使用 tinker 创建一条新的数据并查看数据库内容

创建结果
数据库内容

deleted_at 的默认值修改为非 NULL

但是对我个人习惯来说,我喜欢将这三个字段在数据库中的默认值设置为 0 而不是框架原生支持的 NULL,这样做的原因可以看一下在 开源中国 上的一篇文章 mysql 字段设计,尽量设置不允许为null

这样的话框架的原生软删除就会碰到一个问题: 所有数据都是被软删除的! 为了防止这些情况发生,看了一下 Laravel 框架软删除的实现,并做了一些兼容,防止在字段的默认值非 NULL 时获取不到数据。

框架原生的软删除主要是依赖 Illuminate\Database\Eloquent\SoftDeletes 这个 Trait 来实现的。在该 Trait 中引入了一个全局的 ScopeIlluminate\Database\Eloquent\SoftDeletingScope,这个 Scope 中主要定义的就是对软删除数据的过滤、回滚等几个方法的实现。如果我们想要修改对 deleted_at 字段的查询过滤,需要重写该 Scope 的几个方法

重写 Illuminate\Database\Eloquent\SoftDeletingScope 的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingScope as SystemSoftDeletingScope;

/**
* Class SoftDeletingScope
* @package App
*/
class SoftDeletingScope extends SystemSoftDeletingScope
{
/**
* Default value when the resource is not soft deleted
*
* @var int
*/
const NOT_DELETE_DEFAULT_VALUE = 0;

/**
* Apply the scope to a given Eloquent query builder.
* Filter soft deleted data by default
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
*
* @return void
*/
public function apply(Builder $builder, Model $model)
{
$builder->where($model->getQualifiedDeletedAtColumn(), self::NOT_DELETE_DEFAULT_VALUE);
}

/**
* Add the restore extension to the builder.
* Add restore extensions to restore soft deleted data back to normal data
*
* @param \Illuminate\Database\Eloquent\Builder $builder
*
* @return void
*/
protected function addRestore(Builder $builder)
{
$builder->macro('restore', function (Builder $builder) {
$builder->withTrashed();

return $builder->update([$builder->getModel()->getDeletedAtColumn() => self::NOT_DELETE_DEFAULT_VALUE]);
});
}

/**
* Add the without-trashed extension to the builder.
* Filtering data that has been soft deleted
*
* @param \Illuminate\Database\Eloquent\Builder $builder
*
* @return void
*/
protected function addWithoutTrashed(Builder $builder)
{
$builder->macro('withoutTrashed', function (Builder $builder) {
$model = $builder->getModel();

$builder->withoutGlobalScope($this)->where($model->getQualifiedDeletedAtColumn(),
self::NOT_DELETE_DEFAULT_VALUE);

return $builder;
});
}

/**
* Add the only-trashed extension to the builder.
* Add an extension to retrieve only data that has been soft deleted
*
* @param \Illuminate\Database\Eloquent\Builder $builder
*
* @return void
*/
protected function addOnlyTrashed(Builder $builder)
{
$builder->macro('onlyTrashed', function (Builder $builder) {
$model = $builder->getModel();

$builder->withoutGlobalScope($this)->where($model->getQualifiedDeletedAtColumn(), '!=',
self::NOT_DELETE_DEFAULT_VALUE);

return $builder;
});
}
}
定义模型并验证结果
  • 模型定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace App;

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;

/**
* Class Test
* @package App
*/
class Test extends Model
{
/** Introduced framework native soft deletes */
use SoftDeletes;

/**
* Modify the framework native soft delete lock dependent
* global scope to be custom scope
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}

/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'test';

/**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat = 'U';
}
  • 使用 tinker 命令软删除一条数据并验证结果

软删除结果
数据库内容

  • 软删除数据后查询

软删除结果

其他的方法和操作就不贴出来了 (PS:怪麻烦的)。总的来说 Laravel 框架及其的好用,但是有些地方为了个人的习惯和逻辑可能需要稍稍的改动。不过在修改的过程中可以学到很多东西,Laravel 作者在设计框架的时候使用了非常多的设计模式。