Laravel 5 how paginate with hasMany relationship - laravel

I have a relationship this like;
public function foods() {
return $this->hasMany('App\models\food\food', 'category_id', 'id');
}
My controller file content;
$datas = food_category::where('slug', $slug)->with('foods')->paginate(12);
But incoming datas in there all datas and this is causing bad performance. I want to paginate apply relationship datas.

If you want to paginate foods, try adding a separate method for that:
Model:
class food_category
{
public function getFoodsPaginatedAttribute()
{
return $this->foods()->paginate(12);
}
}
Controller:
$datas = food_category::where('slug', $slug)->get();
View:
#foreach ($datas as $data)
#foreach ($data->foods_paginated as $food)
{{ $food->name }}
#endforeach
#endforeach

Pass paginated collection to the view:
//view
#foreach ($datas as $data)
// do what you need
#endforeach
//link
{{$datas->links()}}

Related

Undefined property: Illuminate\Database\Eloquent\Relations\BelongsToMany::$path

I wrote a relation belongsToMany between products and photos and now I want to show products in the home page. I did it like so:
#foreach ($latestProducts as $product)
<img src="{{$product->photos()->path}}">
#endforeach
homeController:
public function index()
{
$latestProducts = Product::orderBy('created_at' , 'desc')->limit(10)->get();
return view('front.layouts.index' , compact('latestProducts'));
}
photo model:
public function products() {
return $this->belongsToMany(Product::class);
}
product model:
public function photos() {
return $this->belongsToMany(Photo::class);
}
I got Undefined property: Illuminate\Database\Eloquent\Relations\BelongsToMany::$path .And when I write {{$product->photos[0]->path}} , the error changes to "Undefined array key 0. Also when I write {{$product->photos->path}} ,I get an error as "Property [path] does not exist on this collection instance."
I believe you got a photo attribute/field in the Photo model. Because photos is a collection of photos, you might want to write:
#foreach ($latestProducts as $product)
#foreach ($product->photos as $photo)
<img src="{{$photo->path}}">
#endforeach
#endforeach
And only the first photo:
#foreach ($latestProducts as $product)
<img src="{{$product->photos->first()->path}}">
#endforeach
// Or to be safe
#foreach ($latestProducts as $product)
<img src="{{optional($product->photos->first())->path}}">
#endforeach
// Or this in php 8
#foreach ($latestProducts as $product)
<img src="{{$product->photos->first()?->path}}">
#endforeach
You have to use
{{ $product->photos->path }}
cause when you deal with relations in blade you deal with it as a property of class of the father class unlike when you deal with it in eloquent ORM you can use photos()
Basically the error is saying that there is no property photos in the $products. Assuming that the table name is correct and the foreign keys too
you can just do:
public function index()
{
$latestProducts = Product::with('photos')->orderBy('created_at' , 'desc')->limit(10)->get();
return view('front.layouts.index' , compact('latestProducts'));
}
And in blade file try to remove the (), because it will load the relationship.
#foreach ($latestProducts->photos as $product)
<img src="{{$product->path}}">
#endforeach

Paginate Laravel Relation

I have two tables let's say posts and comments with Post and Comment Model.
Post.php
public function comments(){
return $this->hasMany(Comment::class);
}
Comment.php
public function post(){
return $this->belongsTo(Post::class);
}
Now I want to load Post with comments with pagination on both Post and comments.
What I tried so far,
Post::with('comments')->pagenate();
The above code only paginates on Post Model. So I tried the following code but no luck.
In Post.php
public function comments(){
return $this->belongsTo(Comment::class)->paginate(5);
}
Post::with('comments')->pagenate();
In the controller you must put the Post variable and for each post the Comments variable with it paginate, then you return the variables.
$posts = Post::orderBy('id', 'desc')->paginate(10);
foreach ($posts as $post)
$comments = $post->comments()->paginate(2);
return view('post.index', ['posts' => $posts, 'comments' => $comments]);
Now, in the blade view, you only need to put the #foreach of the comments variable in the post and add the links to page it for you.
#foreach( $comments as $comment )
<p> {{ $comment->desc }}</p>
#endforeach
{{ $comments->links() }}

