1. 模型的定义
一. 默认设置
- 框架可以使用 Eloquent ORM 进行数据库交互,也就是关系对象模型;
在数据库入门阶段,我们已经创建了一个 User.php 模型,如下:
php artisan make:model Http/Models/User //默认在 app 目录
而调用的时候,我们也知道表名要
遵循它默认规则
,修改为复数,或 特定;class User extends Model { protected $table = 'user'; }
系统假定你的主键为 id,如果你要修改默认主键,可以特定;
class User extends Model { protected $primaryKey = 'xid'; //主键 }
- 系统假定你的主键 id 为自增性,意味着是主键会自动转换 int 类型;
如果你希望不是非自增,非数值类型主键,可以设置 $incrementing 取消;
public $incrementing = false; //非数字整型主键
如果你主键不是一个整数,那么需要$keyType 设置为 string;
protected $keyType = 'string'
- 系统默认情况下会接管
created_at
和updated_at
两个时间戳列; 如果不想让系统干涉这两个列,可以设置 false 取消;
public $timestamps = false; //取消写入时间戳
如果你想自定义时间戳的格式,可以设置;
protected $dateFormat = 'U';
可以更改创建时间 created_at 和更新时间 updated_at 字段名;
const CREATED_AT = 'create_time'; const UPDATED_AT = 'update_time';
默认读取
database.php
配置的数据库连接,也可以在模型端局部更改
protected $connection = 'mysql';
二. 模型定义
- 之前在查询构造器部分,把常用的数据库操作基本讲完,模型大体相同;
比如,我们要查询所有数据,直接使用模型::all()即可;
//查询所有记录 $users = User::get(); //或 all() return [$users];
也可以像查询构造器一样,添加各种各样的条件,写法一样;
//查询性别为男,价格大于 90,限制显示 2 条 $users = User::where([ ['gender', '=', '男'], ['price', '>', 95] ])->limit(2)->get();
虽然安装了插件,但模型还是没有代码提示,可以通过安装插件解决;
composer require barryvdh/laravel-ide-helper php artisan ide-helper:generate // – 为 Facades 生成注释 php artisan ide-helper:models //– 为数据模型生成注释 php artisan ide-helper:meta //– 生成 PhpStorm Meta file
- 其它查询方法基本和查询构造器一样,如果有不一样,参考错误提示;
这里列出官网给出示例的方法,对照实验(结合详细文档,重复较多);
关于更多 Eloquent ORM 操作, 看手册 ( https://learnku.com/docs/laravel/8.x/eloquent/9406 )
(1) .find(1) //通过主键查找 (2) .first() //查找第一个 (3) .firstWhere() //找到查询中的首个 (4) .find([1,2,3]) //通过数组查找 (5) .firstOr() //查找首个返回,支持闭包 (6) .firstOrFail() //找不到时返回异常 (7) .count()、max()等集合 //集合操作 //PS:还有很多在查询构造器中的方法,比如排序、分组子查询等等都可以使用(并未一一验证)。
2. 模型的增删改
一. 增操作
新增方法如下,注意:默认模型接管
created_at
和updated_at
;$users = new User(); $users->username = '辉夜'; $users->password = '123'; $users->email = 'huiye@163.com'; $users->details = '123'; $users->save();
- 使用
create()
方法实现新增,但需要在模型端设置批量赋值的许可;
User::create([
'username' => '辉夜',
'password' => '123',
'email' => 'huiye@163.com',
'details' => '123',
]);
//许可批量赋值,默认不可
protected $fillable = [
'username',
'password',
'email',
'details'
];
//不许可的批量赋值,不可和$fillable 同时使用
//protected $guarded = ['uid'];
//如果取消批量赋值限制,直接如下
protected $guarded = [];
//PS:必须在模型中定义批量赋值的可填充字段,否则无法生效;防止用户不小心设置新值;
二. 改(更新)操作
更新,只要是查找到一条数据的情况下使用 save()就是更新
$users = User::find(321); //先查出,返回对象 $users->username = '夜辉'; $users->save();
使用
update()
方法实现批量更新;User::where('username', '夜辉') ->update([ 'username' => '辉夜' ]);
三. 删操作
使用
delete()
方法,可以删除数据;$users = User::find(332); $users->delete(); //批量删除 $users = User::where('username', '夜辉'); //名字带 夜辉都删除掉 $users->delete();
如果你是通过主键 id 删除,那使用
destroy(id)
方法,免去查询操作;//通过主键删除 User::destroy(328);
3. 批量赋值和软删除
一. 批量赋值
- 上一节增删改中,新增中我们发现需要进行批量赋值的许可;
- 一般情况下,是为了防止提交过来的字段在部分场景中不需要或不能;
所以,我们需要通过黑白名单机制进行过滤掉必要的字段;
//通过提交过来的数据一次性新增 User::create(\Request::all());
二. 软删除
- 什么叫软删除?它相对于真实的删除,而并非真正的删除,只是隐藏了;
- 首先,需要在数据库创建一个字段 deleted_at(默认),用于判断是否被软删除;
- 默认设置这个字段为空(null),如果写入数据,成为非空状态,则说明被删除;
开启软删除的功能,需要在模型端设置一下:
//开启软删除功能 use SoftDeletes;
当开启了软删除功能,之前的删除操作,都会变成更新操作,给 deleted_at 赋值;
//删除一 $users = User::find(82); $users->delete(); //删除二 User::destroy(81);
而当我们开启了软删除的功能后,此时通过正常的数据获取列表,会自动隐藏
//软删除的数据不可见 $users = User::get(); return [$users]; //单独获取被软删除的数据不行 $users = User::find(82); return [$users];
3. 模型的作用域
一. 本地作用域(scope)
- 很多情况下,我们在数据查找时有一部分条件会被重复且大量使用;
- 而这个条件,可能只是在这个模型对应的数据表使用,别的表并不使用;
- 那么这种情况,可以使用本地作用域的方式,将常用的 SQL 封装起来;
- 参数用法格式:
scope
+ 自定义方法名 比如:用户模块中,我们大量查询需要查询性别为男,且其它条件的 SQL;
$users = User::where('gender', '男') ->where('price', '>', 90) ->get(); //PS:我们可以将性别为男这个片段,封装成一个单独的方法,然后统一在这个模型下调用;
//AppHttpModels;
//本地作用域,搜索自动添加为“男”的条件
//语法:scope 开头,后面名称尽可能包含语义
public function scopeGenderMale($query)
{
return $query->where('gender', '男');
}
//当然,如果赶紧单词太长,直接 gm()也行
$users = User::genderMale()
->where('price', '>', 90)
->get();
6. **上面的方法比较死板,适合简单粗暴**,如果想要灵活多变,**支持传递参数**;
//参数可以是 1 个或多个
$users = User::gender('女', -3)
->where('price', '>', 90)
->get();
//参数 2 和 3,接受控制器传递过来的 1,2
public function scopeGender($query, $value, $value2)
{
return $query->where('gender', $value)->where('status', $value2);
}
### 二. 全局作用域
1. 全局作用域,顾名思义就是在任意地方都可以有效的封装条件;
2. 比如有个需求,不管在哪里操作,总是显示 status 为 1 的用户;
3. 首先在 app 目录下**创建一个用于全局作用域的目录**:`Scopes` ;
4. 创建一个用于设置 status 为 1 的全局作用域的类,它需要实现 `scope 接口`
namespace AppScopes;
//这里引用代码自动生成
use IlluminateDatabaseEloquentBuilder;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentScope;
class StatusScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
// TODO: Implement apply() method.
return $builder->where('status', 1);
}
}
5. 此时,还不能实现全局,因为**需要在模型设置个开关**,让其富有灵活性;
//启用全局作用域
protected static function booted()
{
parent::booted(); // TODO: Change the autogenerated stub
static::addGlobalScope(new StatusScope());
}
//PS:而在控制器端,并不需要做任何设置,即可自动添加 status=1 的条件;
6. 当然,如果这个全局只是针对某个模块,并不需要创建一个全局类,直接闭包即可;
static::addGlobalScope('status', function (Builder $builder) {
return $builder->where('status', 1);
});
//PS:注意 Builder 引入的文件和全局类引入的文件一致,如果引入别的同名类会错;
7. 如果某个查询,并**不需要这个全局条件**,可以**单独移出掉**;
//取消名称为 status 的全局
$users = User::withoutGlobalScope('status')->get();
//取消全局类的条件
$users = User::withoutGlobalScope(StatusScope::class)->get();
//PS:还有 withoutGlobalScopes([])方法,传递参数取消多个全局;
---
## 4. 模型的访问和修改器
### 一. 访问器
1. 访问器:就是在**获取数据列表时,拦截属性并对属性进行修改的过程**;
2. 用法参数格式: `get`+ **字段名** + `Attribute`
3. 比如,我们在输出性别时,在性别左右加上括号,或给邮件转换为大写;
//访问器,前固定 get,后固定 Attribute,Gender 是字段名
//参数$value 是源字段值,可修改返回
public function getGenderAttribute($value)
{
return '【'.$value.'】';
}
//PS:如果字段名是两个单词中间是下划线:user_name,那么方法名:getUserNameAttribute()
4. 我们也可以创建一个虚拟字段,**用已有的数据字段进行整合**,不过要进行数据追加;
> 单条数据加上虚拟字段
>
**model层**
class User extends Model
{
$protected $table = 'user';
//创建一个虚拟字段
public function getInfoAttribute()
{
return $this->username.'-'.$this->gender;
}
}
**controller层**
$info = User::find(19)->info; //->info
dump($info);//打印 名字-性别
> 列表数据加上info虚拟字段
>
**注意:**一定要把虚拟字段加到`$appends`
**model层**
class User extends Model
{
$protected $table = 'user';
//将虚拟字段追加到数据对象列表里去
protected $appends = ['info'];
//创建一个虚拟字段
public function getInfoAttribute()
{
return $this->username.'-'.$this->gender;
}
}
**controller层**
$list = User::all()->toArray();

**注意2** :如果 gender **之前已经有访问器修改过**,上面的方法会**得到修改过的结果**;
5. 如果要使用**源字段进行创建虚拟字段**,需要使用下面这种:`$this->attributes[xxxx]`
class User extends Model
{
$protected $table = 'user';
//将虚拟字段追加到数据对象列表里去
protected $appends = ['info'];
//创建一个虚拟字段
public function getInfoAttribute()
{
return $this->attributes['username'].'-'.$this->attributes['gender'];
}
}

### 二. 修改器
1. 修改器,相对于访问器,**是在写入的时候拦截,进行修改再写入**;
2. 用法格式: `set` + **字段名** + `Attribute`
//修改器,写入数据时,将邮箱转换为大写
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtoupper($value);
}
3. 可以添加默认的日期列,默认 created_at 和 updated_at;
//设置可以自动写入日期的列
protected $dates = [
'details' //详情字段-转换日期格式
];
4. 可以设置字段输出的类型,比如设置一个布尔型,输出时就是 true 和 false;
//设置字段类型
protected $casts = [
'details' => 'boolean' //详情字段转换布尔类型
];
5. 注意的是。模型用`create()`方法写入走修改器, 用`insert()`方法不走修改器。
评论 (0)