【再读lara】Eloquent: Relationship 关联

一对一

用户和文章

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  public function post()
  {
    return $this->hasOne('App\Phone');
  }
}

在当前场景下,Eloquent 会假设 Phone 模型有一个外间 user_id
$phone = User::find(1)->post;


反向关联
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
  public function user()
  {
    return $this->belongsTo('App\User');
  }
}

空对象模型, user 关联如果没有找到文章的作者,就会返回一个空的 App\User 模型。
可以理解返回一个默认值,还没有具体实践过
class Post extends Model
{

  // 数组形式
  public function user()
  {
    return $this->belongsTo('App\User')->withDefault([
      'name' => '游客'
    ]);
  }

    // 闭包形式
    public function user() 
    {
      return $this->belongsTo('App\User')->withDefault(function($user) {
        $user->name = '游客';
      });
    }
}

一对多

文章和评论

文章
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
  public function comments()
  {
    return $this->hasMany('App\Comment');
  }
}


评论
namespace App

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
  public function post()
  {
    return $this->belongsTo('App\Post');
  }
}

多对多

用户和角色
一个用户可以拥有多个角色,一个角色下面可以有多个用户
users, roles, role_user 三张表
role_user 表是以相关联的两个模型数据表、依照字母顺序排列命名的,并且包含 user_id 和 role_id 字段。

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  public function roles()
  {
    return $this->belongsToMany('App\Role');
  }
}


namespace App;

use Illuminate\Databese\Eloquent\Model

class Role extends Model
{
  public function users()
  {
    return $this->belongsToMany('App\User');
  }
}


自定义中间表的场景
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
  public function users()
  {
    return $this->belongsToMany('App\User')->using('App\RoleUser');
  }
}

namespace App;
use Illuminate\Database\Relationships\Pivot;
class RoleUser extends Pivot
{
   
}

远层一对多

一个 Country 模型可以通过中间的 User 模型获得多个 Post 模型

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string


hasManyThrough 方法的第一个参数是我们最终希望访问的模型名称,而第二个参数是中间模型的名称。
namespace App;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
  // 默认
  public function posts()
  {
    return $this->hasManyThrough('App\Post', 'App\User');
  }

  // 自定义
  第三个参数表示中间模型的外键名,第四个参数表示最终模型的外键名。
  第五个参数表示本地键名,而第六个参数表示中间模型的本地键名:
  public function posts()
  {
    return $this->hasManyThrough(
      'App\Post', 
      'App\User',
      'country_id',    // 用户表外键
      'user_id',         // 文章表外键
      'id',                  // 国家表
      'id'                   //
    );
  }
}

多态关联

用户可以「评论」文章和视频

commentable_id 用来保存文章或者视频的 ID 值
commentable_type 用来保存所属模型的类名 (post, video)
posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string


namespace App;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
  public function commentable()
  {
    return $this->morphTo();
  }
}

class Post extends Model
{
  public function comments()
  {
    return $this->morphMany('App\Comment', 'commentable');
  }
}

class Video extends Model
{
  public function comments()
  {
    return $this->morphMany('App\Comment', 'commentable');
  }
}


$commentable = App\Comment::find(1)->commtable();
返回 commentable 的 Post 或 Video 实例

多对多多态关联

Post 和 Video 两个模型都有一个 tags 方法,方法内部都调用了 Eloquent 类自身的 morphToMany 方法

posts
    id - integer
    name - string

videos
    id - integer
    name - string

tags
    id - integer
    name - string

taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string


namespace App;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
  public function tags()
  {
    return $this->morphToMany('App\Tag', 'taggable');
  }
}


反向关联
class Tag extends Model
{
  public function posts()
  {
    return $this->morphedByMany('App\Post', 'taggable');
  }

  public function videos() 
  {
    return $this->morphedByMany('App\Video', 'taggable');
  }
}

$tags = Post::find(1)->tags;

或者
$tag = Tag::find(1);
$videos = $tag->videos;

Dynamic properties allow you to access relationship methods as if they were properties defined on the model
模型中定义的关联,叫做 dynamic property(动态属性)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容