Laravel 4 Pagination Relations - laravel-4

I am trying to display a list of products with their corresponding categories using the following in my controller:
return View::make('products.index')
->with('categories', Categories::with('products')->orderBy('name', 'asc')->Paginate(15))
But the pagination doesn't work, it's displayed all products (500+) while I want to show only 15 on each page. Here are my models:
Categories:
public function products()
{
return $this->belongsToMany('Products');
}
Products:
public function categories()
{
return $this->belongsToMany('Categories');
}
How can I make the pagination work?

Try this:
$categories = Categories::with(array('products' => function($query)
{
$query->orderBy('name', 'asc');
}))->paginate(15);
return View::make('products.index', compact('categories'));
Hope it helps you. Here's the link for eager loading.

Related

Eloquent `with()` with filtering based on relation

I have this tables.
And this model relations, this relations works fine.
class Item extends Model
{
public function translations()
{
return $this->hasMany(ItemTranslations::class);
}
}
class ItemTranslation extends Model
{
public function language()
{
return $this->belongsTo(Language::class);
}
}
I need to return a list of items with the translations, but only the translations related to a specific language.
I can't have this query working, im getting all translations of each item, not only the one filtered with this query. The language related to the translation is not needed on the result.
$query = Item::query();
$query->with('translations')->when('language',function($query) use ($ISOlanguage) {
return $query->where('languages.ISO_code', '=', $ISOlanguage);
});
return $query->paginate();
Any idea who i can have this working? Thanks!
So what you want to do is constraining eager loading
Item::with(["translations" => function ($query) use ($ISOlanguage) {
$query->where('language.ISO_code', $ISOlanguage);
}])->get();
https://laravel.com/docs/5.8/eloquent-relationships#constraining-eager-loads
I finally have it working
Item::with(['translations' => function($query) use ($ISOlanguage) {
$query->whereHas('language', function($query) use ($ISOlanguage) {
$query->where('ISO_code', '=', $ISOlanguage);
});
}])->get();
Thanks #julian-s for your help!

how to add Limit() to pivot table

I have two tables products and categories and a pivot table category_product.
I have added relation in Product.php is below.
public function categories()
{
return $this->belongsToMany(Category::class);
}
I have added relation in Category.php is below.
public function products()
{
return $this->belongsToMany(Product::class);
}
Both are working fine.
But what I want is, I want to take all the categories which has products and the products should not return more than 6 records.
Meaning I have a two categories Music, Movies and both have more than 50+ products.
The code should be return only 6 products for both Music, Movies categories.
This is what I tried,
Category::with(['products' => function ($query){
return $query->select()->limit(6);
}, 'products.properties'])
->whereHas('products', function ($query){
return $query->select()->limit(6);
})->when($slug, function($query) use($slug){
$query->whereIn('slug', $slug);
})->get();
and this,
Category::addSelect([
'products' => Product::select('id')->whereColumn('products.id', 'categories.id')->orderBy('id')->limit(6)
])->when($slug, function($query) use($slug){
$query->whereIn('slug', $slug);
})->get()
Second try returns error,
"stripos() expects parameter 1 to be string, object given"
I am using laravel 6.
Thanks in advance, any answers and suggestion welcome.
Added My Answer Below
please use this. Also add all your logics to eloquent, not in controller.
public function categories()
{
return $this->belongsToMany(Category::class)->limit(6);
}
I found a solution for my question. Please have a check and please advice me if any better way to solve it.(mainly I want to reduce the number of queries)
The solution is
public function getProductsBasedOnCategory(array $slug){
$categories = Category::select()->when($slug, function($query) use($slug){
$query->whereIn('slug', $slug);
})->get();
$res = new Collection();
foreach ($categories as $category){
$category->products = $category->products()->limit(6)->get();
$res->push($category);
}
return $res;
}
This function executing queries how many categories I have.
If I have 10 categories, its executing 10 queries. Exclude $categories query
Is this answer is good or you have any better solution. I want to reduce the number of queries execution.
Please suggest.
you can use like below.
$cat = Category::with('products')->when($slug, function($query) use($slug){
$query->whereIn('slug', $slug);
})->get();
foreach ($cat as $key => $value) {
$value->products->first();
}

Laravel Eloquent get all categories of restaurants?

