【问题标题】:Laravel API Resource: How to return infinite nested array of categories with their children?Laravel API 资源:如何返回无限嵌套的类别数组及其子类别?
【发布时间】:2020-04-10 01:31:33
【问题描述】:

我使用 Laravel 6.x,以下是我的响应 JSON。

{
    "data": [
        {
            "id": 1,
            "name": "quam",
            "parent_id": 0
        },
        {
            "id": 2,
            "name": "quia",
            "parent_id": 1
        },
        {
            "id": 3,
            "name": "beatae",
            "parent_id": 1
        },
        {
            "id": 4,
            "name": "aut",
            "parent_id": 2
        },
        {
            "id": 5,
            "name": "provident",
            "parent_id": 0
        },
        {
            "id": 6,
            "name": "voluptate",
            "parent_id": 0
        },
        {
            "id": 7,
            "name": "vel",
            "parent_id": 2
        },
        {
            "id": 8,
            "name": "sed",
            "parent_id": 3
        },
        {
            "id": 9,
            "name": "voluptates",
            "parent_id": 0
        },
        {
            "id": 10,
            "name": "adipisci",
            "parent_id": 6
        },
        ...
    ]
}

但它想变成这样:

{
    "data": [
        {
            "id": 1,
            "name": "quam",
            "children": [
                {
                   "id": 2,
                   "name": "quam"
                   "children":[
                       {
                           "id": 4,
                           "name": "aut"
                       },
                       {
                           "id": 7,
                           "name": "vel",
                           "children": [
                                ...
                           ]
                       }
                   ]
                 },
                 {
                   "id": 3,
                   "name": "quam",
                   "children":[
                       {
                           "id": 8,
                           "name": "sed"
                       }
                   ]
                 },
            ]
        },
        {
            "id": 5,
            "name": "provident"
        },
        {
            "id": 6,
            "name": "voluptate",
            "children": [
                 {
                      "id": 10,
                       "name": "adipisci"
                 }
            ]
        },
        {
            "id": 9,
            "name": "voluptates"
        },
        ...
}

其实我是想去掉parent_id属性,给每个由其他对象组成的对象加上children数组都有这个parent_id。

CategoryResource.php

class CategoryResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'parent_id' => $this->parent_id,
        ];
    }
}

CategoryController.php

class CategoryController extends Controller
{
    public function index()
    {
        return CategoryResource::collection(Category::all());
    }
}

如何实现这个结构?

【问题讨论】:

  • 拥有无限资源。我的意思是,您需要设置一些限制,否则您将无法预测成本。
  • 显示的输入数组无法正确转换为树形数组

标签: php laravel api laravel-6 jsonapi-resources


【解决方案1】:

假设类别是一个雄辩的模型,模型可以在关系中引用自己,并且这些关系可以是递归的。


class Category extends Model
{

    protected $hidden = ['parent_id'];

    public function children()
    {
        return $this->hasMany('App\Category', 'parent_id')->with('children');
    }
}

所以现在得到你想要的结构就像

Category::with('children:id,name,parent_id')->get('id', 'name', 'parent_id');

您必须在 select 语句中包含 parent_id 才能使关系起作用,但是我添加到模型中的 $hidden 变量使 parent_id 不会出现在序列化结果中。这里唯一需要注意的是,所有类别都将具有children 属性,对于没有子类别的类别,该属性将为空。所以在你的 toArray 方法中,你必须检查空的 children[] 并排除它们

【讨论】:

    【解决方案2】:

    据我所知,您的问题只是关系。要创建“树资源”,您必须加载大量关系。

    恕我直言,这不是一个好的选择,特别是如果您必须加载大量元素,但一般来说,像这样的结构可能是一个危险的瓶颈。

    无论如何... 最简单的方法是急切加载,因此您必须添加具有此属性的基本模型(查看official documentation

    class Parent extends Model {
    
      // [...]
    
      /**
       * The relationships that should always be loaded.
       *
       * @var array
       */
      protected $with = ['children'];
    
      // [...]
    
      public function children() {
         return $this->hasMany('whatever');
      }
    }
    

    接下来,您必须按如下方式更新您的 JSON 资源(为此,请查看 official documentation about resource relationships)。

    class CategoryResource extends JsonResource
    {
    
        public function toArray($request)
        {
            return [
                'id' => $this->id,
                'name' => $this->name,
                'parent_it' => $this->parent_id,
                'childrend' => ChildrenResource::collection($this->whenLoaded('children')),
            ];
        }
    }
    

    这样,由于每次您请求 Parent 时,它都会急切地加载其子项,因此资源将递归地映射到 Child 资源,每个关系都向下映射到叶子。

    【讨论】:

    • 在将 ChildrenResource 更改为 CategoryResource 或 Self 后,它对我有用。谢谢
    【解决方案3】:

    首先,您需要定义一个关系,以使用此方法检索没有父母的主要类别的孩子

    /**
     * get sub product categories of this category
     *
     * @return mixed
     */
    public function childCategories()
    {
        return $this->hasMany(Category::class,'parent_id');
    }
    

    那么你需要用这个方法加载子类的子类:

    /**
     * get recursive all sub categories of this category.
     *
     * @return mixed
     */
    public function childrenCategories()
    {
        return $this->hasMany(Category::class,'parent_id')->with('childCategories');
    }
    

    现在您可以使用此静态函数检索它们

    /**
     * get all Main categories with children.
     *
     * @return mixed
     */
    public static function allMainCategoriesWithChildren()
    {
        return self::whereNull('parent_id')->with('childrenCategories')->get();
    }
    

    现在您可以在资源中使用它或直接在控制器中返回它

    use App\Category;
    return Category::allMainCategoriesWithChildren();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-26
      • 2018-09-10
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多