Laravel5.8
  1. 安装配置及核心内容
  2. 框架基础
  3. 进阶知识
  4. 数据库相关
    1. Laravel - 数据库相关 - 简介与配置
    2. Laravel - 数据库相关 - 原生 SQL 操作
    3. Laravel - 数据库相关 - 查询构造器
    4. Laravel - 数据库相关 - 分页
    5. Laravel - 数据库相关 - 数据迁移
    6. Laravel - 数据库相关 - 数据填充
    7. Laravel - 数据库相关 - redis
    8. Laravel - Eloquent 模型 - 入门
    9. Laravel - Eloquent 模型 - 查询作用域(全局,本地,动态)
    10. Laravel - Eloquent 模型 - 事件与监听方法
    11. Laravel - Eloquent 模型 - 关联关系
    12. Laravel - Eloquent 模型 - 关联查询
    13. Laravel - Eloquent 模型 - 访问器和修改器

Laravel - Eloquent 模型 - 关联关系

程序员日记      2019-09-09

Eloquent 模型支持多种不同类型的关联关系

一对一

一对多

多对多

远层一对一

远层一对多

一对一(多态)

一对多(多态)

多对多(多态)


普通关联

一对一

父表模型中定义关联

$this->hasOne(关联模型名称[,子表的外键ID,父表的主键ID(默认id)]);

子表模型中的相对关联

$this->belongsTo(关联模型名称[,子表外键ID,父表的主键ID(默认id)]);

示例

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model{
    /**
     * 获取关联到用户的手机
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model{
    /**
     * 获取关联到用户的手机
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}


一对多

父表模型中定义关联

$this->hasMany(关联模型名称[,子表的外键ID,父表的主键ID(默认id)]);

子表模型中定义关联

$this->belongsTo(关联模型名称[,子表外键ID,父表的主键ID(默认id)]);

示例

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model{
    /**
     * 获取博客文章的评论
     */
    public function comments()
    {
         return $this->hasMany('App\Comment');
    }
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model{
    /**
     * 获取评论对应的博客文章
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}


多对多

这种一般会有三张表,表1(记录自己的信息),表2(记录自己的信息),中间表(关系表)(用于记录表1,表2关系的关系表)。

常见的就是用户与权限的关系,一个用户拥有多个权限,一个权限可以被多个用户同时拥有。

用户(user),权限(role),用户权限关系表(role_user)。

定义多对多关联(表1,表2,中间表)

return $this->belongsToMany('表1模型名称'[, '关系表名称', '中间表对表1的外键', '中间表对表2的外键']);

定义相对的多对多关联(表1,表2,中间表)

return $this->belongsToMany('表2模型名称'[, '关系表名称', '中间表对表2的外键', '中间表对表1的外键']);

示例.关系的定义

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model{
    /**
     * 用户角色
     */
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model{
    /**
     * 角色用户
     */
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}


多对多中间表

在模型的使用中,我们可以通过pivot对象获取关系表(中间表)的参数

默认情况下,只有模型主键才能用在 pivot 对象上。

如果你的 pivot 表包含额外的属性,必须在定义关联关系时进行指定:

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

使 pivot 对象自动包含created_at 和 updated_at 时间戳,

return $this->belongsToMany('App\Role')->withTimestamps();

使用pivot属性调用关系表的属性。

$user = App\User::find(1);
foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

自定义 pivot 属性名

return $this->belongsToMany('App\Podcast')
            ->as('subscription')
            ->withTimestamps();

说明:

定义好之后,就可以使用自定义的属性名subscription来访问关系表数据了

自定义中间表模型

定义多对多关联时,指定模型

return $this->belongsToMany('App\User')
->using('App\UserRole')
->withPivot([
                'created_by',
                'updated_by'
            ]);

说明

1.using指定中间表模型。

2.withPivot用户获取中间表的参数。

App\UserRole应该继承pivot类

<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class UserRole extends Pivot
{
    //
}


远层一对一

示例

每一个供应商(supplier)都有一个用户(user),每个用户都与一个历史记录(history)关联

示例表结构

//用户表
users
    id - int
    supplier_id - int
//供应商表
suppliers
    id - int
//用户历史记录
history
    id - int
    user_id - int

说明

尽管 history 数据表不包含 supplier_id 列,但是通过user表,suppliers表还是可以访问到history数据。

示例关联定义

$this->hasOneThrough(
    'App\History',//目标表
    'App\User',//中间表
    'supplier_id', // 中间表对本表的外键
    'user_id', // 目标表对中间表的外键
    'id', // 本表的主键ID
    'id' // 中间表的主键ID
);


远层一对多

示例

Country 模型通过中间的 User 模型可能拥有多个 Post 模型

示例表结构

countries
    id - integer
    name - string
users
    id - integer
    country_id - integer
    name - string
posts
    id - integer
    user_id - integer
    title - string

示例关联定义

return $this->hasManyThrough(
    'App\Post',//目标表
    'App\User',//中间表
    'country_id', // 中间表对本表使用的外键
    'user_id', // 目标表对中间表的外键
    'id', // 本表的主键ID
    'id'  // 中间表的主键ID
);

多态关联

一对一(多态)

示例

文章(posts)与用户(users)共用一张图片表,他们与该表都是一对一的关系。

示例表结构

posts
    id - integer
    name - string
users
    id - integer
    name - string
images
    id - integer
    url - string
    imageable_id - integer //存储文章或用户的ID值
    imageable_type - string //存储Post或User

说明

关联名称imageable,关联ID imageable_id,关联类型,imageable_type

示例关系定义

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
    public function imageable()
    {
        return $this->morphTo();
    }
}
class Post extends Model
{
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable','type','id','id');
    }
}
class User extends Model
{
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable','type','id',本表主键);
    }
}

