Laravel - Many-to-many relation, product count by product feature - php

Trying to get the count of products by its features(many-to-many)
For instance,
Product::with([’features’])->where(category_id, $category_id)->get();
Product A->feature1->id
/feature2->id
/feature3->id
Product B->feature3->id
/feature4->id
/feature6->id
.....
how could i get product count from each feature (after filtered by product category)
I am not good at explain in wording, tried my best.
Final result
feature 1 -> 19 products
feature 2 -> 5 products
...

Try this:
Select product_id from products where category_id = "'.$category_id.'" group by feature_id;

You should Define relation within your Product and Feature Model
class Product extends Model {
public function features(){
return $this->belongsTo(Feature::class);
}
}
class Feature extends Model {
public function products(){
return $this->hasMany(Product::class);
}
}
I presume each Product has an attribute feature_id which hold the id of the Feature to which it's belongsTo.
$products = Product::with([’features’])->where(category_id, $category_id)->get(); // This query will return list of product
foreach($products as $product){
// You can access $feature of product like this
$feature = $product->feature;
}
Because I have already define the reverse relation between the both Model I can access Product from Feature as well.
$feature->products(); // This will return a collection of Product and I can perform any sort of query on that too
// Like count number of Products
$feature->products()->count();
$feature->products()->first(); // get the first product
$feature->products()->last(); // get the last product
And so on and so fourth

Assuming you have products relationship on the Feature model you can try this!
$features = Feature::withCount(['products' => function($query){
$query->where('category_id', $category_id);
}])->get();
You will have a products_count with each record of the collection.

This will do the trick
with(['products' => function($q) use($category_id){
$q->where('category_id',18);
}])
->find($feature_ids)
->groupBy('feature_type_id');

Related

How to get verified reviews of a product in laravel

I've following data structure,
Product
id
name
description
Product Review
id
user_id
product_id
review
rating
status (true/false)
Relationship is one to many i.e. one product has many reviews.
What I want is to load all the products with verified reviews(i.e. reviews with status true)
I've tried following,
$products = Product::with('reviews')->get();
but when I iterate over $products to access reviews like $product->reviews, all the reviews(even status false reviews) are displayed.
Any kind of suggestion is appreciated.
You can add a closure to the with function to add extra filtering.
Product::with([
'reviews' => function ($query) { $query->where('status', true); }
])->get();
Another option is to add a filtered relation function to your product model.
public function verifyedReviews() {
return $this->reviews()->where('status', true);
}
And now call this function in your with clause.
Product::with('verifyedReviews')->get();
try this one by using clousre
$products = Product::with(['reviews' => fuction($query) {
return $query->where('status',true);
}])->get();
you can use WhereHas()
Your code would be:
$products = Product::whereHas('reviews',function($query){
return $query->where('status',true);
})->get();

Call to undefined relationship on model laravel using scope

I'm trying to get 5 posts for each category so I did a little search and ends up here Getting n Posts per category
But I'm getting a weird Call to undefined relationship on model when using with scope but it all works fine If I don't use a scope. Here is the Category Model
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
scopeNPerGroup
public function scopeNPerGroup($query, $group, $n = 10)
{
// queried table
$table = ($this->getTable());
// initialize MySQL variables inline
$query->from( \DB::raw("(SELECT #rank:=0, #group:=0) as vars, {$table}") );
// if no columns already selected, let's select *
if ( ! $query->getQuery()->columns)
{
$query->select("{$table}.*");
}
// make sure column aliases are unique
$groupAlias = 'group_'.md5(time());
$rankAlias = 'rank_'.md5(time());
// apply mysql variables
$query->addSelect(\DB::raw(
"#rank := IF(#group = {$group}, #rank+1, 1) as {$rankAlias}, #group := {$group} as {$groupAlias}"
));
// make sure first order clause is the group order
$query->getQuery()->orders = (array) $query->getQuery()->orders;
array_unshift($query->getQuery()->orders, ['column' => $group, 'direction' => 'asc']);
// prepare subquery
$subQuery = $query->toSql();
// prepare new main base Query\Builder
$newBase = $this->newQuery()
->from(\DB::raw("({$subQuery}) as {$table}"))
->mergeBindings($query->getQuery())
->where($rankAlias, '<=', $n)
->getQuery();
// replace underlying builder to get rid of previous clauses
$query->setQuery($newBase);
}
Calling Npergroup with relation
public function latestposts()
{
return $this->posts()->latest()->nPerGroup('category_id', 5);
}
Post Model Relationship
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
In my category controller I'm calling latestposts through
$categories = Category::with('latestposts')->get();
But I'm getting the error: Call to undefined relationship on model
What I want is:
Get the N number of posts per each category but I'm completely lost at this point. Any help would be appreciated
Reference:
Tweaking Eloquent relations – how to get N related models per parent ?
I am giving this answer based on your purpose that you want 5 posts per category.
So you have Category Model and Post Model.
And in Category Model you have relation with Post model like this
//Relationship with posts
public function posts(){
return $this->hasMany('App\Post');
}
And in Post Model you have relation with Category model like this
//Post belongs to Category
public function category(){
return $this->belongsTo('App\Category');
}
I show your question you have done SQL queries.
Instead of that, You can use two approaches
1) Give condition while eagar loading
$categories = Category::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc')->take(5);
}])->get();
Note: This approach will only work when you take only one result of parent child using first() method.
To get n number of posts per category Use this.
First, you can retrieve all categories with
$categories = Category::all();
Then you can use foreach loop and in all $category you have to give assign new attribute in it like here latestposts,
foreach ($categories as $category)
{
$category->latestposts = $category->posts()->orderBy('created_at','desc')->take(5)->get();
}
After this foreach loop you will get latest 5 posts in all categories.
Try this in your code and comment your queries and reviews.