Laravel 5.3 access hasone in elequant from view

I'm trying to access a relations table from a collection of data passed in from the controller. I am able to iterate the collection in my view but I am unable to access the relationship data.
There are 2 tables:
stocks (default model)
stock_datas (has a foreign key stock_id which is already setup)
Controller:
public function getstock() {
return view('vehicles.getstock', ['stock' => \App\Stock::all()]);
}
Model (App\Stock) and then (App\StockData)
// From stock model:
public function stockdata() {
return $this->hasOne('App\StockData');
}
// Stock Data model:
public function stock() {
return $this->belongsTo('App\Stock');
}
View (loop):
#foreach ($stock as $k => $v)
{{ print_r($v->stockdata()->get())->year }}
#endforeach
When I try the query below, I get a
Undefined property: Illuminate\Database\Eloquent\Collection::$year (View: F:\websites\tempsite\resources\views\vehicles\getstock.blade.php)
However, year is a column in the stock_datas table.
I am also able to print_r data from the \App\StockData() table so the reference to the table is correct as doing print_r(\App\StockData::all()) from the controller does return all the rows as expected.
What am I doing wrong?
Since it's one to one relation, you should do it like this:
#foreach ($stock as $v)
{{ $v->stockdata->year }}
#endforeach
First one You have to change {{ print_r($v->stockdata()->get())->year }} this line, remove print_r. Next one in foreach loop you can do something like this
#foreach($stock as $one)
{{ $one->stockadata()->first()->year }}
#endforeach
For better solution you should check if isset $one->stockadata()->first()
and after that call ->year. Finally code should be like this
#foreach($stock as $one)
{{ isset($one->stockadata()->first()) : $one->stockadata()->first()->year : 'Default' }}
#endforeach
When calling get() method on any relationship You will always receive collection, no matter what relationship You have.
There are at least two (2) ways to solve Your problem:
1. $v->stockdata->year
2. $v->stockdata()->first()->year
I would suggest You to use first one, because Your stockdata has 1:1 relationship.
Good luck!
For example:
Stock.php model
class Stock extends Model
{
protected $primaryKey = 'id';
function stockdata() {
return $this->hasOne('App\StockDatas', 'id', 'stock_id');
}
public function getStock(){
return Stock::with('stockdata')->get();
}
}
In contriller
public function getstock(Stock $stock) {
return view('vehicles.getstock', ['stock' => $stock->getStock]);
}
view
#foreach ($stock as $k => $v)
{{ $v->stockdata->year }}
#endforeach

How to best get results from 3 different tables based on ID matches in Laravel.

