简体   繁体   English

Laravel 从父类别及其所有子类别中获取所有产品

[英]Laravel get all products from parent category and all it's sub-categories

I'm trying to retrieve products from a category and all it's sub-categories.我正在尝试从一个类别及其所有子类别中检索产品。

Here's my categories table :这是我的categories表:

| id    | parent_id     | name          |
|----   |-----------    |-------------  |
| 1     | NULL          | Electronics   |
| 2     | 1             | Computers     |
| 3     | 2             | Accessories   |
| 4     | 3             | Keyboards     |

and here's my products table :这是我的产品表:

| id    | category_id   | name          |
|----   |-------------  |-----------    |
| 1     | 2             | Product 1     |
| 2     | 3             | Product 2     |
| 3     | 4             | Product 3     |

Let's say i'm in Computers category page, and i want to display products from this table and all it's childrens.假设我在Computers类别页面中,我想显示此表中的产品以及所有儿童产品。

so it should get products first from Computers and Accessories and also Keyboards .所以它应该首先从ComputersAccessories以及Keyboards获取产品。

Here's my Category Model :这是我的类别模型:

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

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

public function products() {
    return $this->hasManyThrough(Product::class, Category::class, 'parent_id', 'category_id', 'id');
}

Product Model :产品型号 :

public function categories() {
    return $this->belongsTo(Category::class, 'category_id');
}

Query :查询

Category::with(['products', 'childs.products'])->where('id', $category->id)->get();

Return :返回

{
    "id":11,
    "parent_id":4,
    "name":"Computers",
    "products":[
        {
            "id":2,
            "category_id":12,
            "title":"Product 1",
            "laravel_through_key":11
        }
    ],
    "childs":[
        {
            "id":12,
            "parent_id":11,
            "name":"Accessories",
            "products":[
                {
                    "id":1,
                    "category_id":13,
                    "user_id":1,
                    "title":"Product 2",
                    "laravel_through_key":12
                }
            ]
        }
    ]
}

Above, it's escaping the last child category Keyboards .上面,它正在转义最后一个子类别Keyboards

I have tried to use hasManyThrough relationship but i only got products from Computers and Accessories but didn't reach to Keyboards .我曾尝试使用hasManyThrough关系,但我只从Computers and Accessories获得产品,但没有接触到Keyboards

So if i'm on a category i want to get all products from this category tree.所以如果我在一个类别中,我想从这个类别树中获取所有产品。 even if a sub-category has sub-categories.即使一个子类别有子类别。

How can i achieve this?我怎样才能做到这一点?

Thanks.谢谢。

Update :更新

i applied the snippet in Foued MOUSSI 's answer :我在Foued MOUSSI的回答中应用了片段:

public function childrenRecursive() {
    return $this->childs()->with('childrenRecursive');
}

$categoryIds = Category::with('childrenRecursive')->where('id', $category->id)->get();

Return :返回

[
    {
        "id":2,
        "parent_id":1,
        "name":"Computers",
        "children_recursive":[
            {
                "id":3,
                "parent_id":2,
                "name":"Accessories",
                "children_recursive":[
                    {
                        "id":4,
                        "parent_id":3,
                        "name":"Keyboards",
                        "children_recursive":[]
                    }
                ]
            }
        ]
    }
]

and i got the array of category and all it's sub-categories, but to get products from all these categories i need to extract the IDs from the the list with childrenRecursive to call something like :我得到了类别数组及其所有子类别,但是要从所有这些类别中获取产品,我需要使用childrenRecursive从列表中提取 ID 来调用类似的东西:

Product::whereIn('category_id', $categoryIds)->get();

Any idea?任何的想法?

You may fix it by :您可以通过以下方式修复它:

make a recursive relation: (Please Refer to Alex Harris answer here )建立递归关系:(请在此处参考 Alex Harris 的回答)

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

$data = Category::with(['products', 'childrenRecursive', 'childrenRecursive.products'])->where('id', 2)->get()->toArray();

#Edit: Extract list of products #Edit:提取产品列表

Define Flatten laravel recursive relationship collection (tree collections) function inside your controller在控制器中定义Flatten laravel 递归关系集合(树集合)函数

public function flatten($array)
{
        $flatArray = [];

        if (!is_array($array)) {
            $array = (array)$array;
        }

        foreach($array as $key => $value) {
            if (is_array($value) || is_object($value)) {
                $flatArray = array_merge($flatArray, $this->flatten($value));
            } else {
                $flatArray[0][$key] = $value;
            }
        }

        return $flatArray;
}

Then in order to only have products item然后为了只有产品项目

$data = Category::with(['products', 'childrenRecursive', 'childrenRecursive.products'])->where('id', 2)->get()->toArray();

$flatten = $this->flatten($data);

foreach ($flatten as $key => $fl) {
    // eliminate categories from $flatten array
    if (!array_key_exists('category_id', $fl)) {
        unset($flatten[$key]);
    }
}

$product = array_values($flatten);

One option would be to use something like laravel-adjacency-list .一种选择是使用类似laravel-adjacency-list 的东西。 This would allow you to use CTE to recursively load the relationships.这将允许您使用CTE递归加载关系。

