'Remove categories with all childs derived from parent category
I want to remove all related child categories from parent categories. I think I need a recursive function to solve this. Here is my attempt:
public function destroy(Request $request)
{
$categories = \App\Categories::select('parent_id')->whereNotNull('parent_id')->get();
foreach ($categories as $category) {
if ($category->parent_id == $request->cid) {
$childCategories = \App\Categories::select('parent_id')->where('parent_id', $category->parent_id)->get();
}
}
}
My table is like this
+-------------+----------+-----------+
| id | name | parent_id |
+-------------+----------+-----------+
| 1 | MAIN | NULL |
+-------------+----------+-----------+
| 2 | CHILD | 1 |
+-------------+----------+-----------+
| 3 | CHILD 2 | 2 |
+-------------+----------+-----------+
My expectation:
If I removed the main category, child and child 2 categories have to be removed.
How can I perform this with eloquent?
The answers are ok but it didn't work as I expected. I want to delete all of the sub-categories and its derivates. Given examples are only find the first node.
SOLUTION
I fixed this problem via migrations.
I created a FOREIGN KEY for PARENT_ID which refers to the id of category in migration file. When I perform deleting action it's removing itself with child nodes(It works also in case of its children nodes has children nodes).
Here is the migration code that I used:
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade'); Then
App\Categories::find($id)->delete(); removed with child nodes.
Solution 1:[1]
You need to check for child category's child entries too. Will you have data further deep?
Better if you repeat
foreach ($categories as $category) {
inside too with the child category to find if child exist inside.
Solution 2:[2]
I fixed this problem via migrations.
I created a FOREIGN KEY for PARENT_ID which refers to the id of category in migration file. When I perform deleting action it's removing itself with child nodes(It works also in case of its children nodes has children nodes).
Here is the migration code that I used:
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');
Then
App\Categories::find($id)->delete();
removed with child nodes.
Solution 3:[3]
I've faced the same problem and after 2~3 hours I came up with this recursive solution that worked for me.
if (!function_exists('CategoryTree')) {
function CategoryTree($categories = []) {
$categories = (new Category())->whereIn('parent_id', $categories)->get()->toArray();
if(count($categories) > 0){
return array_merge($categories, deleteCategoryTree(array_column($categories, 'id')));
}
return $categories;
}
}
and when you have to call this $categories = CategoryTree([1]);
. This function will give you an array of all the categories derived from the id(s) passed as an array in the parameter.
And for the deletion of those records, you can use the following.
(new Category())->whereIn('id', array_column($categories, 'id'))->delete();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Natarajan N Napoleon |
Solution 2 | bgul |
Solution 3 | Haroon Mahmood |