我有两个雄辩的模型:
EloquentUser
和
SharedEvents
它们都由user_id
关联我正在尝试在SharedEvents模型中设置和附加属性,该模型将附加与事件共享的用户的full_name。
为了可读性,我只包括了类
的追加组件class SharedEvents extends Model {
protected $appends = ['fullName'];
/**
* @return BelongsTo
*/
public function user() : BelongsTo {
return $this->belongsTo('Path'To'EloquentUser', 'shared_with_id', 'user_id');
}
/**
* @return mixed
*/
public function getFullNameAttribute(){
return $this->user->user_full_name;
}
不幸的是,当我运行这个时,当我只想要全名时,我得到了全名和整个用户模型。
是否有办法避免附加用户模型的内容?
感觉就像您试图在SharedEvent
模型中从EloquentUser
模型中获得一级公民的列。你离成功越来越近了,但是考虑一下……
当处理关系时,这是显式的好方法:
假设user_full_name
是User
模型上的访问器:
// EloquentUser.php
// This will automatically add your accessor to every query
// as long as you select the columns the accessor is made
// up of
protected $appends = ['user_full_name'];
/**
* User Full Name Accessor
* @return string
*/
public function getUserFullNameAttribute()
{
return $this->first_name . ' ' . $this->last_name;
}
// SharedEvent.php
/**
* A SharedEvent belongs to an Eloquent User
* @return BelongsTo
*/
public function user() : BelongsTo
{
return $this->belongsTo('Path'To'EloquentUser', 'shared_with_id', 'user_id');
}
// Somewhere in your controller or wherever you want to access the data
$sharedEvents = SharedEvent::with(['user' => function ($query) {
$query->select('user_id', 'first_name', 'last_name');
}])->where(...)->get(['shared_with_id', ...other columns]); // you must select the related column here
这应该让你最接近你想要的,但有几件事你应该知道:
- 如果
user_full_name
是一个访问器,您需要选择组成该访问器的所有列(如上所述) - 必须选择相关键(
EloquentUser
中的user_id
,SharedEvent
中的shared_with_id
)
$appends
在EloquentUser
中是必要的,因为你不能直接在闭包中为子查询添加访问器。试着习惯使用闭包作为关系中的第二个参数。这是在加载关系时精确选择哪些列的最好方法——Eloquent让你很容易偷懒,只需要做:
SharedEvent::with('user')->get();
,正如你所看到的,它只会对SharedEvent
和user
的关系执行select *
。
在处理使用关系的复杂查询时,我注意到的另一件事是,你可以很快达到一个点,感觉你在与框架作斗争。这通常是考虑简化而不是仅仅使用原始SQL的信号。雄辩是强大的,但只是编程工具带中的另一个工具。请记住,您还可以使用其他工具。
我遇到了同样的问题,我的第一个想法是在获取SharedEvent时显式地隐藏(整个)关联模型。
在您的例子中,它看起来像:
class SharedEvents extends Model {
protected $appends = ['fullName'];
protected $hidden = ['user'];
...
}
我实际上决定不这样做,因为我要返回很多其他附加的模型,所以我决定附加整个用户,但我测试了它,它工作。
仅供参考,我不确定是否差异是由于旧版本的Laravel,但Eloquent实际上期望$appends属性是蛇形的(https://laravel.com/docs/5.6/eloquent-serialization#appending-values-to-json):
)请注意,属性名通常以"蛇形大小写"引用,即使访问器是使用"驼形大小写"定义的
你能试试吗?
public function user() : BelongsTo {
return $this->belongsTo('Path'To'EloquentUser', 'shared_with_id', 'user_id')->select('fullName','user_id');
}
在做了一些研究和实验之后,看起来并没有办法在Eloquent中做到这一点。不幸的是,我最终采用的解决方案是运行一个额外的查询。
/**
* This is inefficient, but I could not find a way to get the full name
* attribute without including all of user.
*
* @return string
*/
public function getFullNameAttribute(){
return EloquentUser::select('user_full_name')
->where('user_id', $this->shared_with_id)
->first()
->user_full_name;
}