可修改的自带属性
protected $connection; //数据库连接 protected $table; //表名 protected $primaryKey = 'id'; //主键名,默认为 id protected $keyType = 'int'; //主键类别,默认为int型 public $incrementing = true; //主键是否自增 protected $attributes = [ 'goods_ids' => '[]', //可以配合 $casts, 取出数据时自动转化为 JSON 'category_ids' => '[]', 'display_order' => 0, ]; //设置默认值,不能写成 'goods_ids' => []. 而必须给[]加上引号; protected $fillable = ['field1','field2']; //可以被批量赋值的字段(*为所有字段)。添加字段后可直接在调静态方法create([key=>attribute])中赋值(就是说create静态方法只能给fillable中的字段赋值),其它批量赋值的方法还包括(firstOrCreate(),firstOrNew()) protected $guarded = ['*']; //用法同$fillable属性,但效果相反,除$guarded内的字段都可赋值. 注意:使用的时候应该只选择 $fillable 或 $guarded 中的其中一个,将另一个设置为[]空数组. protected $casts = ['属性名'=>'类别']; //访问时会自动转换成相应的类型,存储在数据库时还是是原来的类别,类型包括 integer,real(?),float,double,string,boolean,object,array(常用于数据库存的json字符串字段),collection,date,datetime,timesteap protected $with = []; protected $withCount = []; protected $perPage = 15; //分页时每页的条目数 public $exists = false; public $appends = ['字段名']; //自定义添加的字段,toArray()会自动获取 public $wasRecentlyCreated = false; protected $dates = ['is_del']; //要格式化为日期的字段 protected static $resolver; protected $hidden = ['属性名']; // protected $dispatchesEvents = [ 'saved' => UserSaved::class, 'deleted' => UserDeleted::class, ]; //事件映射类 protected static $dispatcher; protected static $booted = []; protected static $globalScopes = []; public $timestamps = true; //是否开启 自动处理表中下面两个字段,注意为publick const DELETED_AT = 'delete_at'; //软删除字段 const CREATED_AT = 'created_at'; //创建时间字段 const UPDATED_AT = 'updated_at'; //更新时间字段 protected $dateFormat = 'U'; //模型的日期字段保存格式。同date函数第一个参数,U为unix时间戳
常用静态方法说明
分块 chunk(num,closure)
将结果分num分为一块,用closure回调处理
Flight::chunk(200, function ($flights) {});
使用游标 cursor()
, 返回结果为游标
foreach (Flight::where('foo', 'bar')->cursor() as $flight) {}
快速查找
find(主键id)
简单取回记录 ,参数可主单个id,或用主键数组
findOrFail()
/ firstOrFail()
用法同上,没有结果时会抛出一个异常,firstOrFail为实例方法
批量更新 update([key=>attribute])
参数数组为字段的属性.此时不会触发saved,updated事件
查找插入 firstOrCreate([key=>attribute],[key=>attribute])
/firstOrNew()
先查找参数的中的属性,没有就插入记录,参数2(可选)是在插入时合并的值(就是说在插入时,如果有参数2,将会合并参数1)
firstOrCreate()
返回插入数据后的实例,firstOrNew()
还未插入数据库,需后面手动插入
更新插入 updateOrCreate([attribute1],[attribute2])
,updateOrNew()
用法同上,但参2必填且为修改的字段值
批量删除 destroy(主键id)
, 参数为单个id或id数组
常用公共实例方法
单条记录插入更新 save([option=>'option'])
有记录时为更新,没有记录时为插入.参数可选.注意: 并非记录的属性,具体需google.
delete()
删除单条记录
软删除
laravel自带的软删除使用:
1.创建的表包含一个timestamp自字段,默认值为Null,在eloquent模型中引入trait SoftDeletes
,并将字段名加入到模型中 protect $data = ['字段']
属性中.
2.可以使用模型实例方法trashed()
方法来查看是否被软删除.
3.软删除后记录会从一般查询中排除 ,可以调用模型静态方法withTrashed()
来强制查询.onlyTrashed()
方法只查询软删除中的数据,模型实例方法restore()
可恢复数据为正常状态,模型实例方法foreDelete()
可强制删除数据.
自定义软删除
参考 https://blog.dreamlikes.cn/2017/06/07/laravel5-extend-softdeletes/, https://github.com/broly8/SoftDeletesEx
事件
自带Eloquent模型事件方法如下:
retrieved
, , creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored
.
最简单的模型事件注册:
在app/Providers/EventService.php
中的boot()中注册,
/** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); AdType::creating(function($adType){ //adType为模型 //todo 业务逻辑 dd($adType); }); // }
关联模型
外键关联默认约定示例:有posts文章表,comments评论表,两表的主键名都为id,comments表与posts表关联的字段为post_id , 即 Model名_id
。
正向关联示例:
一对一hasOne()
,一对多hasMany()
class Post extends Base { public function comments() { return $this->hasMany(Comment::class,[comments表中与post表相关联的字段],[post表中的关联字段]);// 参数2,参数3选 } //调用 $coments = Post::find(1)->commets();//返回文章1的所有评论
反向关联:
都是 beLongsTo()
class Comment extends Base { public function post() { return $this->BelongTo(Comment::class,$this表中与post表相关联的字段],[post表中的关联字段]);// 参数2,参数3选 } //调用 $coments = Comment::find(1)->posts;//返回文章1的所有评论
多对多 需要3张表
简单用法示例:ads广告表,channel_labels渠道标签表,ad_channel_label广告渠道标签表(单数),
都调用belongsToMany('另一模型名', '关联表名', '$this在关联表里的键名', '另一模型在关联表里的键名')
方法,默认获取关联表的数据时只有关联的字段,如果想获取其它字段,则必须在定义关联时明确指出再调用withPivot(['field1','field2', ....])
。
如果您想让中间表自动维护 created_at
和 updated_at
时间戳,那么在定义关联时加上 withTimestamps
方法即可。
class ChannelLabel extends Base { protected $table = 'channel_labels'; public function ads() { return $this->belongsToMany(Ad::class,'ad_channel_label');//查询的时候关联表数据只有 ad_id和channel_label_id return $this->belongsToMany(Ad::class,'ad_channel_label')->withPivot('id');//查询的时候关联表数据还会有id return $this->belongsToMany(Ad::class,'ad_channel_label')->withTimestamps();//自动维护时间 } } //调用 $ads = ChannelLabel::find(2)->ads;//获取广告id为2所关联的所有渠道标签 $relate_records=$ads->pivot //获取关联表的数据
过滤关联表中的数据
wherePivot(where条件)
,wherePivothIn(字段,[集合])
在集合里
定义关联表模型
创建一个model此时应继承Illuminate\Database\Eloquent\Relations\Pivot
,而不是直接继承Eloquent/Model,
$this->belongsToMany(Ad::class,'ad_channel_label')->using(关联表模型类名);
远程一对多
有上图的表模型,可使用hasManyThrough(目标表模型名,中间表模型名, '中间表的与$this表关联字段(外键)','目标表的与中间表关联的字段', '$this表本地字段(一般为id)', '中间表的自己的本身的字段(一般为id)')
获取,示例
class Country extends Model { /** * 获得某个国家下所有的用户文章。 */ public function posts() { return $this->hasManyThrough( 'App\Post', 'App\User', 'country_id', // 用户表外键... 'user_id', // 文章表外键... 'id', // 国家表本地键... 'id' // 用户表本地键... ); } }
一对多的多态关联
有如下表模型
有图片表(pictures)和视频表(videos),共用一个评论表(comments),评论表有评论的类别字段(comment_type),和评论的id字段(commentable_id),
在图片和视频模型中调用 morphMany('关联表的模型类名', '关联表的id与type共有的前缀名',['关联表关联的类别字段'], ['关联表关联的id字段'])
方法,参数3和参数4可选但传入后将无视参数2,类别字段的值为默认为模型类的类名。
在评论模型中调用morphTo(['$this表的id与type共有的前缀名'],['$this的关联类别字段'],['$this的关联的id字段'])
,
class Comment extends Model { /** * 获得拥有此评论的模型。 */ public function commentable() //注意方法名,如果有相同前缀,方法名与前缀名相同,那么下面调用morphTo()方法时可以不用传参数 { return $this->morphTo(); //前相同前缀并也前缀也是方法名 return $this->morphTo('前缀名'); //有前缀但方法名与前缀名不同,可以只传入前缀参数 return $this->morphTo('随意','关联的类别字段', '关联的id字段'); } /** * 获得拥有此评论的模型。模型类别包括视频和图片 */ public function commentvideo() { return $this->morphTo('App\Video','commentable', 'commentable_type', 'commentable_id'); } } class Post extends Model { /** * 获得此文章的所有评论。 */ public function comments() { return $this->morphMany('App\Comment', 'commentable');////当类别字段和id字段有相同的字段时并且各自的后缀分为_type和_id时,可只传参数2 } } class Video extends Model { /** * 获得此视频的所有评论。 */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } }
自定义多态关联的类型字段
在app/Providers/AppServiceProvider.php
中的boot()
方法中添加如下代码
use Illuminate\Database\Eloquent\Relations\Relation; Relation::morphMap([ 'posts' => 'App\Post', //键名名表中类别字段的值 'videos' => 'App\Video', ]);
或者使用一个独立的服务提供者注册,具体得google。
多对多的多态关联
表模型如下
基本和一对多差不多,只是多一张多对多的关联表。
在picture或videos表调用 morphToMany(目标模型类名,'多对多关系表的共同前缀名','多对多关系表名',['$this表主键在多对多关系表中的字段'],['目标表主键在多对多关系表中字段'], ['多对多关系表中主键'],['目标表的主键'])
,如果多对多关系表名就是共同前缀名的复数可不传参数3
class Picture extends Model { /** * 获得此图片的所有标签。 */ public function tags() { return $this->morphToMany('App\Tag', 'taggable');//此时多对多的表名为taggables,关联id字段为 taggable_id ,关联类别字段为taggable_type } }
反向关联 morphedByMany()
方法,简单点吧,用它自己的规则
class Tag extends Model { /** * 获得此标签下所有的图片。 */ public function pictures() { return $this->morphedByMany('App\Post', 'taggable'); } /** * 获得此标签下所有的视频。 */ public function videos() { return $this->morphedByMany('App\Video', 'taggable'); } }
基于存在/不存在 的关联查询 has/doesntHave('表名[.字段名]','比较符',num)
// 获得所有至少有一条评论的文章... $posts = App\Post::has('comments')->get(); // 获得所有有三条或三条以上评论的文章... $posts = Post::has('comments', '>=', 3)->get(); //不存在评论 $posts = Post::doesntHave('comments')->get();
同时带条件查询
// 获得所有至少有一条评论内容满足 foo% 条件的文章 $posts = Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->get(); $posts = Post::whereDoesntHave('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->get();
查询关联
class User extends Model { /** * 获得此用户所有的文章。 */ public function posts() { return $this->hasMany('App\Post'); } }
$user->post 返回的是post集合,不可以用查询构造器
$user->post() 返回是post模型,可用查询构造器
定义属性转换
访问器
同yii2的getter方法自定义属性
定义规则: get属性名Attribute()
,属性名用大驼峰法,访问时属性名全部小写
修改器
同yii2的setter方法,属性保存在$model->attributes[]中
定义规则: set属性名Attribute($value)
,
示例
public function setFirstNameAttribute($value) { $this->attributes['first_name'] = strtolower($value); }
预加载
默认情况下当作为属性访问 Eloquent 关联时,关联数据是「懒加载」的。在第一次访问该属性时,才会加载关联数据,但在列表的关联查询时是要一次性查询出来 ,此时可以使用
with('关联的方法名')
,可以使用数组加载多个关联查询,
class Book extends Model { /** * 获得此书的作者。 */ public function author() { return $this->belongsTo('App\Author'); } public funciton publisher() { return $this-belongsTo('App\Pulisher') ; } } $books = App\Book::with('author')->get(); //获取书的数据时同时获取作者的数据 $books = App\Book::with(['author', 'publisher'])->get(); //多个关联
预加载使用筛选条件
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();
延迟预加载
没延迟是直接将所有数据直接查出来,延迟是先查询了再关联查询,
此时使用load()
方法,参数同with()
方法
$books = App\Book::all(); //此时$books为集合 if ($someCondition) { $books->load('author', 'publisher'); } $books->load(['author' => function ($query) { $query->orderBy('published_date', 'asc'); // 添加筛选条件 }]);
关联模型的插入及更新
关联方法()->save(\$model)/saveMany([$model1, \$model2])/create([key=>val])/createMany([[key1=>val1],[key2=>val2]]) ,save()
方法接收model,create()
方法接收纯php数组,
此方法适用于主关联方(hasOne,hasMany),注意此时不是动态属性
$comment = new App\Comment(['message' => '一条新的评论。']); //创建一个新的评论模型实例 $post = App\Post::find(1); //获取id为1的文章 $post->comments()->save($comment); // 为文章1添加刚刚新的评论,注意此时使用的关联方法而非属性。 save()方法只能添加一条记录 $post->comments()->saveMany([ new App\Comment(['message' => '一条新的评论。']), new App\Comment(['message' => '另一条评论。']), ]); $comment = $post->comments()->create([ 'message' => '一条新的评论。', ]); //create/createMany()方法接受数组 $post->comments()->createMany([ ['message' => '一条新的评论。'], ['message' => '另一条新的评论。'], ]);
从关联模型
更新先调用associate()
方法
$account = App\Account::find(10); $user->account()->associate($account); $user->save();
删除dissociate()
方法
$user->account()->dissociate(); $user->save();