Laravel Eloquent group by with pivot table & relations - laravel

I have this platform I'm creating for foodtruck events. There is a pool of exhibitors who attend several events. Each foodtruck has it's own menu of dishes that they serve, in several categories.
The problem / what I'd like to achieve
I would like to make a menu for each event, looping through all
exhibitors (who attend) and then showing the dishes by category.
Something like this;
/menu/{eventid}
Dish category 1
dish from exhibitor A
dish from exhibitor B
Dish category 2
dish from exh A
dish from exh C
dish from exh D
...
Models
Event model
class Event extends Model
{
protected $table = "events";
public function exhibitors()
{
return $this->belongsToMany('App\Exhibitor', 'events_exhibitors');
}
Dish model
class Dish extends Model
{
//
protected $table = "dishes";
public function category()
{
return $this->hasOne('App\Category', 'id', 'category_id');
}
public function exhibitor()
{
return $this->belongsTo('App\Exhibitor');
}
}
Exhibitor model
class Exhibitor extends Model
{
protected $table = "exhibitors";
public function events()
{
return $this->belongsToMany('App\Event', 'events_exhibitors');
}
public function dishes()
{
return $this->hasMany('App\Dish');
}
}
Database structure
There is a pivot table to register which foodtrucks go to which events. So far, I think (hope) my relations are working. I hope this image shows enough;
What I've tried
I've tried several things but I think my insight in Laravel eloquent lacks to understand the logic behind this issue.
$dishes = Event::where('id', $id)
->with(['exhibitors.dishes' => function($q) {
$q->select('dishes.dish_data');
}])->get();
Or
$dishes = Event::with(array('exhibitor.dish') => function($query) use ($sub){
$query->where('name',$sub);}))->get();
I have absolutely no clue how to accomplish this by Eloquent or how this would work in the view.

Try something like this:
It will get all the ids of the exhibitors that are connected to the event.
Then it will get all categories where the connected dishes have an exhibitor_id that is in the array of exhibitor ids.
Category Model
class Category extends Model
{
protected $table = "categories";
public function dishes()
{
return $this->hasMany('App\Dish', 'category_id');
}
}
Controller Action
$event = Event::findOrFail($id);
$exhibitorIds = $event->exhibitors()->select('exhibitors.id')->get()->pluck('id')->all();
$categories = Category::whereHas('dishes', function($query) use ($exhibitorIds) {
$query->whereIn('exhibitor_id', $exhibitorIds);
})->with(['dishes' => function($query) use ($exhibitorIds) {
$query->whereIn('exhibitor_id', $exhibitorIds);
}])->get();
return view('events.menu', compact('event', 'categories') );
View
#foreach($categories as $category)
<h2>{{ $category->name }}</h2>
<ul>
#foreach($category->dishes as $dish)
<li>{{ $dish->dish_data }}</li>
#endforeach
</ul>
#endforeach

Related

Trying to retrieve posts from table by category slug

Hello i am trying to loop posts that are associated to each category by the slug. It works when i use the ids but when i change my controller function to search by slug it retrieves the slug but does not load the foreach loop.
I have tried so many methods and i don't know where i am going wrong please help.
Category Model :
protected $table = 'post_categories';
public function posts()
{
return $this->hasMany('App\Post', 'id', 'name', 'catslug');
}
Post Model
public function user()
{
return $this->belongsTo('App\User');
}
public function postCategories()
{
return $this->belongsTo('App\PostCategory');
}
Controller
public function getPostCategory($catslug) {
$postCategories = PostCategory::with('posts')
->orderBy('name', 'asc')
->where('catslug', '=', $catslug)
->first();
return view ('articles.category.categoriesposts')->with('postCategories', $postCategories);
}
Route
Route::get('articles/category/{catslug}', [
'uses' => 'ArticlesController#getPostCategory' ,
'as' => 'PostCategory'
] );
View
#foreach($postCategories->posts as $post)
<h4>{{ substr($post->title, 0, 50) }}</h4>
<p>{{ substr($post->body, 0, 90) }}</p>
#endforeach
When i use id there is no problem i cant see what i am doing wrong any feedback will be truly appreciated
Thanks
Ash
Save category id in posts table insted of category name or slug.
Change in post category model:
public function posts()
{
return $this->hasMany('App\Post', 'category_id');
}
Your controller method:
public function getPostCategory($catslug)
{
$postCategories = PostCategory::with('posts')->where('catslug', $catslug)->first();
return view('articles.category.categoriesposts')->with('postCategories', $postCategories);
}
If you want to order posts by name then add orderBy() in relationship :
public function posts()
{
return $this->hasMany('App\Post', 'category_id')->orderBy('name', 'asc');
}

hasOne Relation not working in laravel

Hi I want to make relationship between two tables first Table is product and second is productimages
ProductController.php
public function product(){
$products = Product::all();
dd($products->images);
}
Product.php (modal)
class Product extends Model
{
public $timestamps = false;
//
public function images()
{
return $this->hasOne(ProductImage::class);
}
}
ProductImage.php(model)
class ProductImage extends Model
{
public function product(){
return $this->belongsTo(Product::class);
}
}
When i am using this method $products = Product::find(1); working find but i need all.
Thanks
When you're doing $products->images you're trying to access property of collection.
Preload all products with their images, use with() method:
$products = Product::with('images')->get();
Then you'll be able to get image of each product and avoid N + 1 problem:
#foreach ($products as $product)
// Access $product->image here
#endforeach
Product::with('images')->get();

