ThinkPHP5 Model关联查询返回指定字段
如题,我在写一个接口时需要用到关联查询,因为对ThinkPHP5 不熟悉,去查询官方文档,使用belongsTo 指定关联模型,然后写出查询语句是这样子的:
public static function getMessageListByPage($pageno, $rows)
{
$ruleList = [];
//with 关联预载入
$ruleList = collection(self::with('user')
->order('updatetime desc')
->page($pageno.','.$rows)
->field('uid, lastmessage, readstatus, file, appid')
->select())->toArray();
return $ruleList;
}
//关联方法的使用
//has_one(或has_many):外键在子关联对象中
//belongs_to:外键在父联对象中
//当有大量的关联数据需要查询的时候,一般都会考虑选择关联预载入的方式
//预载入方法定义
public function user()
{
// setEagerlyType设置预载入查询方式为 0 为 JOIN 1为 IN
return $this->belongsTo('User', 'uid', 'id', [], 'LEFT')
->field('email')
->setEagerlyType(0);
}
这是一个最新消息列表的分页查询,我想在每条消息上附带上用户邮箱,就是email字段
查询结果如下 :
[
{
"uid":45,
"readstatus":0,
"lastmessage":"0",
"file":0,
"createtime":0,
"updatetime":0,
"appid":0,
"user":{
"id":45,
"group_id":3,
"email":"xxxxxxxx@qq.com",
"password":"xxxxxxxxxxxxx",
"xxx":"xxxx"
}
}
]
虽然成功带上了email 字段,但是却是在user 属性里面,并且整个查询把user 表的所有字段都返回了,field方法对belongsTo 关联不起作用.这肯定不符合我的预期啊
于是乎遇事不决看文档,文档说可以使用bind()
方法指定查询字段,该方法支持数组,以下为官方文档:
绑定属性到父模型(V5.0.4+)
可以在定义关联的时候使用bind方法绑定属性到父模型,例如:
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function profile()
{
return $this->hasOne('Profile','uid')->bind('nickname,email');
}
}
//或者使用数组的方式指定绑定属性别名
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function profile()
{
return $this->hasOne('Profile','uid')->bind([
'email',
'truename' => 'nickname',
'profile_id' => 'id',
]);
}
}
于是我就加上了bind
方法,指定返回email字段:
public static function getMessageListByPage($pageno, $rows)
{
$ruleList = [];
//with 关联预载入
$ruleList = collection(self::with('user')
->order('updatetime desc')
->page($pageno.','.$rows)
->field('uid, lastmessage, readstatus, file, appid')
->select())->toArray();
return $ruleList;
}
//关联方法的使用
//has_one(或has_many):外键在子关联对象中
//belongs_to:外键在父联对象中
//当有大量的关联数据需要查询的时候,一般都会考虑选择关联预载入的方式
//预载人方法定义
public function user()
{
// setEagerlyType设置预载入查询方式为 0 为 JOIN 1为 IN
return $this->belongsTo('User', 'uid', 'id', [], 'LEFT')
->bind('email')
->setEagerlyType(0);
}
然后查询结果如下:
[
{
"uid":45,
"readstatus":0,
"lastmessage":"0",
"file":0,
"createtime":0,
"updatetime":0,
"appid":0,
"email":"xxxxxxxx@qq.com",
"user":{
"id":45,
"group_id":3,
"email":"xxxxxxxx@qq.com",
"password":"xxxxxxxxxxxxx",
"xxx":"xxxx"
}
}
]
坑爹呢,email字段是有了,但是user表的所有字段还是被查询出来了,连密码都查出来了,用脚趾头想也知道这指定不符合我的初衷,于是乎继续看文档,但是文档对这块介绍不多,我注意到文档里一句话
绑定关联属性不影响原有关联属性的读取,绑定关联模型的属性支持读取器。
所以说其实bind
方法不会影响关联属性,也就是查询后附加的user 模型对象
得嘞,去百度看看还有没有其他解决办法,果然找到一个 fastadmin 社区帖子
他给出的解决方法是:
//with的时候使用闭包查询
->with([
'account' => function ($query) {
$query->withField('id,user_id,account,frozen');
}, ])
于是乎我再次去修改查询方法,加入闭包指定返回email字段:
public static function getMessageListByPage($pageno, $rows)
{
$ruleList = [];
//with 关联预载入
$ruleList = collection(self::with(
['user' => function($query){
$query->withField(['email']);
}])
->order('updatetime desc')
->page($pageno.','.$rows)
->field('uid, lastmessage, readstatus, file, appid')
->select())->toArray();
return $ruleList;
}
//关联方法的使用
//has_one(或has_many):外键在子关联对象中
//belongs_to:外键在父联对象中
//当有大量的关联数据需要查询的时候,一般都会考虑选择关联预载入的方式
//预载人方法定义
public function user()
{
// setEagerlyType设置预载入查询方式为 0 为 JOIN 1为 IN
return $this->belongsTo('User', 'uid', 'id', [], 'LEFT')
->bind(['email' => 'email',])
->setEagerlyType(0);
}
查询结果为:
[
{
"uid":45,
"readstatus":0,
"lastmessage":"0",
"file":0,
"createtime":0,
"updatetime":0,
"appid":0,
"email":"xxxxxxxx@qq.com",
"user":{
"email":"xxxxxxxx@qq.com",
}
}
]
貌似达到了预期的效果,但是还是会多出user这个属性,先凑合着用吧.
我想到的是自己再做一次循环数据处理将user去除,但是觉得应该还有更优雅的方法,记录下来找到合适的方式再更新,