说明

$this->morphOne(要关联的表模型,关联名称,关联类型,关联ID,本表ID);

1.要关联的表模型:这个就不需要多解释了

2.关联关系名:数据表中的id与type的前缀,比如上诉例子,imageable_id,imageable_type,他们的前缀是id,

3.关联类型:会与关联关系名自动组成表中的字段名:关联关系名_关联类型,上诉例子就是imageable_type;

4.关联ID:会与关联关系名自动组成表中的字段名:关联关系名_关联ID,上诉例子就是imageable_id;

5.本表主键:这里就不多解释了


一对多(多态)

示例

文章(posts)与视频(videos)共用一张图片表,他们与该表都是一对多的关系。

示例表结构

posts
id - integer
title - string
    body - text
videos
  id - integer
  title - string
  url - string
comments
    id - integer
    body - text
    commentable_id - integer //存储文章或视频的ID值
    commentable_type - string //存储Post或者Video

说明

关联名称commentable,关联ID commentable_id,关联类型,commentable_type

示例关系定义

<?php
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','type','id','id');
    }
}
class Video extends Model
{
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable','type','id','id');
    }
}

说明

$this->morphMany(要关联的表模型,关联名称,关联类型,关联ID,本表ID);

1.要关联的表模型:这个就不需要多解释了

2.关联关系名:数据表中的id与type的前缀,比如上诉例子,imageable_id,imageable_type,他们的前缀是id,

3.关联类型:会与关联关系名自动组成表中的字段名:关联关系名_关联类型,上诉例子就是imageable_type;

4.关联ID:会与关联关系名自动组成表中的字段名:关联关系名_关联ID,上诉例子就是imageable_id;

5.本表主键:这里就不多解释了


多对多(多态)

示例

文章(posts)与视频(videos)共用一张标签表(tags),他们与该表都是多对多的关系。

一篇文章或视频可以拥有多个标签,一个标签可以属于多个文章或视频。

示例表结构

//文章表
posts
    id - integer
    name - string
//视频表
videos
    id - integer
    name - string
//标签表
tags
    id - integer
    name - string
//关系表
taggables
    tag_id - integer //存储标签ID
    taggable_id - integer //存储文章或视频的ID值
    taggable_type - string //存储Post或Video.

说明

关联名称taggable,关联ID commentable_id,关联类型,commentable_type

示例关系定义

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    /**
     * 获取指定文章所有标签
     */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class video extends Model
{
    /**
     * 获取指定视频所有标签
     */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}

定义相对的关系

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
    /**
     * 获取所有分配该标签的文章
     */
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'taggable');
    }
    /**
     * 获取分配该标签的所有视频
     */
    public function videos()
    {
        return $this->morphedByMany('App\Video', 'taggable');
    }
}