Laravel Eloquent get all categories of restaurants? - laravel

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.

Related

How to use custom model function in eloquent

I want to get all user's online friends, how can I call a custom model function inside the eloquent condition?
this is my code
$friends = $user->friends()->where(function (Builder $query){
$query->where('friend', 'yes');
})
->get();
and this is my function in model
public function getIsOnlineAttribute(): bool
{
// check if the user is online or not
return $this->is_online;
}
I can access is_online after eloquent by foreach, but in my case, I want to check everything in one step ( inside where condition in eloquent). how can I do that???
You can't use conditions for eloquent accessors, in this case you can use (assume 1 is database column value):
$friends = $user->friends()->where('is_online', 1)->get();
or
$friends = $user->friends()->whereIsOnline(1)->get();
or you can create eloquent scope on your model:
public function scopeIsOnline($query) {
$query->where('is_online',1);
}
and you can use this eloquent scope on your controller in this way:
$friends = $user->friends()->isOnline()->get();
this worked for me :)
$friends = $user->friends()
->simplePaginate()
->reject(function ($friend) {
return $friend->is_online === false;
});

Laravel Eloquent how to get all parents

I have relation like this:
DB relation
I have a code in my model that retrieves me just one parent:
public function AllParents()
{
return $this->belongsToMany($this, 'parent', 'product_id', 'parent_id')
->select('parent', 'name');
}
I get it in my controller like this:
private function product(Product $product)
{
return $product->Product()
->with('AllParents')
->get();
}
Finally I need data like this:
Product1/Product_2/Product_3
I think I need a loop, but how to do it in Eloquent?
Just change relationship. You have mentioned pivot table name wrong one.
public function AllParents()
{
return $this->belongsToMany(Product::class, 'Product_parent', 'product_id', 'parent_id') ->select('parent', 'name');
}
and then you can access
\App\Models\Product::with('AllParents')->get()
In your Product Model. You have define relationship like this.
public function allParents()
{
return $this->belongsToMany(Product::class, 'product_parents', 'product_id', 'parent_id')->select('name');
}
And, In Controller you can get all the parents with eager loading.
Product::with('allParents')->find($productId);
And, In View you can use foreach loop to iterate every parent object.
#foreach ($product->allParents as $parentProduct)
{{ $parentProduct->name }}
#endforeach
I did like this:
I modified my controller
private function product(Product $product)
{
$allParents = [];
$parent = null;
$parent->$product->Product()->with('AllParents')->first()->id;
while ($parent != null) {
array_push($allParents, Product::all->find($parent));
$parent = Product::all()->find($parent) - first();
}
}

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!

Filter on related table with Laravel and eloquent

My method is:
public function show(Tag $tag)
{
$posts = $tag->posts;
return view('posts.index',compact('posts'));
}
It works fine but i want to get the posts where posts->user_id is the authenticated user.
public function show(Tag $tag)
{
$posts = $tag->posts()->where('user_id',Auth::user()->id);
return view('posts.index',compact('posts'));
}
How do i filter on the related posts table?
this is a many to many relationship with a pivot table present
What you have should work, but don't forget to get() the results after adding your where:
$posts = $tag->posts()->where('user_id',Auth::user()->id)->get();

Eloquent where condition based on a "belongs to" relationship

Let's say I have the following model:
class Movie extends Eloquent
{
public function director()
{
return $this->belongsTo('Director');
}
}
Now I'd like fetch movies using a where condition that's based on a column from the directors table.
Is there a way to achieve this? Couldn't find any documentation on conditions based on a belongs to relationship.
You may try this (Check Querying Relations on Laravel website):
$movies = Movie::whereHas('director', function($q) {
$q->where('name', 'great');
})->get();
Also if you reverse the query like:
$directorsWithMovies = Director::with('movies')->where('name', 'great')->get();
// Access the movies collection
$movies = $directorsWithMovies->movies;
For this you need to declare a hasmany relationship in your Director model:
public function movies()
{
return $this->hasMany('Movie');
}
If you want to pass a variable into function($q) { //$variable } then
function($q) use ($variable) { //$variable }
whereBelongsTo()
For new versions of Laravel you can use whereBelongsTo().
It will look something like this:
$director = Director::find(1);
$movies = Movie::whereBelongsTo($director);
More in the docs.
is()
For one-to-one relations is() can be used.
$director = Director::find(1);
$movie = Movie::find(1);
$movie->director()->is($director);

Resources