Trying to get products AND variants for a particular supplier.
I can get the products easy enough, but can't figure out how to best get to the variants with matching product_id and send it to the view.
Variants.product_id matches with Product.ID
This works (getting products for the supplier)
public function suppliers($id) {
$supplier = Supplier::orderby('company_name', 'ASC')->find($id);
$products = Supplier::find($id)->products;
$data = [];
$data['supplier'] = $supplier;
$data['products'] = $products;
return view('admin.purchasing.supplier-details', $data);
}
I've tried this to get the variants also without luck.
Controller:
public function suppliers($id) {
$supplier = Supplier::orderby('company_name', 'ASC')->find($id);
$products = Supplier::find($id)->products;
$variants = array();
foreach ($products as $product) {
$product_id = $product->id;
$variants[] = Variant::find($product_id);
}
$data = [];
$data['supplier'] = $supplier;
$data['products'] = $products;
$data['variants'] = $variants;
return view('admin.purchasing.supplier-details', $data);
}
View:
#foreach($products as $product)
<tr>
<td>{{ $product['title'] }}</td>
#foreach($variants as $variant)
#if($variant->product_id == $product['id'])
<td>${{ $variant->price }}</td>
#else
<td>not set</td>
#endif
#endforeach
</tr>
#endforeach
Any tips much appreciated.
First of all , you should have relation set on your models to make this work
like this For exemple :
Supplier.php
public function products()
{
return $this->hasMany('App\Product');
}
Product.php
public function variants()
{
return $this->hasMany('App\Variant');
}
public function Supplier()
{
return $this->belongsToMany('App\Supplier'); //in case you have only one supplier for each product change this to belongsto
}
Variant.php
public function products()
{
return $this->belongsToMany('App\Product'); //not sure if this should be manytomany or one to many , it deppends on what you did
}
anyway now you can do this
Controller
public function suppliers($id) {
$Data = Supplier::where('id',$id)->orderby('company_name', 'ASC')->with('products.variants')->first(); //you will get the supplier with all products associated to him with variants foreach product
return view('admin.purchasing.supplier-details')->with('Data',$Data); // now you just loop the $supplierwithproducts->products to get results (dd the variable to check output)
}
View
{{ $Data->name }} // supplier name since Supplier model was the starting point
#foreach($Data->products as $product) //loop all products related to that supplier
{{ $product->name }} //shows product name (depends on you database columns
#foreach($product->variants as $variant) // loops all variants in the current product
{{ $variant->name }} // shows variants
#endforeach
#endforeach
If you copy and paste this code it might not work ,but this will give you an idea how you should handle relations in laravel (levrage eloquent relations)
Check this for more informations
Laravel Docs
Laracasts Defining Relationships With Eloquent
Laracasts Updating Records and Eager Loading

How to paginate a related model in laravel

i have two model which is RoomCategory and Room. and i want to paginate all rooms related by each roomcategory by a foreach loop, here's my MVC.
Model
class RoomCategory extends \Eloquent {
public function Room(){
return $this->hasMany('Room','category_id','id','RoomCategory');
}
}
class Room extends \Eloquent {
public function RoomCategory(){
return $this->belongsTo('RoomCategory','id','category_id','Room');
}
}
Controller
public function index()
{
$room_category = RoomCategory::get()
->with('Room')->paginate(1);
return View::make('pages.roomlist', compact('room_category'));
}
View
#foreach($room_category as $category)
{{$category->name}}
#foreach($category->room as $rooms)
{{$rooms->name}}
{{$category->room->links()}}
#endforeach
#endforeach
and i got this error
Call to undefined method Illuminate\Database\Eloquent\Collection::with()
can someone help me how to paginate those rooms under a foreach loop of the roomcategories. thanks
To achieve what you want you have to fetch all room categories, loop through them and then loop through the each room category rooms.
This is example code:
public function index()
{
$room_category = RoomCategory::with('Room')->paginate(1);
return View::make('pages.roomlist', compact('room_category'));
}
Your view:
#foreach($room_category as $category)
{{$category->name}}
#foreach($category->Room as $rooms)
{{$rooms->name}}
#endforeach
#endforeach
You don't need get() method if you are using paginate. Replace this
$room_category = RoomCategory::get()
->with('Room')->paginate(1);
with this
$room_category = RoomCategory::with('Room')->paginate(1);
EDIT
It would be good if you don't use pagination links for room in your index page, just paginate your roomcategory.
$room_category = RoomCategory::with([
'Room' => function($query) {
$query->latest()->limit(5);
}
])->paginate(3);
On your index view paginate the categories and make a link to each category page and paginate your room their
index.blade.php
#foreach($room_category as $room_cat)
#foreach($room_cat->Room as $room)
<div class="room-section"></div>
#endforeach
View more of this category
#endforeach
{{ $room_category->links() }}
Your Controller
public function showCategory($id)
{
$room_category = RoomCategory::with([
'Room' => function($query) {
$query->latest()->paginate(8);
}
])->find($id);
return View::make('category.show', compact('$room_category'));
}
and category/show.blade.php you can paginate room
#foreach($room_category->Room as $room)
<div class="room-section"></div>
#endforeach
{{ $room_category->Room()->links() }}

Resources