Pagination in relations using 'with' - laravel

I have some trouble with pagination. I need to take only one category with movies and paginate it. Now I write some code, but I don't think it's optimized.
$category = Category::with(['movies' => function ($query) {
$query->orderBy('id', 'desc')->paginate(18);
}])->where('slug', $slug)->first();
$catMoviesPaginate = $category->movies()->paginate(18);

You can do it with lazy loading as here I mention the code which can help to you.
$category = Category::where('slug', $slug)->first();
$movies= $category->movies()->paginate(18); //lazy loding.
return view('example', compact('category', 'movies'));
You can render the pagination in view file as well.
#foreach ($movies as $movie)
{{ $movie->id }}
#endforeach
{!! $movies->render() !!}

The most efficient way would be to create an inversed relation in movies for categories. Then you query the movies in X category by slug. You should end up with something like this
Movies::whereHas('categories', function($q) use($slug) {
$q->where('slug', $slug)
})->paginate(18);
You can take it a step further and create a scope in the Movies model to simplify your code. With the proper scope it can be as simple as Movies::inCategory($slug)->paginate(18)

Related

Laravel Foreach sum result with while filter

Here my table
:chart_of_account_category
id
name
:chart_of_accounts
id
chart_of_accounts_category_id
:ledger_book
id
transaction_id
chart_of_accounts_id
:transaction
id
name
date
total
this is what i want to achieve
Controller
$chart_of_accounts_category = ChartOfAccountsCategory::get();
return view ('backend.ledger_book.index', compact('chart_of_accounts_category'));
Blade/View
#foreach ($chart_of_accounts_category as $account_category )
#foreach ($account_category->ChartOfAccounts as $item)
$item->LedgerBook->where('chart_of_accounts_id', $item->id)->sum('transaction.total'), 2)
#endforeach
#endforeach
i can get the sum thru this, but i still need to filter few things more, which i done it in blade. but cant get the filter works properly especially where like with symbol %, i would minimize query inside blade, is there anywhere i can get the result thru controller?
$item->LedgerBook->where('chart_of_accounts_id', $item->id)->where('transaction.date', 'like', '2019-06-%')->sum('transaction.total'), 2)
Instead of 'like' operator, you can use
->whereYear('transaction.date', '2019')->whereMonth('transaction.date', '06').
Also, I would suggest you to eager load ChartOfAccounts, LedgerBook and Transaction in your Controller. This will make your foreach loops much faster.
$chart_of_accounts_category = ChartOfAccountsCategory::with(['chartOfAccounts' => function ($query) {
$query->with(['ledgerBooks' => function ($query) {
$query->with(‘transaction’)
->whereHas(‘transaction', function ($query) {
$query->whereYear('date', '2019')
->whereMonth('date', '06');
});
}]);
}])
->get();

Attain many has-many-through

