如何在不获取模型内容的情况下从相关模型中追加Eloquent属性?

时间:2016-10-01 19:33:14

标签: php mysql eloquent

我有2个雄辩的模特:

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;
}

不幸的是,当我运行它时,我只需要全名和整个用户模型,而我只需要全名。

有没有办法避免附加用户模型的内容?

4 个答案:

答案 0 :(得分:1)

感觉就像是在尝试使用EloquentUser模型中的SharedEvent模型头等公民制作列。你越来越近了,但考虑一下......

在处理关系时,这是明确的好方法:

假设user_full_nameUser型号的访问者:

// 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

这应该让你最接近你想要的,但你应该知道几件事:

  1. 如果user_full_name是访问者,则需要选择构成该访问者的所有列(如上所述)
  2. 您必须选择相关的密钥(user_id中的EloquentUsershared_with_id中的SharedEvent
  3. 此处$appends需要EloquentUser,因为您无法在闭包内直接添加子查询的访问者。
  4. 尝试使用闭包作为关系中的第二个参数。这是你在加载关系时选择哪些列的最佳方法 - Eloquent让你很容易变得懒惰而且只是这样做:

    SharedEvent::with('user')->get();
    

    正如您所看到的,select *与您的SharedEvent关系只会user

    在处理使用关系的复杂查询时,我注意到的另一件事是,您可以快速达到感觉就像在与框架作斗争的程度。这通常是考虑简化使用原始SQL的标志。 Eloquent功能强大,但它只是编程工具带中的另一个工具。请记住,您可以使用其他工具。

答案 1 :(得分:0)

你能试试吗?

public function user() : BelongsTo {
    return $this->belongsTo('Path\To\EloquentUser', 'shared_with_id', 'user_id')->select('fullName','user_id');
}

答案 2 :(得分:0)

在做了一些研究和实验之后,看起来似乎没有办法用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;
}

答案 3 :(得分:0)

我遇到了同样的问题,我的第一个想法是在获取 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):

  

请注意,即使访问器是使用“驼峰大小写”定义的,属性名称也通常在“蛇形大小写”中引用