I have 2 tables, product and promotion. I do not know how I can display the price of both product and promotion(price after discount) based on product_id in blade. In blade i can only display price for promotion using {{$promotion->price}}
Product Table
id - name - price
Promotion Table
id product_id - price - discount
Controller:
$latestProduct = Promotion::orderBy('created_at', 'desc')
->with('product')
->take(20)
->get();
Model:
Product Model
public function promotion()
{
return $this->hasMany('App\Model\Promotion');
}
Promotion Model
public function product()
{
return $this->belongsTo('App\Model\Product');
}
in blade file:
Edit:
#foreach($latestProduct as $product)
{{$product->price}}
{{$product->promotion->price}}
#endforeach
would work.
I think it'll be better to make like this:
$latestProducts = Product::orderBy('created_at', 'desc')
->with('promotion')
->take(20)
->get();
And, as mentioned Ali Özen, in your blade file you'll be able to iterate through your products and get product's promotion price with:
$product->promotion->price
Related
Searching from pivot table using laravel.
Here is my table structure:
Product
id
name
Categories
id
name
product_category (Pivot table)
id
category_id
product_id
//products can have multiple categories
Product model:
public function categories(){
return $this->belongsToMany(Category::class, 'product_category');
}
What is the best way to search all products by category id?
Currently I am doing this way, and it seems not an efficient way:
//Controller
$categories = product_category::where('category_id',1)->get();
Now I have to loop through categories and then get Products and pass it to views? Any idea how to do this in an efficient way?
For this you could use the whereHas() method:
$categoryId = 1;
$products = Product::whereHas('categories', function ($query) use($categoryId) {
$query->where('id', $categoryId);
})->get();
The above will return all products that are in the Category where the id is equal to $categoryId.
You can eager load products for a given category. Try:
$category = Category::with('products')->where('category_id',1)->find(1);
When you do this, only 2 database queries will be executed: one for loading the category, and one for loading related products.
Then in your Blade view you can do:
#foreach($category->products as $product
{{ $product->name }}
#endforeach
You can use this inside your method in controller..this only works when $request->$query(search) have value .then here we use wereHas for get the relationship of model and with->() using for get pivot table values
->when($request->query('search'), function ($query)use($request) {
$q= $request->query('search');
return $query->whereHas('relation name', function (Builder $query) use ($q) {
$query->with('pivot table name.column name')
->where('pivot table name.column name', 'like', "%{$q}%")
});})
I have the following:
//users table
id
name
email
remeber_token
role_id
//roles table
id
name
//products table
id
name
//product_prices
role_id
product_id
price
The price of the product will vary depending on the user role, how to define the correct relationship so in blade I can do something like:
$product->price
and that will return the correct price depending on the user and the product?
I believe that when you say the user role, you refer to the role of the authenticated user.
The easiest approach is to define a HasOne relationship on the product model:
class Product
{
public function price()
{
return $this->hasOne(Price::class)->where('role_id', auth()->user()->role_id)
}
}
So from the view, you can simply say:
// Lets use optional() because there may not be any price for that product and user.
optional($product->price)->price
If there are many products involved, then using sub queries would make more sense.
class ProductsController extends Controller
{
public function index()
{
$products = Product::addSelect(['right_price' => Price::select('price')
->whereColumn('product_id', 'products.id')
->where('role_id', auth()->user()->role_id)
->limit(1)
])->get()
return view('products.index', compact('products'));
}
}
And then in the view:
#foreach($products as $product)
<p>{{$product->right_price}}</p>
#endforeach
For more info, pls check out this article.
I have problem with relationship query. I have in my show.blade.php (category):
#foreach( $attributes as $attribute)
{{ $attribute->title }}
#endforeach
and in CategoryController function show:
$attributes = Attribute::where('visible',1)
->orderBy('order', 'asc')
->with('products')
->get();
I need to display product attributes for specific categories. Solution displaying all attributes from the database. I have 3 categories, each of these categories has products that have their own attributes. Not all attributes are in all categories.
My model relationship is: Category 1:n Product N : (pivot product_attribute) : N Attribute
Category id is passed from the view. I also have access to a specific category. But how to display the attributes of products in this category. Do you have any idea?
Assuming you have relationships defined properly in Attribute and Product models, You can use below query to get Attributes of specific category
$attributes = Attribute::with(['product.category'])->whereHas('product.category', function($q) use ($categoryId) {
$q->where('id', $categoryId);
})->get();
Here product is relation name defined in Attribute model and category is relation name defined in Product model. id is primary key field in category table.
Searching from pivot table using laravel.
Here is my table structure:
Product
id
name
Categories
id
name
product_category (Pivot table)
id
category_id
product_id
//products can have multiple categories
Product model:
public function categories(){
return $this->belongsToMany(Category::class, 'product_category');
}
What is the best way to search all products by category id?
Currently I am doing this way, and it seems not an efficient way:
//Controller
$categories = product_category::where('category_id',1)->get();
Now I have to loop through categories and then get Products and pass it to views? Any idea how to do this in an efficient way?
For this you could use the whereHas() method:
$categoryId = 1;
$products = Product::whereHas('categories', function ($query) use($categoryId) {
$query->where('id', $categoryId);
})->get();
The above will return all products that are in the Category where the id is equal to $categoryId.
You can eager load products for a given category. Try:
$category = Category::with('products')->where('category_id',1)->find(1);
When you do this, only 2 database queries will be executed: one for loading the category, and one for loading related products.
Then in your Blade view you can do:
#foreach($category->products as $product
{{ $product->name }}
#endforeach
You can use this inside your method in controller..this only works when $request->$query(search) have value .then here we use wereHas for get the relationship of model and with->() using for get pivot table values
->when($request->query('search'), function ($query)use($request) {
$q= $request->query('search');
return $query->whereHas('relation name', function (Builder $query) use ($q) {
$query->with('pivot table name.column name')
->where('pivot table name.column name', 'like', "%{$q}%")
});})
I am trying to order my products by the average of the ratings given in reviews of the product.
here are my tables:
Product : id, productname, price, approved
reviews: id, review, rating, product_id_fk
How would I change this to return on the highest average rating to the lowest?
$products = Product::where('approved', '=', 1)->orderBy('productname');
return view('pages.search')->with('products', $products)
Create a new table called product_review_ratings containing
product_id
avg_rating
Create a scheduled command that loops through all products and sum avrage rating. Save to product_review_ratings table.
In the ProductReviewRating Model add a relationship to Product
class ProductReviewRating extends Model
{
public function product() {
return $this->belongsTo(Product::class);
}
}
Now you can sort by rating.`
$collection = ProductReviewRating::orderBy('avg_rating', 'desc')->get();
And in view
#foreach ($collection as $rating)
{$rating->product->name} - {$rating->avg_rating} <br>
#endforeach
Example of scheduled command (assuming that you have reviews relation in product model)
foreach (Product::all() as $product) {
ProductReviewRating::updateOrCreate(['product_id' => $product->id],[
'product_id' => $product->id,
'avg_rating' => $product->reviews->pluck('rating')->avg()
]);
}
The easy way (no scheduled command needed) is to compute the avg() over the reviews and join the result with products:
$products = DB::table('reviews')
->join('products', 'reviews.product_id', '=', 'products.id')
->select(DB::raw('avg(rating) as average, products.*'))
->groupBy('product_id')
->orderBy('average', 'desc')
->get();
make this a method in your products model, or better yet, products Repository.
The accepted answers is quite outdated now.
There is a builtin withAvg eloquent function that can do the required job.
These methods will place a {relation}_{function}_{column} attribute on your resulting models
So to get the average of the ratings from reviews table:
Product::where('approved', '=', 1)->withAvg('reviews', 'rating')->orderBy('reviews_avg_rating');
Now you can use the product rating as easy as : $product->reviews_avg_rating
The resulted sql will be using subquery to get it on every product:
select `products`.*, (select avg(`reviews`.`rating`) from `reviews` where `products`.`id` = `reviews`.`product_id`) as `reviews_avg_rating` from `products`