这里我们users表对应的模型类名是users,大家特意注意下和user取名的不同
1.一对一关系
1>表A和表B的记录一一对应,比如一个用户对应一个社交账号
数据表的设计如下:

2>定义模型Users,并在其中定义与UserAccounts的一对一对应关系:
public function account() {
return $this->hasOne('App\Http\Models\UserAccounts');
}
3>最后在控制器中编写测试代码如下:
$account = Users::find(1)->account; dd($account);
浏览器中会输出相对应的UserAccounts模型实例。

注意:上面的$this->hasOne()方法的完整格式是
$this->hasOne('App\Http\Models\UserAccount',$foreign_key,$local_key);
第一个参数是关联模型的类名称,
第二个参数,Eloquent 会假设对应关联的外键名称是基于模型名称的,会取用自身模型的「蛇形命名」后的名称,并在后方加上 _id,所以定义模型时候要注意,模型的名称加上'_id'的组合作为外键,我们这里外键=>'users'+'_id',也就是$foreign_key = 'users_id'
第三个参数,Eloquent 的默认外键在上层模型的 id 字段会有个对应值。换句话说,Eloquent 会寻找用户的 id 字段与 Phone 模型的 user_id 字段的值相同的纪录。如果你想让关联使用 id 以外的值,则可以传递第三个参数至 hasOne 方法来指定你自定义的键.
4>我们也可以在UserAccount模型中定义与User的一对一关系:
public function users() {
return $this->belongsTo('App\Http\Models\Users');
}
相应的测试代码为:
$user = UserAccounts::find(1)->users; dd($user);
上述代码会输出相应的Users模型实例。

分析:
Eloquent将调用belongsTo的关联方法名users作为关联关系$relation的值,并将$relation.'_id'作为默认外键名对应users表的id,如果表中没有相应列,又没有在定义关联关系的时候指定具体的外键,就会报错。
如果user_accounts中关联users的外键是$foreign_key,该外键对应users表中的列是$local_key,那么调用belongsTo方法:
$this->belongsTo('App\Http\Models\User',$foreign_key,$local_key);
此外,belongsTo还接收一个额外参数$relation,用于指定关联关系名称,其默认值为调用belongsTo的方法名,这里是user。
2.一对多关系

2>我们在用户模型Users中定义与文章模型Post的一对多关系如下:
public function posts() {
return $this->hasMany('App\Http\Models\Post');
}
对应的测试代码:
$posts = User::find(1)->posts; dd($posts);
这样就能获取id为1的用户所有发表的文章。

由于关联模型实例本身是一个查询构建器,我们可以添加查询条件到该实例:
$posts = User::find(1)->posts()->where('views','>',100)->get();
dd($posts);
需要注意的是这里我们调用的是posts方法,而不是动态属性posts。
3>同样,我们可以在文章模型Post中定义文章所属用户模型User的对应关系:
public function author() {
return $this->belongsTo('App\Http\Models\User','user_id','id');
}
我们可以使用如下方式获取指定文章对应的用户模型实例:
$author = Post::find(1)->author; dd($author);
结果如下:

注意我们在belongsTo方法中传入了额外参数,意为posts表中的user_id对应users表中的id。如果我们定义的方法名为user,则不需传入这些参数:
public function users() { return $this->belongsTo('App\Http\Models\Users'); }
我们在调用belongsTo方法时如果没有传入第四个参数$relation,则默认使用当前调用belongsTo的方法名为关联关系名称并赋值给$relation
3.多对多关系
1>表A的某条记录通过中间表C与表B的多条记录关联,反之亦然。比如一个用户有多种角色,反之一个角色对应多个用户。
数据表设计如下

提示:在定义多对多关联的时候如果没有指定中间表,Eloquent 会合并两个关联模型的名称并依照字母顺序命名,所有中间表的名字要根据两个模型的名称来写,比如模型1 users,模型2 role 那么表名就是role_users,Eloquent默认的中间表使用这种规则拼接出来。
2>我们在模型Users中定义多对多关联如下:
public function roles() {
return $this->belongsToMany('App\Http\Models\Role');
}
注意:我们这里模型的名称是users和role那么关联表中对应的字段就是users_id和role_id,我们的两个表对应的的模型类名是users 和role ,那么自动拼成的中间表名就是 role_users ,并且该表对应的字段就是role_id和users_id,如果你设计表的时候没有注意到这点,那么需要把中间表名作为第二个参数传入,中间表字段$user_id和$role_id作为第三个和第四个参数传入(这两个顺序不能乱),如果关联方法名不是roles还可以将对应的关联方法名作为第五个参数传入该方法。
3>接下来我们在控制器中编写测试代码:
$user = User::find(1);
$roles = $user->roles; echo 'User#'.$user->name.'所拥有的角色:<br>';
foreach($roles as $role) {
echo $role->name.'<br>';
}
对应输出为:
User#所拥有的角色:
role1
role2
role3
4>相对的我们也可以在模型Role中定义获取对应User模型的方法:
public function users() {
return $this->belongsToMany('App\Http\Models\Users');
}
测试代码如下:
$role = Role::find(4);
$users = $role->users; echo 'Role#'.$role->name.'下面的用户:<br>';
foreach ($users as $user) {
echo $user->mobile.'<br>';
}
对应输出为:
Role#role1下面的用户:
18652005200
18612341234
5>此外我们还可以通过动态属性pivot获取中间表字段:
$roles = Users::find(1)->roles;
foreach ($roles as $role) {
echo $role->pivot->role_id.'<br>';
}
对应输出为:
1
2
3
注意:我们取出的每个 Role 模型对象,都会被自动赋予 pivot 属性。此属性代表中间表的模型,它可以像其它的 Eloquent 模型一样被使用。
默认情况下,pivot 对象只提供模型的键。如果你的 pivot 数据表包含了其它的属性,则可以在定义关联方法时指定那些字段:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
4.远层一对多
1>所谓的“远层一对多”指的是通过一个中间关联对象访问远层的关联关系,比如用户与文章之间存在一对多关系,国家与用户之间也存在一对多关系,那么通过用户可以建立国家与文章的之间的一对多关联关系,我们称之为“远层一对多”。
数据表设计如下

