jflizandro
jflizandro

Reputation: 632

Create a tree structure from two tables

So, my problem is that I need to build a tree with data from two tables.

I have the following tables:

Category:

| id | parent_id | name           |
|----|-----------|----------------|
| 1  | null      | Category 1     |
| 2  | 1         | Category 1.1   |
| 3  | 2         | Category 1.1.1 |
| 4  | null      | Category 2     |
| 5  | 4         | Category 2.1   |
| 6  | null      | Category 3     |


Layer:

| id | category_id | name    |
|----|-------------|---------|
| 1  | 2           | Layer 1 |
| 2  | 2           | Layer 2 |
| 3  | 3           | Layer 3 |
| 4  | 4           | Layer 4 |
| 5  | 4           | Layer 5 |
| 6  | 5           | Layer 6 |

My Category model:

class Category extends Model
{
    public function parent()
    {
        return $this->belongsTo('App\Category', 'parent_id');
    }

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

    public function layers()
    {
        return $this->hasMany('App\Layer', 'category_id', 'id');
    }
}

Layer model:

class Layer extends Model
{
    public function category()
    {
        return $this->belongsTo('App\Category', 'category_id');
    }
}

I'm using the following function to build the category tree:

public function index()
{
    $categories = Category::all();
    $layers = Layer::all();

    return $this->buildTree($categories->toArray(), null);
}


function buildTree($categories, $parent_id)
{
    $categoriesTree = [];
    foreach ($categories as $category) {
        $category['folder'] = true;

         if ($category['parent_id'] == $parent_id) {
            $childrens = $this->buildTree($categories, $category['id']);
            if ($childrens) {
                $category['childrens'] = $childrens;
            }

            $categoriesTree[] = $category;
        }
    }

    return $categoriesTree;
}

The above function works well for categories and the response is:

But I want to add layers as child of respective category, like the following:

What is the best way to do this?

Upvotes: 1

Views: 550

Answers (1)

Dan
Dan

Reputation: 5358

I suggest using a relationship in your Category model with the Layer model and eager load it. This way you achieve the same result but with less overhead on your buildTree function because Laravel is doing most of the work:

Category.php model

class Category extends Model
{
    // ...

    public function layers()
    {
        return $this->hasMany(Layer::class);
    }

    // ...
}

In your controller:

public function index()
{
    $categories = Category::with('layers')->get();

    // ...
}

This results in an array like this:

eager loaded layers per category

Upvotes: 1

Related Questions