How to paginate a related model in laravel - 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() }}

Related

Laravel Eloquent "With" and sub "With" relationship query -> pass Column Value as Where clause

I have 3 Models "Category" (tableName = 'categories'), "Brand" ('brands'), "Item" ('items')
Can I pass parent column value (e.g. categories) to use it in the Where clause?
Simple example:
Category::with(['brands' => function ($q) {
$q->with(['items' => function ($query) use ($localWhereHas) {
$query->whereColumn('category_id', 'categories.id');
}]);
}]);
Relations are:
Category Model:
public function brands(): BelongsToMany
{
return $this->belongsToMany(Brand::class, 'category_brands')->withPivot('is_visible', 'addon_price');
}
Brand Model:
public function items(): HasMany
{
return $this->hasMany(Item::class, 'brand_id');
}
Item Model:
public function category(): BelongsTo
{
return $this->belongsTo(Category::class, "category_id");
}
The main idea is that I need the structure to be nested like this Category->Brands->Items
The backup plan is to fetch All needed Categories and Foreach them to get as many as categories I have all Brands->Items, using categoryId ($category->category_id) .... but I don't like it
No, you can't pass it directly because it is not the same context.
If you want to have a display like this :
Category
-brand
-item
Then you should maybe just group your items by brand :
$categories = Category::with('items.brand')->get();
#foreach($categories as $category)
{{ $category->name}}
#foreach($category->items->groupBy('brand_id') as $brand_id => $items)
{{ $items->first()->brand->name }}
#foreach($items as $item)
{{ $item->name }}
#endforeach
#endforeach
#endforeach

Laravel 5 how paginate with hasMany relationship

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()}}

Laravel get posts by category

I'm trying to figure out how to get all the posts for a category using Laravel Eloquent 5.3.
I have three tables..
**Posts**
id | title | text
**Term_relationships**
term_id | post_id
**Terms**
id | name
Eloquent Models
class Term extends Model
{
public function posts()
{
return $this->belongsToMany('App\Post', 'term_relationship');
}
}
class Post extends Model
{
public function terms()
{
return $this->belongsToMany('App\Term', 'term_relationship');
}
}
class Term_relationship extends Model
{
}
I've tried with for example
Term::where('name', $category)->posts->get();
Easy,
if you want Posts with Terms do this
$data = App\Post::with('terms')->get();
in your view :
#foreach($data as $post) // will loop over posts and show title
<div>{{$post->title }} </div>
#foreach($post->terms as $term)
<div> {{ $term->title }} </div> // will loop and echo all terms for current post
#endforeach
#endforeach
if you want Terms with posts do this
$data = App\Term::with('posts')->where('name', $category)->get();
in your view
#foreach($data as $term) // will loop over terms and show title
<div>{{$term->title }} </div>
#foreach($term->posts as $post)
<div> {{ $post->title }} </div> // will loop and show all posts in each term
#endforeach
#endforeach
i think the seconds way suits your needs better since int he first example u will need to use wherehas and a closure

How to safely access other users and other model's records inside Blade template

I have 3 models in my app Users, Sales and Plans, when I render sales for each customer (due to storing) I only get id's for other users and models related to that sale (like account manager, owner, plan), now I'm trying to use those ID's inside blade to get names or other rows based on ID and model. Here is the show function:
public function show($id) {
$user = User::find($id);
$sales = Sale::where('customer_id', '=', $id)->get();
return view('profiles.customer', ['user' => $user, 'sales' => $sales]);
}
And in blade I get all those sales like:
#foreach ($sales as $sale)
<li>
<i class="fa fa-home bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> {{$sale->created_at->format('g:ia, M jS Y')}}</span>
<h3 class="timeline-header">{{$user->name}} became a customer</h3>
<div class="timeline-body">
<p>Date: {{$sale->sold_date}}</p>
<p>Price: {{$sale->sale_price}}</p>
</div>
</div>
</li>
#endforeach
So inside each record I have like "account_manager_id", "agent_id", "owner_id", "plan_id".
Currently I have this solved by adding public static function (this is for users, have same function for Plan model as well) in Sale model class:
public static function getUser($id) {
return User::where('id', $id)->first();
}
And I'm using it like this in Blade:
Account manager: {{$sale->getUser($sale->account_mgr_id)->name}}
Is this the safest and best way to do it? Or there is something I'm overlooking here?
You need to add relationships in your Sales Model.
class Sales extends Eloquent {
.....
.....
public function accountManager() {
return $this->hasMany('App\User', 'account_manager_id');
}
public function agents() {
return $this->hasMany('App\User', 'agent_id');
}
public function owner() {
return $this->hasOne('App\User', 'owner_id');
}
}
Now $sales->agents will give you a user with agent_id as id in User table.
Update your hasOne, hasMany relationships as your need. Laravel Documentation.
From your blade template, your access your AccountManager as
#foreach($sales->accountManager as $manager)
Name: {{ $manager->name}}
#endforeach
I think you could use Eloquent relationships. Taking your example, you should define relationship in your User model:
<?php
class User extends Eloquent {
public function sales() {
return $this->hasMany(Sale::class, 'customer_id');
}
}
Then, whenever you need to get sales of that user (entries, that relate via customer_id column), just simply do
<?php
$user = User::find($id);
$sales = $user->sales;
This is very fun when when you have to print out list of users that have sales, for example
<?php
public function showUsersWithSales() {
$users = User::with('sales')->get();
return view('users-with-sales', compact('users'));
}
users-with-sales.blade.php example:
#foreach ($users as $user)
User: {{ $user->name }}<br>
Sales:<br>
#foreach ($user->sales as $sale)
{{ $sale->amount }} {{ $sale->currency }} # {{ $sale->created_at }}<br>
#endforeach
<hr>
#endforeach
It would print all users with their sale amount and currency, followed by date when it was created.
This sample takes into account, that your User model has name attribute and your Sale model has amount, currency, created_at and customer_id fields in your database.
To reverse the action, say you have a sale and want to know who made it, just simply define a relationship!
<?php
class Sale extends Eloquent {
public function customer() {
return $this->belongsTo(User::class, 'customer_id');
}
}
Hope that helps!
Eloquent Relationship is your friend, https://laravel.com/docs/5.2/eloquent-relationships and you can solve your problem easily.
Suggestion is to remove all those function access and control from view and put it somewhere else. This will be good habit for you so you can avoid the infamous fat view.

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

Resources