Laravel - hasManyThrough with Limit/Take - laravel

I have Products, SubCategories, Categories relationship..
in Category model where I defined hasManyThrough relationship :
public function products()
{
return $this->hasManyThrough('Products','SubCategory');
}
How do I display only 4 products on each category?
$products = Category::with('products')->get()
I already add take(2) or limit(2) on hasManyThrough relationship, but the query limit overall products, not by subcategory. Here is the query log :
select products.*, subcategories.category_id from products inner join subcategories on subcategories.id = products.subcategory_id where subcategories.category_id in (?, ?, ?, ?, ?, ?) limit 4

I dont't think you can set hasManyTrough relation limits, but you can separate your relations and set own limits for them:
Category has subcategories:
public function subcategories()
{
return $this->hasMany('Subcategory')->limit(2);
}
Subcategories has products:
public function products()
{
return $this->hasMany('Product')->limit(4);
}
Then you can call:
Category::with('subcategories.products')->get();

Related

Laravel: Property [user] does not exist on this collection instance

In Laravel, I've Orders model where each order belongs to only one user,
I want to return only user names and orders ids when I fetch the orders, So in my OrdersController I've this function
public function getAllOrders()
{
$orders = Order::all();
return new OrderResource($orders);
}
and in my OrderResource I've
public function toArray($request)
{
return [
'user' => $this->user,
'id' => $this->id,
];
}
I'm getting an error saying Property [user] does not exist on this collection instance.
I think the reason is coming from the fact that $orders is a collection and I should loop through it and get for each order get the user associated with it, but I've no idea how to do that.
Note: I'm using oneToMany and belongsTo on Users and Orders Model. so orders table doesn't have a user column, I want to get the user from the relationship.
When using a collection use like this;
public function getAllOrders()
{
return OrderResource::collection(Order::all());
}
When using a model use like this;
public function getOrder($id)
{
return new OrderResource(Order::find($id));
}
More information in the documentation: https://laravel.com/docs/7.x/eloquent-resources#concept-overview
Note: To avoid N+1 queries, you should get your orders like this; Order::with('user')->get(); instead of Order::all()
The difference is that Order::with('user')->get(); will perform two queries.
select * from orders
select * from users where id in (?, ?, ?, ?, ...)
Whereas Order::all() will perform N+1 queries (N = number of orders)
select * from orders
select * from users where id = ?
select * from users where id = ?
select * from users where id = ?
... and so on

How to write nested single query in Laravel Eloquent

These are the two queries I am firing. I want to make it simpler and faster. how should I do it?
$parentList = Category::select('parent_id')->groupBy('parent_id')->get()->toArray();
$categories = Category::whereNotIn('categories.id', $parentList)->get();
Table categories have following columns(
id,
parent_id,
name)
Make this relation in your Category Model as :-
public function parents()
{
return $this->hasOne('App\Category', 'parent_id', 'id');
}
Then simply use this relation as :-
$categories = Category::whereDoesntHave('parents')->get();

Laravel Fetching one to Many Relationship

Hello I am learning laravel and I am having an issue retrieving data from my relations.
In my database there are Product and Groups filled with dummy data.
I defined my relationship like this in product model:
public function Group()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And in my group vice versa with :
public function Product()
{
return $this->belongsTo('App\Product','product_id', 'id');
}
The way I am referencing to my products table is :
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
Now I have column product_id in my database under groups, and it is linked to if from products id it seems.
The groups table contains of its auto incremented id and product_id foreign key column.
While products table has auto incremented id and name column.
The issue is here :
How do I return the products that are not null or have value (of products id) in groups table.
I tried something like this in my filter controller:
public function getProductsWithGroup()
{
$Products = Product::with('groups')->get();
return $Products ;
}
But that is giving me call to undefined relations.
I am not sure how to access belongsTo or hasMany methods and whether I need an extra group_id column in my products table.
You named the relationship wrong. It should be groups & define in lowercase as
public function groups()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And use ->has() to check existence
public function getProductsWithGroup()
{
$Products = Product::has('groups')->get();
return $Products ;
}
->with() is used to eager load and ->has() is used to check existence & filter.
To get the products don't have any groups,
$Products = Product::doesntHave('groups')->get();
To see other ways to use ->has() check, https://laravel.com/docs/5.7/eloquent-relationships#querying-relationship-existence

Laravel Eloquent nested query

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
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();
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.

Laravel Get products from multiple taxonomies

I have 3 tables, products, taxonomies and product_taxonomy. The 3rd table is a pivot table that contains product_id and taxonomy_id, meaning that product and taxonomy are many to many relationship. Given a list of taxonomy ids, how can I get all the products that belong to these taxonomies? NOTE: I want to have the products result set being able to paginated or order by maybe it's price or something.
You need to create many-to-many relationship and that requires relationship methods like:
// Product Model
public function taxonomies()
{
return $this->belongsToMany('Taxonomy');
}
// Taxonomy Model
public function products()
{
return $this->belongsToMany('Product');
}
The query:
$listOfTaxonomyIds = [1,2,3];
$products = Product::whereHas('taxonomies', function($query) use ($listOfTaxonomyIds){
$query->whereIn('taxonomy_id', $listOfTaxonomyIds);
})->get();

Resources