Eloquent模型部分使用说明

可修改的自带属性

    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_atupdated_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(关联表模型类名);
远程一对多
QQ截图20171207171128

有上图的表模型,可使用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();

发表回复

您的电子邮箱地址不会被公开。