etrepat / baum

Baum is an implementation of the Nested Set pattern for Laravel's Eloquent ORM.
http://etrepat.com/baum
MIT License
2.24k stars 460 forks source link

toHierarchy() method returns roots as object with keys #213

Closed logusgraphics closed 8 years ago

logusgraphics commented 8 years ago

I'm currently using Baum (which is excellent by the way) to build a category tree structure from a seeded migration.

The method buildTree($categories) works great and seeds my pre-populated nested array perfectly.

However, when I want my controller to return a JSON array of the tree structure with the method toHierarchy() I get the root objects nested inside an object and each object hast a key and value which I can't use to model in my front-end framework (AngularJS).

This is the code in my controller:

$categories = Category::all()->toHierarchy();
return Response::json($categories, 200);

And this the response I get from my REST Client (Postman):

{
  "381": {
    "id": 381,
    "name": "Gráfica",
    "code": "GR",
    "description": "",
    "slug": "grafica",
    "parent_id": null,
    "lft": 1,
    "rgt": 56,
    "depth": 0,
    "created_at": "2016-02-19 19:33:36",
    "updated_at": "2016-02-19 19:33:36",
    "children": [
      {
        "id": 382,
        "name": "Diseño Gráfico",
        "code": "DG",
        "description": "",
        "slug": "diseno-grafico",
        "parent_id": 381,
        "lft": 2,
        "rgt": 13,
        "depth": 1,
        "created_at": "2016-02-19 19:33:36",
        "updated_at": "2016-02-19 19:33:36",
        "children": [
          {
            "id": 383,
            "name": "Imagen física de marcas",
            "code": "DG1",
            "description": "Iso-logotipos y Aplicaciones, Manuales de identidad corporativa. Arquigráfica, diseño ambiental.",
            "slug": "imagen-fisica-de-marcas",
            "parent_id": 382,
            "lft": 3,
            "rgt": 4,
            "depth": 2,
            "created_at": "2016-02-19 19:33:36",
            "updated_at": "2016-02-19 19:33:36",
            "children": []
          }
        ]
      },
      {
        "id": 388,
        "name": "Dirección de arte",
        "code": "",
        "description": "",
        "slug": "direccion-de-arte",
        "parent_id": 381,
        "lft": 14,
        "rgt": 21,
        "depth": 1,
        "created_at": "2016-02-19 19:33:36",
        "updated_at": "2016-02-19 19:33:36",
        "children": [
          {
            "id": 389,
            "name": "Dirección de Arte en Gráfica",
            "code": "DA1",
            "description": "Avisos para diarios, revistas y/o publicaciones. Brochures, guías, catálogos, memorias, editorial.",
            "slug": "direccion-de-arte-en-grafica",
            "parent_id": 388,
            "lft": 15,
            "rgt": 16,
            "depth": 2,
            "created_at": "2016-02-19 19:33:36",
            "updated_at": "2016-02-19 19:33:36",
            "children": []
          },
          {
            "id": 390,
            "name": "Dirección de Arte en Cine y TV.",
            "code": "DA2",
            "description": "Comerciales, institucionales, señales de identificación, separadores, infomerciales, artística de programas, animaciones, placas.",
            "slug": "direccion-de-arte-en-cine-y-tv",
            "parent_id": 388,
            "lft": 17,
            "rgt": 18,
            "depth": 2,
            "created_at": "2016-02-19 19:33:36",
            "updated_at": "2016-02-19 19:33:36",
            "children": []
          }        
        ]
      }
    ]
  },
  "409": {
    "id": 409,
    "name": "Vía pública",
    "code": "VP",
    "description": "",
    "slug": "via-publica",
    "parent_id": null,
    "lft": 57,
    "rgt": 62,
    "depth": 0,
    "created_at": "2016-02-19 19:33:36",
    "updated_at": "2016-02-19 19:33:36",
    "children": [
      {
        "id": 410,
        "name": "Avisos para vía pública urbana",
        "code": "VP1",
        "description": "Afiches, posters, carteleras, vallas, medianeras, gigantografías.",
        "slug": "avisos-para-via-publica-urbana",
        "parent_id": 409,
        "lft": 58,
        "rgt": 59,
        "depth": 1,
        "created_at": "2016-02-19 19:33:36",
        "updated_at": "2016-02-19 19:33:36",
        "children": []
      }
    ]
  }
}

As you can see it returns an object with nested key,value based objects as the root elements which I can't use to model in AngularJS. I need the root parent to be an array like this:

[
  {
    "id": 381,
    "name": "Gráfica",
    "code": "GR",
    "description": "",
    "slug": "grafica",
    "parent_id": null,
    "lft": 1,
    "rgt": 56,
    "depth": 0,
    "created_at": "2016-02-19 19:33:36",
    "updated_at": "2016-02-19 19:33:36",
    "children": [
      {
        "id": 382,
        "name": "Diseño Gráfico",
        "code": "DG",
        "description": "",
        "slug": "diseno-grafico",
        "parent_id": 381,
        "lft": 2,
        "rgt": 13,
        "depth": 1,
        "created_at": "2016-02-19 19:33:36",
        "updated_at": "2016-02-19 19:33:36",
        "children": []
     }
    ]
  }
]
logusgraphics commented 8 years ago

So I figured out a temporary but clean solution:

I created a recursive function to do the job which toHierarchy() was supposed to do the right way.

$categories = Category::roots()->get();

    function nestChildren($nodes)
    {
        foreach ($nodes as $node) {
            if (count($node->getDescendants()) > 0) {
                $node['children'] = $node->getDescendants();
                nestChildren($node['children']);
            }
        }
    }

    nestChildren($categories);

    return Response::json($categories, 200);

So the first line gets all the roots and then I recurse them with the getDescendants() method. And now I have the correct root array thrown at the REST client.