Reputation: 31
I would like to retrieve all posts of chosen category and all nested subcategories. I mean sth like this:
[id= 1]-Category 1
[id= 7]--Category 1.1
[id=12]---Category 1.1.1
[id=13]---Category 1.1.2
[id= 9]--Category 1.2
[id= 3]-Category 2
At first I tried to get recursively all IDs of chosen category and all nested subcategories and then retrieve posts with those categories IDs.
I wrote method getSubcategoriesIds($category)
in controller which actually give me what I want but it returns array with duplicated ids. For instans, category 1 I get:
array:10 [
0 => 1
1 => 7
2 => 1
3 => 7
4 => 12
5 => 1
6 => 7
7 => 12
8 => 13
9 => 9
]
How can I improve the method to return IDs without duplicates? Or maybe there is better way to revive those posts?
Here are my files:
Model Category.php:
class Category extends Model {
public function parent() {
return $this->belongsTo('App\Category', 'parent_id');
}
public function children() {
return $this->hasMany('App\Category', 'parent_id');
}
public function subcategories() {
return $this->children()->with('subcategories');
}
public function parents() {
return $this->parent()->with('parents');
}
public function posts(){
return $this->hasMany('App\Post');
}
}
PostController.php:
public function show($id)
{
$ids =$this->getSubcategoriesIds(Category::with('subcategories')->where('id', $id)->first()));
$posts = Post::whereIn('category_id', $ids)->get();
return view('post.index', compact('posts'));
}
public function getSubcategoriesIds($category) {
$array = [$category->id];
if(count($category->subcategories) == 0) {
return $array;
}
else {
foreach ($category->subcategories as $subcategory) {
array_push($array, $subcategory->id);
if(count($subcategory->subcategories)){
$array = array_merge($array, $this->getChildren($subcategory->subcategories, $array));
}
}
return $array;
}
}
public function getChildren($subcategories, $array) {
foreach ($subcategories as $subcategory) {
array_push($array, $subcategory->id);
if(count($subcategory->subcategories)){
return $array = array_merge($array, $this->getChildren($subcategory->subcategories, $array));
}
return $array;
}
}
Upvotes: 2
Views: 2532
Reputation: 3
I have infinite category db like "id", "name", "parent_id". I don't have any product which is relation with my parent categories so i have to get deep categories.
I write a relation and a recursive function:
public function children(){
return $this->hasMany(self::class, 'parent_id');
}
public function getChildrenIds(&$arr){
$children = $this->children;
foreach ($children as $child) {
if (count($child->children) > 0)
$child->getChildrenIds($arr);
else
array_push($arr, $child->id);
}
}
and then in controller i can get my sub category products like:
$category = Categories::where('slug', $slug)->first();
$category_sub_cat_ids = [];
$category->getChildrenIds($category_sub_cat_ids);
$products = Products::whereIn('category_id', $category_sub_cat_ids)->paginate(30);
(I know the model names are inappropriate. this project's owner has a junior "developer" and they asked me to help.)
Upvotes: 0
Reputation: 31
I found problem in my recursive method. I shouldn't have passed $array
to the recursive method getChildrenIds()
.
Here is my solution (with some refactoring):
public function getCategoriesIds($category)
{
if(!empty($category))
{
$array = array($category->id);
if(count($category->subcategories) == 0) return $array;
else return array_merge($array, $this->getChildrenIds($category->subcategories));
}
else return null;
}
public function getChildrenIds($subcategories)
{
$array = array();
foreach ($subcategories as $subcategory)
{
array_push($array, $subcategory->id);
if(count($subcategory->subcategories))
$array = array_merge($array, $this->getChildrenIds($subcategory->subcategories));
}
return $array;
}
and now $this->getCategoriesIds(Category::with('subcategories')->where('id', 1)->first());
returns:
array:10 [
0 => 1
1 => 7
2 => 12
3 => 13
4 => 9
]
Upvotes: 1
Reputation: 8927
Your question: How can I improve the method to return IDs without duplicates? Or maybe there is better way to revive those posts?
$subcategoriesIds = array:10 [
0 => 1
1 => 7
2 => 1
3 => 7
4 => 12
5 => 1
6 => 7
7 => 12
8 => 13
9 => 9
]
My answer: collect($subcategoriesIds)->unique()->all()
Check out Laravel Collection Unique Docs
Upvotes: 0