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
How to Install Laravel Without Using Composer
Friend of a Friend in PHP/Mysql
Add a Checkout Checkbox Field That Enable a Percentage Fee in Woocommerce
Fatal Error: Call to Undefined Function: Ldap_Connect()
How to Make My PHP Ide Understand Dependency Injection Containers
PHP Error: "The Zip Extension and Unzip Command Are Both Missing, Skipping."
Securing a Rest API Accessible from Android
Concatenate PHP Function Output to a String Like Variables
How to Trigger Xdebug Profiler for a Command Line PHP Script
Symfony2 - How to Switch from "Dev" to "Prod"
A Script to Change All Tables and Fields to the Utf-8-Bin Collation in MySQL
Send Email from Localhost with Gmail(Windows)
What Is Difference Between PHP Cli and PHP Cgi
PHP How to Go One Level Up on Dirname(_File_)