get data from multiple relations in laravel eloquent

I have the following tables pharmacies,categories,medicines and I am using laravel
the relations are like this
pharmacy have many medicines and the medicine belongs to one category
the medicines table have pharmacy_id and category_id columns + other columns
I want to show a pharmacy by id and it should return an object of pharmacy with categories, each category have object of medicines in this pharmacy. If there is no medicine in any category, then it should not be returned.
I think its a model relations issue
any idea could be useful
the category model
class Category extends Model
{
protected $table = 'categories';
public function pharmacies()
{
return $this->belongsToMany(Pharmacy::class, 'pharmacy_category', 'category_id', 'id');
}
public function medicines()
{
return $this->hasMany(Medicine::class);
}
}
the pharmacy model
class Pharmacy extends Model
{
use SoftDeletes;
protected $table = 'pharmacies';
protected $appends = ['favourite'];
public function categories()
{
return $this->belongsToMany(Category::class,'pharmacy_category','pharmacy_id','id');
}
public function getFavouriteAttribute()
{
if (!Auth::check()) {
return 0;
}
return (FavouritePharmacy::where('user_id', Auth::user()->id)->where('pharmacy_id', $this->id)->count() == 1) ? 1 : 0;
}
}
the medicine model
class Medicine extends Model
{
protected $appends = ['favourite'];
public function orders()
{
return $this->belongsToMany(Order::class);
}
public function getFavouriteAttribute()
{
if (!Auth::check()) {
return 0;
}
return (FavouriteMedicine::where('user_id', Auth::user()->id)->where('medicine_id', $this->id)->count() == 1) ? 1 : 0;
}
}
If you want to display pharmacy info, categories with medicines, with these relationships I'd do this:
$pharmacy = Pharmacy::find($id);
$categoriesWithMedicines = Category::whereHas('medicines', function($q) use($id) {
$q->where('pharmacy_id', $id);
})
->with(['medicines' => function($q) use($id) {
$q->where('pharmacy_id', $id);
}])
->get();
Then in a view, you'll have a pharmacy object and a list of categories with medicines which belong to the pharmacy:
#foreach ($categoriesWithMedicines as $category)
{{ $category->name }}
#foreach ($category->medicines as $medicine)
{{ $medicine->name }}
#endforeach
#endforeach

Laravel Nesting to 4 levels not working

I have relationships like the following:
Category -> Subcategory -> Product -> Price
A Category contains X Subcategories.
A Subcategory contains X Products.
A Product contains X Prices (New Price, Old Price, One Record per Price Change)
I wanted to do the following:
#foreach($categories as $category)
[...]
#foreach($category->subcategories as $subcategory)
[...]
#foreach($subcategory->products as $product)
[...]
#foreach($product->prices as $price)
[... #endforeach x4 ...]
The 3 first levels are working. When using the 4th however ($product->prices) I get an Trying to get property of non-object error.
The relationships in the Models:
Category.php
class Category extends Model
{
public function subcategories()
{
return $this->hasMany('App\SubCategory');
}
}
SubCategory.php
class SubCategory extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
public function products()
{
return $this->hasMany('App\Product');
}
}
Product.php
class Product extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
public function subcategory()
{
return $this->belongsTo('App\SubCategory');
}
public function price()
{
return $this->hasMany('App\ProductPrice');
}
}
ProductPrice.php
class ProductPrice extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
}
This is what I send to my View:
class PageController extends Controller
{
public function showMainPage()
{
$categories = Category::with('subcategories')->get();
$data = array(
"categories" => $categories,
);
return view('index')->with($data);
}
}
This worked fine, even with Products but began to have errors when using the ProductPrices.
As #GONG said, change your code for use eager load, this will run so much faster than use some foreaches.
See laravel docs: https://laravel.com/docs/5.3/eloquent-relationships#eager-loading

Using relations on a collection

I have a Collection that holds the root category and all descendants. In my Category model, I have established that there can be many posts in relation to the category. I retrieve the category and it's descendants with this code:
$category = Category::findOrFail($categoryID);
$categoryAndDescendants = $category->getDescendantsAndSelf();
$categoryAndDescendants is a Collection object that holds Category models. Is it possible to retrieve all of the posts at once?
I basically want to do something like:
$posts = $categoryAndDescendants->posts()->orderBy('timestamp', 'DESC');
Which would retrieve all of the posts for all of the categories and their descendants in that particular collection.
Thanks for the help and I apologise for the awful wording.
I think that's not possible.
But you could write a custom Collection, and implements this function. Something like this:
<?php
use Illuminate\Support\Collection;
class CategoryCollection extends Collection
{
public function posts()
{
$posts = new Collection();
foreach ($this->items as $category) {
foreach ($category->posts() as $post) {
$posts->add($post);
}
}
return $posts;
}
}
And then, you just need to set this custom collection to your Category model.
class Category extends Eloquent
{
public function newCollection(array $models = array())
{
return new CategoryCollection($models);
}
}

Resources