How to Create a Nested-List of Categories in Laravel

How to create a nested-list of categories in Laravel?

You can make a self-referential model:

class Category extends Model {

public function parent()
{
return $this->belongsTo('Category', 'parent_id');
}

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

and make a recursive relation:

// recursive, loads all descendants
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}

and to get parents with all their children:

$categories = Category::with('childrenRecursive')->whereNull('parent_id')->get();

Lastly you need to just iterate through the children until children is null. There can definitely be some performance issues with this if you are not careful. If this is a fairly small dataset that you plan to remain that way it shouldn't be an issue. If this is going to be an ever growing list it might make sense to have a root_parent_id or something to query off of and assemble the tree manually.

Create a nested lists of categories in Laravel 5

You are currently loading all categories (including the child ones) and then looping through them. You only want to load the root categories (categories without parent). To do this, change your controller method to only load categories where the parent_id is null.

$categories = Category::whereNull('parent_id')->with('children')->get();

Create a breadcrumb of nested lists of categories in Laravel 5.2

First of all think to change your categories structure to the Nested Set model. It's better and esier to handle nested categories (and ant other structure). Here is nice Laravel's package:

https://github.com/etrepat/baum

For your example there is only not especially optimal solution. When you willl query the leaf category:

$category = Categories::where('parent_id', $parent_id)
->orderBy('name', 'ASC')
->first();
return view({your view here}, compact('category'));

You'll need partial view (ex.: breadcrumb.blade.php) with section:

<ul>
@section('breadcrumb')
@show
</ul>

The in the main action vie you can do somethink like that:

@section('breadcrumb')
<li>{{$category->name}}</li>
@stop
@while($parent = $category->parent)
@section('breadcrumb')
@parent
<li>{{$parent->name}}</li>
@stop
@endwhile

ATTENTION

But as I said in the begining - this is VERY sub-optimal solution because you have to call query for each parent, so it's only fine if you have not much nested levels.

Laravel - How to get all nested subcategories recursively

After some research I have found the solution


Category Model

public function subcategories(){
return $this->hasMany(Category::class, 'parent_id');
}

public function children(){
return $this->subcategories()->with('children');
}

public function hasChildren(){
if($this->children->count()){
return true;
}
return false;
}

public function findDescendants(Category $category){
$this->descendants[] = $category->id;

if($category->hasChildren()){
foreach($category->children as $child){
$this->findDescendants($child);
}
}
}

public function getDescendants(Category $category){
$this->findDescendants($category);
return $this->descendants;
}

Controller

$category = Category::find($cat_id);
$category_ids = $category->getDescendants($category);
echo '<pre>'; print_r($categoriesID); die;

I have found the solution here

Laravel 5.6 Nested Categories

You have to adjust your route:

Route::get('{category1}/{category2?}/{category3?}/{category4?}',
'ProductController@category');

And your controller:

public function category(Category $category1, Category $category2 = null,
Category $category3 = null, Category $category4 = null) {
$category = collect(func_get_args())->filter()->last();

$categories = $category->children;

return view('product.list', compact('categories'));
}

How to print infinity nested categories in dropdown (select) menu in Laravel

In your main blade template do like below. Here we first add the select box then loop through the categories. If a parent category has childs, then first the childs are added by calling another template and passing childs data to it.

<select name="" id="">     
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>

@if (count($category->childs) > 0)
@include('subcategories', ['subcategories' => $category->childs, 'parent' => $category->name])
@endif

@endforeach
</select>

Now, we have to create childs displaying template. Based on my example, the name should be subcategories.blade.php. In the child blade template, add the followings:

@foreach ($subcategories as $sub)
<option value="{{ $sub->id }}">{{ $parent}} -> {{ $sub->name }}</option>

@if (count($sub->childs) > 0)
@php
// Creating parents list separated by ->.
$parents = $parent . '->' . $sub->name;
@endphp
@include('subcategories', ['subcategories' => $sub->childs, 'parent' => $parents])
@endif
@endforeach

In the child template, we are recursively calling the child template itself over and over as long as each child has other childs.

And, here is the outcome on my machine: https://ibb.co/ynRB04h

laravel 5 nested category and nested sub category

If I understand well, to obtain children relationship you could use the following method on the App\Category model:

// app/Category.php

public function children(): HasMany
{
return $this->hasMany(static::class, 'cat_parent_id', 'id');
}

Then to obtain all children of the main category:

use App\Category;

$children = Category::where('name','Child-1- P - 2')->first()->children;

And here is a supporting test with a factory:

// database/factories/CategoryFactory.php

use App\Category;

$factory->define(Category::class, function (Faker $faker) {
static $id = 1;
return [
'name' => 'Category '.$id++,
'cat_parent_id' => null,
];
});

// tests/Unit/Models/CategoryTest.php

use App\Category;

/**
* @test
*/
public function returns_associated_child_records()
{
// create master records
factory(Category::class, 3)->create();

// get parent for the sub-categories
$parent = $master->first();

// create sub-categories
foreach(range(1, 4) as $id) {
factory(Category::class)->create([
'name' => 'Sub category '.$id,
'cat_parent_id' => $parent->id
]);
}

$this->assertEquals(
['Sub category 1', 'Sub category 2', 'Sub category 3', 'Sub category 4'],
Category::where('name', $parent->name)->first()->children->pluck('name')->toArray()
);
}

I'm working here on the assumption that category names will be unique - otherwise you'd have to loop over the collection of records.



Related Topics



Leave a reply



Submit