Eloquent ORM(对象关系映射)
ORM,即 Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在操作具体的 业务对象时,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法即可。
ORM 两种最常见的实现方式是 ActiveRecord 和 DataMapper,ActiveRecord 尤其流行,在很多框架中都能看到它的身影。两者的区别主要在于 ActiveRecord 中模型与数据表一一对应,而 DataMapper 中模型与数据表是完全分离的。
Laravel 中的 Eloquent ORM 使用的也是 ActiveRecord 实现方式,每一个 Eloquent 模型类对应着数据库中的一张表,我们通过调用模型类的相应方法实现对数据库的增删改查。
2、定义模型
2.1 创建模型
我们使用Artisan命令make:model生成模型类,模型类默认位于app目录下,我们也可以在创建时指定生成目录:
php artisan make:model Models/Post
这样就会在app目录下生成一个Models目录,并且在Models目录下生成一个Post模型类。Laravel 中所有模型类继承自IlluminateDatabaseEloquentModel类。
2.2 指定表名
如果不手动指定,默认Post对应的数据表为posts,以此类推。也可以通过设置$table属性自定义表名:
public $table = 'posts';
2.3 指定主键
Eloquent默认数据表主键为id,当然也可以通过设置$primaryKey属性来自定义主键:
public $primaryKey = 'id';
2.4 时间戳设置
默认情况下,Eloquent模型类会自动管理时间戳列create_at和update_at(如果定义迁移时设置了这两列的话),如果要取消自动管理,可以设置$timestamps属性为false:
public $timestamps = false;
还有,如果你想要设置时间戳的格式,可以使用$dateFormat属性,该属性决定了日期时间以何种格式存入数据库,以及以何种格式显示:
//设置日期时间格式为Unix时间戳
protected $dateFormat = 'U';
3、查询数据
3.1 获取多个模型
我们可以使用Eloquent模型上的all方法获取所有模型实例
$posts = Post::all();
需要了解的是每一个Eloquent模型本身都是一个查询构建器,所有我们可以调用所有查询构建器上的方法,只不过第一个方法调用都要使用静态方法调用:
$posts = Post::where('id','<',3)->orderBy('id','desc')->take(1)->get();
dd($posts);
3.2 获取单个模型
可以使用查询构建器方法获取单个模型实例:
$post = Post::where('id',1)->first();
dd($post);
当然也可以通过Eloquent模型类提供的快捷方法find:
$post = Post::find(1);
3.3 聚合函数查询
如果要对查询结果进行计数、统计、最大值/最小值、平均数等聚合运算,可以使用查询构建器上的对应方法,我们我们查询文章总数:
$count = Post::where('id','>',0)->count();
echo $count;
输出结果为3,又或者我们想要获取文章最大阅读数:
$views = Post::where('id','>',0)->max('views');
echo $views;
调用Eloquent模型类的save方法即可创建模型并插入数据到数据库:
1.2 使用create方法插入数据
除此之外还可以使用create方法插入数据,由于该方法中用到了批量赋值(Mass Assignment),所以我们需要在模型类中设置$fillable属性或者$guarded属性,以表明哪些属性可以通过该方法设置,哪些不可以。
开始之前,我们先解释下什么是批量赋值,以及为什么要使用批量赋值。
批量赋值的英文名称是Mass Assignment,所谓的批量赋值是指当我们将一个数组发送到模型类用于创建新的模型实例的时候(通常是表单请求数据),我们可以简单通过如下方式实现:
$post = Post::create(Input::all());
而不是像使用save方法那样一个一个的设置属性值,如果模型属性很多的话,使用save简直是噩梦有木有。
但事物总是相对的,使用批量赋值是很方便,但同时也带来了安全隐患,很多时候模型类的某些属性值不是我们所期望通过批量赋值修改的,比如用户模型有个user_type属性,如果用户通过请求数据将其类型修改为管理员类型,这显然是不允许的,正是基于这一考虑,Eloquent模型类为我们提供了$fillable属性和$guarded属性,我们可以将其分别看作“白名单”和“黑名单”,定义在$fillable中的属性可以通过批量赋值进行赋值,而定义在$guarded中的属性在批量赋值时会被过滤掉。
那么如果我们确实想要修改定义在$guarded中的属性怎么办?答案是使用save方法。
此外需要注意的是$fillable和$guarded方法同时只能定义一个,原因嘛很简单,非黑即白,定义了一个另外一个也就确定了。
可见批量赋值不仅为我们创建模型提供了便利,还避免了安全隐患,提高了系统的安全性。
下面我们来演示一下批量赋值的使用。首先在Post模型中定义$guarded属性如下:
protected $guarded = ['views','user_id','updated_at','created_at'];
然后在控制器中实现创建模型实例的逻辑:
$input = [
'title'=>'test 5',
'content'=>'test content',
'cat_id'=>1,
'views'=>100,
'user_id'=>2
];
$post = Post::create($input);
dd($post);
2、更新模型
2.1 使用save方法更新模型
save方法还可以用于更新模型,要更新模型数据,先要获取该模型实例,然后修改模型属性,再调用save方法保存即可:
$post = Post::find(1);
$post->title = 'test 1 title';
if($post->save()){
echo '更新文章成功!';
}else{
echo '更新文章失败!';
}
2.2 使用update方法更新数据
和create相对应的,Eloquent模型类还支持使用update方法更新数据,同样要用到批量赋值:
$input = [
'title'=>'test 6 title',
'content'=>'test content 6',
'cat_id'=>1,
'views'=>200,
'user_id'=>1
];
$post = Post::find(6);
if($post->update($input)){
echo '更新文章成功!';
dd($post);
}else{
echo '更新文章失败!';
}
1、删除模型
1.1 使用delete删除模型
删除模型很简单,先获取要删除的模型实例,然后调用delete方法即可:
$post = Post::find(5);
if($post->delete()){
echo '删除文章成功!';
}else{
echo '删除文章失败!';
}
该方法返回true或false。
1.2 使用destroy删除模型
当然如果已知要删除的模型id的话,可以用更简单的方法destroy直接删除:
$deleted = Post::destroy(5);
你也可以一次传入多个模型id删除多个模型:
$deleted = Post::destroy([1,2,3,4,5]);
调用destroy方法返回被删除的记录数。
1.3 使用查询构建器删除模型
既然前面提到Eloquent模型本身就是查询构建器,也可以使用查询构建器风格删除模型,比如我们要删除所有浏览数为0的文章,可以使用如下方式:
$deleted = ModelsPost::where('views', 0)->delete();
返回结果为被删除的文章数。
1、查询作用域
Eloquent还支持将一些常用的查询封装到模型方法中,方便调用,我们将其称之为“查询作用域”,实现查询作用域很简单,只需要在模型方法前加上scope前缀即可,比如我们经常需要获取浏览数最高的文章,就可以使用该机制实现——在Post中定义一个scopePopular方法:
public function scopePopular($query)
{
return $query->where('views','>=',100);
}
对应的,我们在控制器中定义测试代码如下:
$posts = Post::popular()->orderBy('views','desc')->get();
foreach ($posts as $post) {
echo '<'.$post->title.'> '.$post->views.'views<br>';
}
2、模型事件
Eloquent也支持模型事件——当模型被创建、更新或删除的时候触发相应事件,Eloquent目前支持八种事件类型:creating、created、updating、updated、saving、saved、deleting、deleted。
deleting和deleted很好理解,在删除模型时触发,deleting在删除操作前执行,deleted在删除完成后执行。
当创建模型时,依次执行saving、creating、created和saved,同理在更新模型时依次执行saving、updating、updated和saved。无论是使用批量赋值(create/update)还是直接调用save方法,都会触发对应事件(前提是注册了相应的模型事件)。
你可以在任何你喜欢的地方注册模型事件,这里我们选择在服务提供者AppServiceProvider的boot方法中注册:
Post::saving(function($post){
echo 'saving event is fired<br>';
});
Post::creating(function($post){
echo 'creating event is fired<br>';
});
Post::created(function($post){
echo 'created event is fired<br>';
});
Post::saved(function($post){
echo 'saved event is fired<br>';
});