2>我们创建一个模型Country,并在其中定义国家与文章的远层一对多关系如下:
public function posts() {
return $this->hasManyThrough('App\Http\Models\Post','App\Http\Models\Users');
}
其中第一个参数是关联对象类名,第二个参数是中间对象类名。
当运行关联查找时,通常会使用 Eloquent 的外键约定。如果你想要自定义关联的键,则可以将它们传递至 hasManyThrough 方法的第三与第四个参数。第三个参数为中间模型的外键名称,而第四个参数为最终模型的外键名称.
public function posts() {
return $this->hasManyThrough('App\Http\Models\Post','App\Http\Models\Users',$country_id,$user_id);
}
接下来我们在控制器中定义测试代码如下:
$country = Country::find(1);
$posts = $country->posts; echo 'Country#'.$country->name.'下的文章:<br>';
foreach($posts as $post){
echo '<<'.$post->title.'>><br>';
}
页面会输出:该国家下对应的所有文章
Country#china下的文章:
<<test1>>
<<test2>>
<<test4>>
5、多态关联
1>多态关联允许一个模型在单个关联中从属一个以上其它模型。比方说你可为你的工作人员和产品保存一些照片。使用多态关联,你可以对这两种情况使用单个 photos 数据表
数据表设计如下:

2>分别定义三个模型
class Photo extends Model {
/** * 获取所有拥有的 imageable 模型。 */
public function imageable() { return $this->morphTo();
}
}
class Staff extends Model {
/** * 获取所有工作人员的照片。 */
public function photos() {
return $this->morphMany('App\Http\Models\Photo', 'imageable');
}
}
class Product extends Model {
/** * 获取所有产品的照片。 */
public function photos() {
return $this->morphMany('App\Http\Models\Photo', 'imageable');
}
}
其中第一个参数是关联模型类名,第二个参数是关联名称,即$imageable_id和$imageable_type中的$imageable部分。当然也可以传递完整参数到morphMany方法:
$this->morphMany('App\Http\Models\Comment',$imageable,$imageable_type,$imageable_id,$id);
最后一个参数是Staff/Products表的主键。
3>接下来我们在控制器中定义测试代码如下:
$staff = Staff::find(1);
echo $staff->name.'的照片信息:<br />';
foreach ($staff->photos as $photo) {
echo $photo->id.'<br />';
echo $photo->path.'<br />';
}
$product = Product::find(1);
echo '产品编号为'.$product->id.'的照片信息:<br />';
foreach ($product->photos as $photo) {
echo $photo->id.'<br />';
echo $photo->path.'<br /><br />';
}
输出结果如下
tom的照片信息:
1
/test/1
2
/test/2
产品编号为1的照片信息:
4
/test/4
6.多态多对多
1>博客的 Post 和 Video 模型可以共用多态关联至 Tag 模型。使用多对多的多态关联能够让你的博客文章及图片共用独立标签的单个列表
数据表设计如下

2>Post 及 Video 模型都会拥有 tags 方法,并在该方法内调用自身 Eloquent 类的 morphToMany 方法:
class Post extends Model {
/** * 获取该文章的所有标签。 */
public function tags() {
return $this->morphToMany('App\Http\Models\Post', 'taggable');
}
}
在 Tag 模型上,你必须为每个要关联的模型定义一个方法。因此,在这个例子中,我们需要定义一个 posts 方法及一个 videos 方法:
class Tag extends Model {
/** * 获取所有被赋予该标签的文章。 */
public function posts() {
return $this->morphedByMany('App\Http\Models\Post', 'taggable');
/** * 获取所有被赋予该标签的图片。 */
public function videos() {
return $this->morphedByMany('App\Http\Models\Video', 'taggable');
}\Video', 'taggable');
} }
3>你可以简单的使用 tags 动态属性来访问文章的所有标签:
$post = Post::find(1);
echo $post->title.'下面的标签:<br />';
foreach ($post->tags as $tag) {
echo $tag->name.'<br />';
}
输出结果:
test1下面的标签:
tag1
tag2
tag3
4>你也可以从多态模型的多态关联中,通过访问运行调用 morphedByMany 的方法名称来获取拥有者。在此例子中,就是 Tag 模型的 posts 或 videos 方法。因此,你可以通过访问使用动态属性来访问这个方法:
$tag = Tag::find(1);
echo $tag->name.'下面的视频:<br />';
foreach ($tag->videos as $video) {
echo $video->name.'<br />';
}
输出结果:
tag1下面的视频:
video1
video2
video3