I need to attain latest comments from array of users through posts.
Users model
public function comments()
{
return $this->hasManyThrough('App\Comment', 'App\Post');
}
has-many-through
$user = users::where('id',5)->first();
$user->comments()->get()
many has-many-through
$user = users::where('role','member')->get();
How can I achieve this.
You might looking for the method with() in ORM to get your expected results.
eg. `User::where('field','SOMECONDTION')->with('comments');
so in your foreach on your view you simply get the comments data.
#foreach($users as $index => $user)
#foreach($user->comments as $j => $comment)
{{$comment->some_field}}
#endforeach
#endforeach

OrderBy on Eloquent whereHas relationship

I have a simple page which lists counties and there related items under headings. These items need to be approved, hence the whereHas method.
I currently have the following eloquent query;
$counties = County::whereHas('items', function ($query) {
$query->where('approved', 1);
})->get();
The items returned are currently ordered by their primary field id (it would seem), however I want to list these items alphabetically by their name field.
I have tried the following query, but this does change anything. Any advice would be appreciated?
$counties = County::whereHas('items', function ($query) {
$query->where('approved', 1)->orderBy('name');
})->get();
$counties = County::whereHas('items', function ($query) {
$query->where('approved', 1);
})->orderBy('name')->get();
I don't think you can order on the subquery, it should be before the ->get
when you want to display the result , try this :
#foreach($counties as $county)
#foreach($county->items->orderBy('name') as $item)
{{ $item->name }}
#endforeach
#endforeach
Or in your County Models :
public function approvedItems(){
return $this->hasMany(Item::class)->where('approved', 1)->orderBy('name');
}
and then :
controller :
$counties = County::whereHas('approvedItems')->get();
view :
#foreach($counties as $county)
#foreach($county->approvedItems as $item)
{{ $item->name }}
#endforeach
#endforeach
Try to work with your models and relationships for having the lightest controller you can, you will gain in lisibility
To keep it eloquent, you can put it in the relation, in the Model class:
public function reviews()
{
return $this->hasMany(Review::class)->orderBy('id','desc');
}
https://laravel.io/forum/09-14-2015-ordering-a-collection-by-the-related-items
Might be late, but hopefully someone stumbles on this (it's the first in google search)
$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');

Laravel conditional on relation: return first()

I have a Laravel 5.2 one-to-many relation and I want to return the model and put a condition to relation.
I've tried this:
$categories = Category::with(['descriptions' => function($d) use ($default_language) {
$d->where('language_id', $default_language->id);
}])->get();
It work fine, I just want something else: the relation should not be a collection or array, just a simple object. I want to do something like
$d->where('language_id', $default_language->id)->first();
, just in this case first() is not working. Any ideas?
EDIT
Actually first() is not working properly, it returns first description just for the first object returned, for others it return nothing.
Try this:
$categories = \Jobinja\CMS\Blog\Models\Category::with([
'descriptions' => function ($q) use ($defaultLanguage) {
return $q->where('language_id', $defaultLanguage->id)->take(1);
}
])
->get()
->map(function ($item) {
if ($item->descriptions->isEmpty() === false) {
$item->description = $item->descriptions->first();
}
return $item;
});
and get to description:
foreach ($categories as $category) {
$description = $category->description;
}
You can't do that but you can use first() on a collection later, for example in a view:
#foreach ($categories as $category)
{{ $category->descriptions->first()->name }}
#endforeach
I can say to use instead of first() find() and give it the language_id or $default_language->id and this will try to find in the table first the column id and assign the value. If you have different id column name give it to the find like find(['your_column_name' => '<your_value']).
If you want array to something like ->toArray(). You can test different scenarios in tinker. php artisan tinker
Here is a link to document this -> https://laravel.com/docs/5.3/eloquent#retrieving-single-models

htmlentities() expects parameter 1 to be string, array given? Laravel

I've found many question realated to my problem but couldn't found an answer yet. It's about my foreach loop in my blade.
I want to print all product-names in my blade but I couln't figure out how to do that.
thats how I'm getting the products:
--- current code:
// controller
$id_array = Input::get('id');
$products= Products::whereIn('id', $id_array)->get();
$product_name = [];
foreach($products as $arr)
{
$product_name= $arr->lists('name');
}
returning $product_name gives me this as a output:
["football","cola","idontknow","freshunicorn","dummy-data"]
In my blade is just a simple:
#foreach($products as $product)
{{ $product}}
#endforeach
Error: htmlentities() expects parameter 1 to be string, array given
Thanks for your help and time.
It seems you are getting an object in an array in an array.
Like this:
array(
array(
object
)
)
It happens because you use the get() function to retrieve you model. The get() function always "wants" to retrieve multiple models. Instead you will have to use the first() function.
Like this:
foreach($id_array as $arr)
{
$want2editarray[] = Product::where('id', $arr)->first();
}
Hope it helps :)
Edit after #Wellno comment
That's probably because Product::where('id', $arr)->first(); returns null because it did not find anything.
I forgot to add a check after the retrieving of the product.
This can be done like this:
foreach($id_array as $arr)
{
// First try to get model from database
$product = Product::where('id', $arr)->first();
// If $product insert into array
if ($product) $want2editarray[] = $product;
}
Why do you use loop with IDs? You can find all products by IDs:
$products = Product::whereIn('id', $id_array)->get();
And then use $products in the blade template
#foreach($products as $product)
{{ $product->name }}
#endforeach
try to use Model/Eloquent to fetch data.
View should only display the data and not fetching directly from DB or do heavy calculations.

Resources