简介
数据库表通常相互关联。例如,一篇博客文章可能有许多评论,或者一个订单对应一个下单用户。Eloquent 让这些关联的管理和使用变得简单,并支持多种类型的关联:
一对一
一对多
多对多
远程一对多
多态关联
多对多多态关联
定义关联
Eloquent 关联在 Eloquent 模型类中以方法的形式呈现。如同 Eloquent 模型本身,关联也可以作为强大的 查询语句构造器 使用,提供了强大的链式调用和查询功能。例如,我们可以在 posts
关联的链式调用中附加一个约束条件:
$user->posts()->where('active', 1)->get();
不过,在深入使用关联之前,让我们先学习如何定义每种关联类型。
一对一
一对一关联是最基本的关联关系。例如,一个 User
模型可能关联一个 Phone
模型。为了定义这个关联,我们要在 User
模型中写一个 phone
方法,在 phone
方法内部调用 hasOne
方法并返回其结果:
<?php namespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{/**
* 获取与用户关联的电话号码记录。
*/public function phone(){return $this->hasOne('App\Phone');}}
hasOne
方法的第一个参数是关联模型的类名。一旦定义了模型关联,我们就可以使用 Eloquent 动态属性获得相关的记录。动态属性允许你访问关系方法就像访问模型中定义的属性一样:
$phone = User::find(1)->phone;
Eloquent 会基于模型名决定外键名称。在这个列子中, 会自动假设 Phone
模型有一个 user_id
的外键。如果你想覆盖这个约定,可以传递第二个参数给 hasOne
方法:
return $this->hasOne('App\Phone', 'foreign_key');
另外,Eloquent 假设外键的值是与父级 id
(或自定义 $primaryKey
)列的值相匹配的 。换句话说,Eloquent 将会在 Phone
记录的 user_id
列中查找与用户表的 id
列相匹配的值。如果您希望该关联使用 id
以外的自定义键名,则可以给 hasOne
方法传递第三个参数:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
定义反向关联
我们已经能从 User
模型访问到 Phone
模型了。现在,让我们再在 Phone
模型上定义一个关联,这个关联能让我们访问到拥有该电话的 User
模型。我们可以使用与 hasOne
方法对应的 belongsTo
方法来定义反向关联:
<?php namespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model{/**
* 获得拥有此电话的用户。
*/public function user(){return $this->belongsTo('App\User');}}
在上面的例子中,Eloquent 会尝试匹配 Phone
模型上的 user_id
至 User
模型上的 id
。它是通过检查关系方法的名称并使用 _id
作为后缀名来确定默认外键名称的。但是,如果 Phone
模型的外键不是 user_id
,那么可以将自定义键名作为第二个参数传递给 belongsTo
方法:
/**
* 获得拥有此电话的用户。
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key');
}
如果父级模型没有使用 id
作为主键,或者是希望用不同的字段来连接子级模型,则可以通过给 belongsTo
方法传递第三个参数的形式指定父级数据表的自定义键:
/**
* 获得拥有此电话的用户。
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}
默认模型
belongsTo
关联允许定义默认模型,这适应于当关联结果返回的是 null
的情况。这种设计模式通常称为 空对象模式,为您免去了额外的条件判断代码。在下面的例子中,user
关联如果没有找到文章的作者,就会返回一个空的 App\User
模型。
/**
* 获得此文章的作者。
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault();
}
您也可以通过传递数组或闭包给 withDefault
方法,已填充默认模型的属性:
/**
* 获得此文章的作者。
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault([
'name' => '游客',
]);
}
/**
* 获得此文章的作者。
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault(function ($user) {
$user->name = '游客';
});
}
看完本文有收获?点赞、分享是最大的支持!