Below are the steps to get you set up (at the time of writing)以下是让您进行设置的步骤(在撰写本文时)

  1. Run composer require staudenmeir/laravel-adjacency-list:"^1.0"运行composer require staudenmeir/laravel-adjacency-list:"^1.0"
  2. Add the HasRecursiveRelationships trait to your Category model:HasRecursiveRelationships特性添加到您的Category模型:

     use Staudenmeir\\LaravelAdjacencyList\\Eloquent\\HasRecursiveRelationships; class Category extends Model { use HasRecursiveRelationships; ... }
  3. Change your query to be:将您的查询更改为:

     Category::with('descendants.products')->where('id', $id)->first(); //$id being the id of the parent category you want to get.

If you're wanting to just get the products that are in/under a category you could do something like:如果您只想获取属于/属于某个类别的产品,您可以执行以下操作:

Product::whereHas('category', function ($query) use ($category) {
    $query->whereIn('categories.id', $category->descendantsAndSelf()->select('id')->getQuery());
})->get();

For more information on how to use laravel-adjacency-list please refer to the documentation .有关如何使用laravel-adjacency-list更多信息,请参阅文档

$categories  = Category::whereParentId(null)->with('children.children.children')->get();

并且在视图中您可以使用 foreach 循环显示项目

Since I'm using MySQL 5, I used this way to resolve this issue in my project if anyone is interested about it.由于我使用的是 MySQL 5,如果有人对此感兴趣,我会使用这种方式来解决我的项目中的这个问题。 It makes more sense for me.这对我来说更有意义。

If you're using MySQL 8, you can take this question as a reference to edit this code.如果您使用的是 MySQL 8,则可以将此问题作为参考来编辑此代码。 How to create a MySQL hierarchical recursive query? 如何创建 MySQL 分层递归查询?

public function scopeWhereCategoryId($query, $category_id){
    return $query->where(function($query) use ($category_id){
        $query->where('category_id', trim($category_id));
        $query->orWhereRaw("category_id in (
            select  id
            from    (select * from pm_categories
                    order by category_id, id) categories_sorted,
                    (select @pv := '" . trim($category_id) . "') initialisation
            where   find_in_set(category_id, @pv)
            and     length(@pv := concat(@pv, ',', id))
        )");
    });
}

If you use ORM Eloquent Relationship如果你使用 ORM Eloquent 关系

public function categoriesProduct(ProductCategory $category)
{
     $categories = ProductCategory::where('parent_id', $category->id)
                                  ->orWhere('id', $category->id)
                                  ->latest()
                                  ->get();
     return view('categoryProduct', compact('categories', 'category'));
}

I think the better way is article Eloquent: Recursive hasMany Relationship with Unlimited Subcategories我认为更好的方法是文章Eloquent: Recursive hasMany Relationship with Unlimited Subcategories

Just add products relationship to the Category Model只需将产品关系添加到类别模型

Class Category extends Model

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

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

 public function products()
 {
     return $this->hasMany(Product::class);
 }

Query:询问:

 $Categories = Category::whereNull('parent_id')
->with('childrenCategory','products')
->get();

Returns:返回:

[
{
    "id": 1,
    "parent_id": null,
    "name": "Category 1",
    "description": "Category 1",
    "created_at": "2021-12-10T11:43:48.000000Z",
    "updated_at": "2021-12-10T11:43:48.000000Z",
    "products": [
    {
        "id": 1,
        "category_id": 1,

        "name": "productNobis provident.",
        "description": "Ad quia ullam voluptatem modi ab dolorem non.",
        "qty": 1,
        "created_at": "2021-12-10T11:43:48.000000Z",
        "updated_at": "2021-12-10T11:43:48.000000Z"
    },
    ],
    "children_categories": [
    
    ]
},
{
    "id": 2,
    "parent_id": null,
    "name": "Category 2",
    "description": "Laborum aut quibusdam earum commodi.",
    "created_at": "2021-12-10T11:43:48.000000Z",
    "updated_at": "2021-12-10T11:43:48.000000Z",
    "products": [
    {
        "id": 5,
        "category_id": 2,
        "name": "productVoluptas laborum adipisci.",
        "description": "Autem ut et voluptate ab sit voluptatem quia.",
        "qty": 1,
        "created_at": "2021-12-10T11:43:48.000000Z",
        "updated_at": "2021-12-10T11:43:48.000000Z"
    },
    ],
    "children_categories": [
    {
        "id": 4,
        "parent_id": 2,
        "name": "Category 4",
        "description": "Eos nemo libero non eius voluptates.",
        "created_at": "2021-12-10T11:43:48.000000Z",
        "updated_at": "2021-12-10T11:43:48.000000Z",
        "products": [
        {
            "id": 9,
            "category_id": 4,
            "name": "productSunt deleniti minus.",
            "description": "Vitae numquam autem consequuntur consequuntur.",
            "qty": 1,
            "created_at": "2021-12-10T11:43:48.000000Z",
            "updated_at": "2021-12-10T11:43:48.000000Z"
        },
        ],
        "categories": [
        {
            "id": 6,
            "parent_id": 4,
            "name": "Rerum qui earum.",
            "description": "Nihil ipsum officiis vitae et error accusamus ipsam.",
    
            "created_at": "2021-12-10T11:43:48.000000Z",
            "updated_at": "2021-12-10T11:43:48.000000Z",
            "products": [
            {
                "id": 13,
                "category_id": 6,
        
                "name": "productConsequatur quisquam molestiae.",
                "description": "Autem sed mollitia eos eveniet iste ipsa aut aliquam.",
                "qty": 1,
                "created_at": "2021-12-10T11:43:48.000000Z",
                "updated_at": "2021-12-10T11:43:48.000000Z"
            },
        ]
        }
        ]
    }
    ]
}
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM