我有一个
Category
资源,如下所示:
<?php
namespace Domain\Category\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class CategoriesResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param Request $request
* @return array
*/
public function toArray($request): array
{
return [
'id' => (string)$this->id,
'type' => 'categories',
'attributes' => [
'name' => $this->name,
'slug' => $this->slug,
'parent' => $this->parent,
'description' => $this->description,
'image' => $this->image,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]
];
}
}
parent
是类别父级的ID,它本身就是一个Category
。当我调用返回此资源的端点时,我得到:
{
"data": {
"id": "5",
"type": "categories",
"attributes": {
"name": "Paper",
"slug": "paper",
"parent": 1,
"description": "test",
"image": null,
"created_at": "2022-09-09T19:01:44.000000Z",
"updated_at": "2022-09-09T19:01:44.000000Z"
}
}
}
这正是我所期望的。但现在我认为返回嵌套关系会更好,所以我不想返回上面的内容,而是想返回:
{
"data": {
"id": "5",
"type": "categories",
"attributes": {
"name": "Paper",
"slug": "paper",
"parent": {
"id": "5",
"type": "categories",
"attributes": {
"name": "Parent Paper",
"slug": "parent-paper",
"parent": 0,
"description": "test 2",
"image": "test.png",
"created_at": "2022-09-09T19:01:44.000000Z",
"updated_at": "2022-09-09T19:01:44.000000Z"
},
"description": "test",
"image": null,
"created_at": "2022-09-09T19:01:44.000000Z",
"updated_at": "2022-09-09T19:01:44.000000Z"
}
}
}
所以我考虑在模型中添加与其自身的关系:
<?php
namespace Domain\Category\Models;
use Domain\Product\Models\Product;
use Domain\Shared\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Str;
class Category extends BaseModel
{
protected $fillable = [
'name',
'parent',
'description',
'image',
];
public function parent() : BelongsTo
{
return $this->belongsTo(Category::class, 'parent');
}
}
然后更新
parent
中的 resource
字段:
public function toArray($request): array
{
return [
'id' => (string)$this->id,
'type' => 'categories',
'attributes' => [
'name' => $this->name,
'slug' => $this->slug,
'parent' => new CategoriesResource($this->parent),
'description' => $this->description,
'image' => $this->image,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]
];
}
但这不起作用。我收到一条错误消息:
尝试读取 int 上的属性“id”
此错误指向 ID 字段:
public function toArray($request): array
{
return [
'id' => (string)$this->id,
``
Furthermore, I don't want it to get into a loop, meaning that when displaying the `parent` info I don't want it to display the parent's parent and so on.
Is this possible?
我在这里看到几个问题:
为什么在 HasOne 关系上使用 CategoryResource::collection?
并且,该父级可能会嵌套创建 N+1 问题,您应该尽可能使用资源条件:https://laravel.com/docs/9.x/eloquent-resources#conditional-relationships
编辑:因此应用此功能将防止进一步加载
Category::parent
关系:
public function toArray($request): array
{
return [
'id' => (string)$this->id,
'type' => 'categories',
'attributes' => [
'name' => $this->name,
'slug' => $this->slug,
'parent' => new CategoriesResource($this->whenLoaded('parent')),
'description' => $this->description,
'image' => $this->image,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]
];
}
错误
Attempt to read property "id" on int
通常可能是由于将关系命名为与列名称相同而导致的。 Laravel 始终加载列并忽略它们具有相同名称的关系。
在模型中简单地重命名您的关系(或将您的列重命名为 ie.
parent_id
)应该可以解决问题:
class Category extends BaseModel
{
protected $fillable = [
'name',
'parent', // <-- this is the DB column name
'description',
'image',
];
public function parentEntity() : BelongsTo // <-- renamed from `parent()`
{
return $this->belongsTo(Category::class, 'parent');
}
}
或重命名列的版本:
class Category extends BaseModel
{
protected $fillable = [
'name',
'parent_id', // <-- renamed the DB column name
'description',
'image',
];
public function parent() : BelongsTo // <-- now can use `parent()` since the column is `parent_id`
{
return $this->belongsTo(Category::class, 'parent');
}
}