Laravel中获取全层级分类商品及分页展示问题
我有一个多层级分类结构:Parent - child one - child two - child two (one)
当访问Parent页面时,需要获取该分类及其所有子层级(Parent、child one、child two、child two(one))的商品,而不只是父分类下的商品。
当前遇到两个问题:
- 怎么才能获取上述所有层级分类下的商品?
- 如何在Parent页面实现这些商品的分页展示?
现有代码(仅能展示父分类下的商品):
public function totalcategoriessubs($catslug) { $categories = Category::where('slug','=',$catslug)->with('childs')->paginate(12); $products = Product::whereHas('category', function($q) use($catslug){ $q->where('slug',$catslug); })->paginate(12); return view('front.categoriessubs', compact('products', 'categories')); }
我更新后的代码(能拿到Parent、child one、child two层级的商品,但拿不到child two(one)的商品):
public function totalcategoriessubs($catslug) { //changed $category = Category::where('slug','=',$catslug)->with('childs')->first(); //testing this $products = Product::whereHas('category', function($q) use ($catslug,$category) { $q->where(function($q) use ($catslug,$category) { $q->where('slug',$catslug)->orWhere('category_id',$category->id); }); })->orderBy('created_at', 'DESC')->paginate(10); //end testing return view('front.categoriessubs', compact('products', 'category')); }
1. 先搞定所有层级的分类ID
你现在的问题核心是:当前代码只覆盖了父分类本身和它的直接子分类(比如child one、child two),但像child two(one)这种更深层的子分类,它的category_id是child two的ID,不是Parent的ID,所以没被查询到。
我们需要先把Parent下面所有层级的分类ID都收集起来,包括父分类自己。
首先,确保你的Category模型里已经定义了递归的子分类关系(如果还没加的话):
// app/Models/Category.php public function childs() { // 关联子分类,并且递归加载子分类的子分类 return $this->hasMany(Category::class, 'category_id', 'id')->with('childs'); }
然后,在控制器里加一个私有方法,用来递归收集所有分类ID:
// 控制器内的私有方法 private function getAllCategoryIds(Category $category) { // 先把当前分类ID加进去 $ids = [$category->id]; // 遍历所有子分类,递归收集它们的ID foreach ($category->childs as $child) { $ids = array_merge($ids, $this->getAllCategoryIds($child)); } return $ids; }
2. 修改商品查询逻辑
现在用上面的方法拿到所有相关分类的ID,然后用whereIn来查询属于这些分类的商品:
public function totalcategoriessubs($catslug) { // 获取父分类,同时递归加载所有子分类 $category = Category::where('slug','=',$catslug)->with('childs')->first(); // 拿到父分类+所有子分类的ID数组 $categoryIds = $this->getAllCategoryIds($category); // 查询所有属于这些分类的商品,同时做分页 $products = Product::whereHas('category', function($q) use ($categoryIds) { $q->whereIn('id', $categoryIds); })->orderBy('created_at', 'DESC')->paginate(10); return view('front.categoriessubs', compact('products', 'category')); }
3. 分页展示的实现
其实你已经用了paginate(10),这一步Laravel已经帮你处理了分页逻辑。你只需要在前端视图里添加分页链接就行,直接调用分页对象的links()方法:
{{-- 在你的 front/categoriessubs.blade.php 视图文件中 --}} <div class="pagination-container"> {{ $products->links() }} </div>
这个方法会自动生成带页码的分页导航,点击就能切换不同页的商品。
可选优化(针对大量分类的情况)
如果你的分类层级特别深、数量特别多,递归遍历可能会有点性能问题。这时候可以考虑用嵌套集合(Nested Set)来优化,比如用kalnoy/nestedset这个Laravel包,它能更高效地查询所有子分类,不用递归遍历。不过如果你的分类规模不大,上面的递归方法完全够用。
内容的提问来源于stack exchange,提问作者mafortis