I'm trying to get all categories of restaurants.
My models:
Restaurant
public function categories()
{
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id');
}
Category
public function restaurants()
{
return $this->belongsToMany(Restaurant::class,'restaurant_categories_relation', 'category_id');
}
In my controller:
$restaurants = Restaurant::where('district_id', $request->district)->paginate(8);
$categories = $restaurants-> ????;
Please help me do this, thanks!
You could use has() like :
Category::has('restaurants')->get();
That will return the categories who are related with the restaurants.
Try also the use of whereHas like :
$users = Category::whereHas('restaurants', function($q){
$q->->where('district_id', $request->district)->paginate(8);
})->get();
Since you've already a Collection we can't query the categories so I suggest adding a function to scope that inside the Restaurant model like :
public static function getCategoriesOfRestaurants($restaurants)
$categories = [];
foreach($restaurants as $restaurant){
array_push( $categories, $restaurant->categories->pluck('id')->toArray());
}
return Category::WhereIn('id', array_unique($categories))->get();
}
Then just call it when you get the $restaurants collection :
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
$categories = Restaurant::getCategoriesOfRestaurants($restaurants);
Note: The use of with("categories") when getting the collection will query All the related categories in the first query so the foreach loop will not generate any extra query just looping through the already fetched data, and finally we will get the collection of categories in the return statement.
use with() method for eagerloading, that provides you get all categories in a single query
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
foreach($restaurants as $restaurant){
foreach($restaurant->categories as $category)
{{$category}}
}
}
if you want to use categories outside of the loop, then assign these categories to a variable
foreach($restaurants as $restaurant){
$categories = $restaurant->categories;
}
// do something with $categories
Your relation should be
Restruant.php
public function categories() {
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id','category_id');
}
then in you controller method just wirte
$restruants = Restruant::with('categories')->get();
It should return you collection of all restruants with all related categories.

How to get top 10 category list in laravel eloquent query

i have three table one is category table and another is product table and one more product_to_category table, and it has only product_id and category_id column.
Now i want to get top 10 categories with maximum number of product, with details of 10 products from each category.
What i wrote is
$result = ProductToCategory::groupBy('category_id')->with(['product',function($q){
$q->take(10);
}])->orderBy('category_id)->take(10);
But this is not working.How to write this query properly
Can anyone please help. ty
Model relations
For Product model
public function category(){
return $this->belongsTo(ProductToCategory::class);
}
For Category model
public function products()
{
return $this->hasMany(ProductToCategory::class);
}
For ProductToCategory model
public function product()
{
return $this->hasMany(Product::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
The most efficient way would be using a raw SQL query because you can't filter products by using eager loading constraint.
But if you want an Eloquent solution anyway, define the relationships:
In the Product model:
public function categories()
{
return $this->belongsToMany(Category::class, 'product_to_category');
}
And in the Category model:
public function products()
{
return $this->belongsToMany(Product::class, 'product_to_category');
}
Then you'll have two options, both have their pros and cons:
1. This code will execute just 2 queries but will use more memory. You could get top ten categories with their products:
$categories = Category::withCount('products')->latest('products_count')->take(10)->with('products')->get();
And then keep only first ten products:
$categories->transform(function($category) {
$topProducts = $category->products->take(10);
unset($category->products);
$category->products = $topProducts;
return $category;
});
2. This solution will create 12 queries but will save the memory:
$categories = Category::withCount('products')->latest('products_count')->take(10)->get();
$categories->transform(function($category) {
$category->products = Product::whereHas('categories', function($q) use($category) {
$q->where('id', $category->id);
})
->take(10)
->get();
return $category;
});
Here is the DB facade version:
$tenPopularTags = DB::table('product_to_category')
->join('category', 'product_to_category.category_id', '=', 'category.id')
->select(DB::raw('count(product_to_category.category_id) as repetition, question_tag.tag_id'))
->groupBy('product_to_category.category_id')
->orderBy('repetition', 'desc')->take(10)
->get();
However I like #Alexey Mezenin way of doing it. Because that is the cleaner way have customized it a bit:
$tenCategories = Category::withCount('products')->orderBy('questions_count', 'DESC')->take(10)->get();
Have used both in my project blog with post and categories relationship and it works!

Laravel 5: Count product by category where active product only

In Laravel 5.4, I have my relationship:
public function products()
{
return $this->hasMany(Product::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
And my query is:
$x = Category::with('products')->where('active', 1)->get();
It does show all category names correctly, but how to count only product 'active = 1'? I don't wish to count all products, but active products only.
try this:
$x = Category::with(['products' => function($query) { $query->where('active','=', 1); }])->where('active', 1)->get();
That will give you products that are active and then only categories where products are active.
Try this to be more specific. Additional from idea of #linuxartisan
$x = Category::whereHas('products', function ($query) {
$query->where('products.active', '=', 1);
})
->where('categories.active', '=', 1)
->get();
I am assuming you have active field for product as well as category.
Just try this query
$x = Category::whereHas('products', function ($query) {
$query->where('products.active', 1);
})->where('categories.active', 1)
->get();
public function products()
{
return $this->hasMany(Product::class)->where('active',1);
}
This is working in Laravel 7

Resources