Laravel 5.4 : count the products in each category and sort them by Eloquent query

I have two Models one is Product and the other is ProductCategory
and I have relations between both
Product Model
public function productCategory() {
return $this->belongsTo( ProductCategory::class, 'product_category_id' );
}
Product Category Model
public function categoryProduct() {
return $this->hasMany( Product::class, 'product_category_id' );
}
now each category has some product like (cat-1 has 3 products, cat-2 has 7 products, cat-3 has 5 products).
I need an Eloquent query which will get 4 categories sorted by the count of products in each category.
For Ex.
cat-2 has 7 products
cat-3 has 5 products
cat-1 has 3 products
tahnks
Use withCount() and then orderBy() to make it with single query.
ProductCategory::with('categoryProduct')->withCount('categoryProduct')->orderBy('category_product_count','desc')->get();
To get just the count
ProductCategory::withCount('categoryProduct')->orderBy('category_product_count','desc')->get();
Then you can try it as:
$rows= ProductCategory::withCount('categoryProduct')->get();
and you can access this by:
foreach ($rows as $row) {
echo $row->categoryProduct_count;
}
this is pure eloquent
suppose you get the $categories as a collection then you can define a custom sort by function
$categories = ProductCategory::all()->with('categoryProduct'); //which will fetch you all categories with products
$sorted = $categories->sortBy(function ($category, $key) {
return count($category);
});
doc link

LARAVEL - Show products to related category

I'm trying to show products related to the category. In my menu I have a list of categories if I click this category i want to see related products to this category. I'm just learning laravel can somebody help me out..
DATABASE:
-categories: ID, NAME
-products: has Category_id
View
Route::get('/category' , [
'uses' => 'productController#getCategory',
'as' => 'category.single'
]);
Controller
public function getCategory($category) {
$singleCategory = Category::find($category);
return view('pages.category', ['category' => $singleCategory]);
}
How do I go from here?
in Category.php Model add a relation
public function products()
{
return $this->hasMany('App\Product');
}
then you can call
$singleCategory->products
and you'll get you products by category_id
As per the following lines:
$singleCategory = Category::find($category);
return view('pages.category', ['category' => $singleCategory]);
category list is available on pages.category page under $category. Its a Collection object, you can access its object by using foreach() loop.
How do I go from here?
I don't know.
But for your problem, if you want to get the products of a Category just do:
$singleCategory = Category::find($category);
$products = $singleCategory->products;
(I assume you added a products method in your Category model, if not, read this: https://laravel.com/docs/5.4/eloquent-relationships#one-to-many).
Then you can display your products by looping on your products:
foreach($products as $product) {
echo $product->name;
}

Laravel Eloquent - Using array in find() method

I have three tables - users, products and orders
There is a relation between users and orders (users has many orders).
orders table contains product_id and user_id column.
Now I want to access the product details of orders for a user.
What I am trying:
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::find($orders);
return view('shop.myorders', compact('products'));
}
But this is not working. Can anyone help me? What other way can be better to achieve this?
As mentioned, find() will always return 1 item, and expects a string/int for the parameter. You want to use where and get instead. With an array of ids, you can use whereIn.
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::whereIn('id', $orders)->get();
return view('shop.myorders', compact('products'));
}
I assume you have orders() relation defined in the Product model:
public function orders()
{
return $this->hasMany(Order::class)
}
Then you'll be able to load products from all user's orders:
$products = Product::whereHas('orders', function($q) {
$q->where('user_id', auth()->id())
})->get();

Categories