【问题标题】:Laravel: Retrieve polymorphic attributes efficientlyLaravel:有效地检索多态属性
【发布时间】:2015-09-02 08:19:53
【问题描述】:

我的实际问题是: 如何将我真正需要的属性返回给客户端,将其余的扔掉并尽可能高效?

所以,我有一个结构,其中我基本上有媒体对象,可以是不同类型的,如视频、图片、链接等。这是以多态方式构造的。在这个例子中,用户可以有一个头像,它实际上是一个媒体对象,但我在客户端唯一感兴趣的实际上是图像 url。

我们的应用程序是 RESTful 的,如果我想列出所有用户,我希望用户 JSON 基本上返回一个属性,其中 仅 是头像的 url,而不是完整的多态模型,然后我必须在客户端遍历,更不用说从服务器发送到客户端的巨大开销。

来自用户模型:

/**
 * A user can have an avatar
 *
 * @return \Illuminate\Database\Eloquent\Relations\MorphOne
 */
public function avatar() {
    return $this->morphOne('Fanlete\Media', 'appendable');
}

来自媒体模型:

/**
 * A media element can be extended in different ways (kind of inheritance), this function morphs to the specific implementation
 *
 * @return \Illuminate\Database\Eloquent\Relations\MorphTo
 */
public function mediable()
{
    return $this->morphTo();
}

/**
 * A media element can be appended by various models, i.e. a user to save its avatar
 *
 * @return \Illuminate\Database\Eloquent\Relations\MorphTo
 */
public function appendable() {
    return $this->morphTo();
}

来自 Picture Model,一个具体的媒体实现:

public function media()
{
    return $this->morphMany('Fanlete\Media', 'mediable');
}

所以,假设我有一个功能可以列出我的控制器中的所有用户:

public function index()
{
    return User::all();

}

我想要这样的输出:

{
    "id": 1,
    "email": "user@example.org",
    "name": "Example",
    "surname": "User",
    "created_at": "2015-06-17 07:05:26",
    "updated_at": "2015-06-17 07:05:26",
    "avatar": "http://upload.wikimedia.org/wikipedia/en/3/38/Avatarjakeneytiri.jpg"
}

目前我是这样解决的,实际上感觉不是那么优雅,而且不知何故非常错误和瓶颈:

又是用户模型:

protected $appends = ['avatar'];

public function getAvatarAttribute()
{
    return $this->avatar()->get()->first()->mediable()->get()->first()->url;
}

当然我也可以在我的控制器中做这样的事情:

$users = Users::with("avatar.mediable")->get()->all();
// Now sort out attributes I don't need and return array

如果没有排序,输出将如下所示(非常混乱且开销巨大):

{

    "id": 1,
    "email": "user@example.org",
    "name": "Example",
    "surname": "User",
    "created_at": "2015-06-17 07:05:26",
    "updated_at": "2015-06-17 07:05:26",
    "avatar": 

    {
        "id": 6,
        "appendable_id": 1,
        "appendable_type": "Fanlete\\User",
        "mediable_id": 6,
        "mediable_type": "Fanlete\\Picture",
        "created_at": "2015-06-17 07:05:26",
        "updated_at": "2015-06-17 07:05:26",
        "mediable": 

                {
                    "id": 6,
                    "url": "http://upload.wikimedia.org/wikipedia/en/3/38/Avatarjakeneytiri.jpg",
                    "title": null,
                    "created_at": "2015-06-17 07:05:26",
                    "updated_at": "2015-06-17 07:05:26"
                }
            }
}

但这也感觉像是一种解决方法,并且正是我不需要和想要的开销。

谢谢

【问题讨论】:

    标签: rest laravel polymorphism eloquent


    【解决方案1】:

    你可能就快到了。

    您的getAvatarAttribute() 确实太复杂了。您可以尝试执行以下操作:

    /** we hide the relation from the json */
    protected $hidden = ['avatar'];
    
    /** we append the url of the avatar to the json */
    protected $appends = ['avatar_url'];
    
    /**
     * To not be confused with the avatar() method, I used avatar_url.
     */
    public function getAvatarUrlAttribute()
    {
        return $this->avatar->mediable->url;
    }
    

    然后,您应该能够在没有瓶颈的情况下执行$users = User::with('avatar.mediable')->get();,并获得良好的 JSON 响应。

    【讨论】:

    • 像魅力一样工作,甚至与其他模型级联!因此,例如,如果博客文章有用户作为关注者,您的解决方案也会使用 avatar_url 级联以下用户。我必须做出一点改变:return User::with('avatar.mediable')->get()->all();- 注意中间的“get()”。
    • 还有一件事:它也适用于 return User::all();- 我真的不明白为什么,但似乎 laravel 在这里为我考虑并自动为我包含所有子模型。
    • @Thinklabs 我不确定 Laravel 是否会在没有 with() 的情况下急切加载头像,这可能会导致性能问题。
    • 嘿,你的速度更快:是的,确实:使用“with” - 关键字可以利用急切加载。所以你的回答非常有效。更多信息可以在这里找到:http://laravel.com/docs/5.0/eloquent#eager-loading - 如果没有“with”,它也可以工作,但在某些情况下可能会很慢。
    猜你喜欢
    • 2019-11-14
    • 2020-11-14
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2017-04-11
    • 2013-08-21
    相关资源
    最近更新 更多