问题
I was working with Laravel and got stuck in a situation. I have following models:
- Category
- Product
- CategoryProduct
CategoryProduct
holds the information about which product belongs to which category (a product may belong to multiple categories).
Now, when I want to load all products belonging to a particular category, I need to run query on Product
and CategoryProduct
which is where I'm stuck.
I gave it the following try but was unsuccessful:
$products = Product::where('status', '=', 'active')
->where('category_id', '=', $category_id)
->take($count)
->skip($skip)
->get();
Obviously, it will say that category_id
is not a column.
Here is my DB & Model structure:
categories table
id, name, etc.
products table
id, name, sku, etc.
category_products table
id, product_id, ( Foreign key to Product.id ) category_id, ( Foreign key to Category.id ) etc.
Product model
class Product extends Eloquent {
protected $table = 'products';
protected $hidden = array();
public static $rules = array('name' => 'required|min:3');
}
Category model
class Category extends Eloquent {
protected $table = 'categories';
public static $rules = array('name' => 'required|min:3');
}
CategoryProduct model
<?php
class CategoryProduct extends Eloquent {
protected $table = 'category_products';
public function product()
{
return $this->belongsTo('Product');
}
public function category()
{
return $this->belongsTo('Category');
}
}
Update
A new question on this
I'm trying to display products. If category is not passed (value is -1), then I will show all products, otherwise I will show products from the passed category.
Now, when I show all products, those products may already exist in a category. I want to display ticked checkbox for products that are already in a category. I'm doing something like this:
if($category_id==-1)
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
else{
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('category_id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
}
The table category_products have product_id, category_id as columns.
Now, the query:
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
will pick products only from products table. If I check each product for its existence in category_products, then there will be too many database queries for large number of products.
Any idea, how to achieve this. I hope I was able to clear my situation. Thanks
回答1:
The CategoryProduct
model should not be necessary unless you have additional fields besides product_id and category_id which point to other relationships.
What is necessary are the methods for setting up the relationship on the Category
and Product
models.
In Category
, add the relationship function...
public function products()
{
return $this->belongsToMany('Product', 'category_products');
}
In your Product
model, do the same for categories.
public function categories()
{
return $this->belongsToMany('Category', 'category_products');
}
Then you can query for your active products that belong to that category using your relationship method and whereHas()
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
回答2:
You don't need a model for a pivot table in Many-to-Many relationships. Look at this section of the Eloquent documentation for further explanation.
You still need to create a migration to set up the pivot table (or do it manually if you don't use migrations), but not a model. Instead, create a function for Category
to designate the relationship:
public function products()
{
return $this->belongsToMany('App\Product', 'category_products');
// - You might need to adjust the namespace of App\Product
// - category_products refers to the pivot table name
}
Likewise, Product
needs a similar public function.
Then you're able to do it the other way around, by finding the category and then listing all its related products:
$products = Category::find($category_id)
->products()
->where('status', 'active')
->take($count)
->skip($skip)
->get();
This question could also be relevant to yours.
来源:https://stackoverflow.com/questions/29751104/laravel-eloquent-nested-query