Laravel:具有嵌套自我关系的资源

问题描述 投票:0回答:2

我有一个

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?
php laravel laravel-9 laravel-resource
2个回答
2
投票

我在这里看到几个问题:

为什么在 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,
    ]
  ];
}

0
投票

错误

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');
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.