Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel API Resource: How to return infinite nested array of categories with their children?

I use Laravel 6.x and below is my response 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
        },
        ...
    ]
}

But it want to be like this:

{
    "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"
        },
        ...
}

In fact, I want to remove the parent_id attribute and add children array to each object that consists of other objects have this 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());
    }
}

How can I implement this structure?

like image 381
Fred II Avatar asked Oct 28 '25 06:10

Fred II


1 Answers

From what I see your problem is just the relations. To create a "tree resource" you have to load a lot of relations.

IMHO it's not a good choice, expecially if you have to load a lot of elements but generally, structures like these may be a dangerous bottleneck.

Anyway... The easy way it's the eager loading, so you have to add your base model with this attribute (have a look at the 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');
  }
}

next you have to update your JSON Resource as follows (also for this, have a look at the 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')),
        ];
    }
}

In this way, since everytime you request a Parent it will eager load its children, the resource will recursively map into a Child resource each relation down to the leaf.

like image 171
IlGala Avatar answered Oct 29 '25 19:10

IlGala



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!