Laravel: 有效地检索多态属性
Laravel: Retrieve polymorphic attributes efficiently
我的实际问题是:
如何 return 将我实际需要的属性分配给客户端,将其余部分扔掉并尽可能高效?
所以,我有一个基本上有媒体对象的结构,可以是不同类型,如视频、图片、link 等等。这是以多态方式构造的。在这个例子中,用户可以有一个头像,它实际上是一个媒体对象,但我在客户端唯一感兴趣的实际上是图像 url.
我们的应用程序是 RESTful,如果我想列出所有用户,我希望用户 JSON 基本上 return 一个 属性 和 只有头像的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();
}
来自图片模型,一个具体的媒体实现:
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
如果没有 sortin,输出将如下所示(非常混乱且开销巨大):
{
"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"
}
}
}
但这也感觉像是一种解决方法,而且正是我不需要也不想要的开销。
感谢
你可能就快到了。
您的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 响应。
我的实际问题是: 如何 return 将我实际需要的属性分配给客户端,将其余部分扔掉并尽可能高效?
所以,我有一个基本上有媒体对象的结构,可以是不同类型,如视频、图片、link 等等。这是以多态方式构造的。在这个例子中,用户可以有一个头像,它实际上是一个媒体对象,但我在客户端唯一感兴趣的实际上是图像 url.
我们的应用程序是 RESTful,如果我想列出所有用户,我希望用户 JSON 基本上 return 一个 属性 和 只有头像的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();
}
来自图片模型,一个具体的媒体实现:
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
如果没有 sortin,输出将如下所示(非常混乱且开销巨大):
{
"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"
}
}
}
但这也感觉像是一种解决方法,而且正是我不需要也不想要的开销。
感谢
你可能就快到了。
您的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 响应。