简体   繁体   English

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

[英]How can I append an Eloquent property from a related model without getting the model's contents?

I have 2 eloquent models:我有两个雄辩的模型:

EloquentUser

and

SharedEvents

They are both related by user_id它们都通过 user_id 相关

I'm attempting to set up and appends attribute in the SharedEvents model that will append the full_name of the user with whom the event has been shared.我正在尝试在 SharedEvents 模型中设置和附加属性,该属性将附加与该事件共享的用户的全名。

For the sake of readability, I'm only including the appends components of my class为了可读性,我只包括我的类的附加组件

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

Unfortunately when I run this I'm getting back both the full name and the entire user model when I only want the full name.不幸的是,当我运行它时,当我只想要全名时,我会返回全名和整个用户模型。

Is there a way to avoid attaching the content of the user model?有没有办法避免附加用户模型的内容?

It feels like you're trying to make columns from your EloquentUser model first class citizens in your SharedEvent model.这感觉就像你想从您列EloquentUser模型一等公民在您的SharedEvent模型。 You're getting close, but consider...你正在接近,但考虑......

When working with relationships, this is a good way to be explicit:在处理关系时,这是一个明确的好方法:

Assuming user_full_name is an accessor on your User model:假设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

This should get you the closest to what you want, but there are a couple of things you should know:这应该会让你最接近你想要的,但有几件事你应该知道:

  1. If user_full_name is an accessor, you need to select all of the columns that make up that accessor (as I mention above)如果user_full_name是一个访问器,您需要选择组成该访问器的所有列(正如我上面提到的)
  2. You must select the related keys ( user_id in EloquentUser and shared_with_id in SharedEvent )您必须选择相关按键( user_idEloquentUsershared_with_idSharedEvent
  3. The $appends is necessary in EloquentUser here because you can't directly add an accessor to your sub query inside the closure.这里的EloquentUser$appends是必需的,因为您不能直接在闭包内的子查询中添加访问器。

Try to get comfortable with using a closure as the 2nd argument in your relationships.试着习惯使用闭包作为你们关系中的第二个参数。 It's the best way to really be precise as to which columns you're selecting when you're loading relationships — Eloquent makes it really easy to be lazy and just do:这是在加载关系时真正准确选择哪些列的最佳方式——Eloquent 让懒惰变得非常容易,只需执行以下操作:

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

which as you've see will just do a select * on both SharedEvent and your user relationship.正如您所看到的, SharedEvent和您的user关系执行select *

Another thing I've noticed when working with complex queries that use relationships is that you can quickly reach a point where it feels like you're fighting the framework.在处理使用关系的复杂查询时,我注意到的另一件事是,您可以很快达到感觉就像是在与框架作斗争的地步。 That's often a sign to consider simplifying ot just using raw SQL.这通常是考虑简化而不是仅使用原始 SQL 的标志。 Eloquent is powerful, but is just another tool in your programming tool belt. Eloquent 功能强大,但只是您编程工具带中的另一个工具。 Remember that you have other tools at your disposal.请记住,您还有其他工具可供使用。

I was running into the same problem, and my first idea was to explicitly hide the (entire) associated model when fetching SharedEvent .遇到了同样的问题,我的第一个想法是在获取SharedEvent时显式隐藏(整个)关联模型。

In your case, this would look like:在你的情况下,这看起来像:

class SharedEvents extends Model {

   protected $appends  = ['fullName'];
   protected $hidden   = ['user'];
   ...
}

I actually decided against this since I am returning a lot of other attached models, so I decided on attaching the entire user, but I tested it and it works.我实际上决定反对这个,因为我返回了很多其他附加的模型,所以我决定附加整个用户,但我测试了它并且它有效。

FYI, I'm not sure if the discrepancy is due to an older version of Laravel, but Eloquent actually expects $appends attributes to be in snake-case ( https://laravel.com/docs/5.6/eloquent-serialization#appending-values-to-json ):仅供参考,我不确定这种差异是否是由于 Laravel 的旧版本造成的,但 Eloquent 实际上希望 $appends 属性是蛇形的( https://laravel.com/docs/5.6/eloquent-serialization#appending -values-to-json ):

Note that attribute names are typically referenced in "snake case", even though the accessor is defined using "camel case"请注意,属性名称通常在“snake case”中引用,即使访问器是使用“camel case”定义的

Can you try this?你能试试这个吗?

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

After doing some research and experimentation, it doesn't look like there's a way to do this with Eloquent.在做了一些研究和实验之后,看起来 Eloquent 没有办法做到这一点。 The solution I ended up going with unfortunately is running an additional query.不幸的是,我最终采用的解决方案是运行一个额外的查询。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM