Attain many has-many-through - laravel

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

Related

Pagination in relations using 'with'

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)

accessing collections within collections laravel 5

I have a table of "rosters" that's pretty much strictly foreign keys. It acceses the "schools" table, "courses" table, and "students" table. So essentially, a 'student' takes a 'course' at a 'school'. My RostersController has this
public function show($id)
{
$roster = Roster::where('course_id', $id);
return view('roster')->with('roster', $roster);
}
My Roster Model is:
public function students()
{
return $this->hasMany('App\Student');
}
My student Model is:
public function roster()
{
return $this->belongsTo('App\Roster');
}
my view is this:
#foreach ($roster as $child)
<p>{{$child->id}}</p>
<p>{{$child->students->first_name}}</p>
#endforeach
The rosters table just saves the student_id rather than all of the student's data that is already in the 'students' table. So i'm trying to access the students table from this relation but when i run this, it tells me that anything related to the students table is 'not on this collection'. I know that I could do things this way if i was working with a hasOne relationship, but how can i accomplish this with a hasMany to output the students table value in each row?
You should try this
public function show($id)
{
$roster = Roster::with('students')->where('course_id', $id);
return view('roster')->with('roster', $roster);
}
Try this
Roster.php
public function show($id)
{
$roster = Roster::with('students')->where('course_id', $id)->get(); // load the students
return view('roster')->with('roster', $roster);
}
On the view
#foreach ($roster as $child)
<p>{{$child->id}}</p>
<p>
<!-- Loop through the stundents since this returns an collection of students and not just one -->
#foreach($child->students as $student)
{{$student->first_name}} <br>
#endforeach
</p>
#endforeach
Check this for more information on eager loading
The $child->students is a collection. So, you need to use another foreach loop inside the first one.
Your code should look like this:
#foreach ($roster as $child)
<p>{{$child->id}}</p>
#foreach($child->students as $student)
<p>{{$student->first_name}}</p>
<p>{{$student->age}}</p>
<p>{{$sutdent->another_column_in_students_table}}</p>
#endforeach
<p>{{$child->any_other_column_in_roster_table_if_needed}}</p>
#endforeach
So, your first issue is, that
$roster = Roster::where('course_id', $id);
will just return a QueryBuilder instance, you have to use
$roster = Roster::where('course_id', $id)->get();
then for sure, students is a collection, you have to iterate over it like this:
#foreach ($child->students as $student)
{{ $student->yourProperty}} <br>
#endforeach
Update:
I saw you know already about that when to use get() in query laravel 5

How to pass variable from foreach to view in laravel 5.4?

I want to count each location in my Job table by using location_id in my job table with id in location table. below code, I can count result correctly but I don't know how to pass this variable to the view. Please help?
//my code
public function index(){
$location = Location::all();
$count_location = [];
foreach ($location as $locations){
$count_location = Job::where('location_id', $locations->id)->count();
}
}
Use withCount() and view() to pass location with counted jobs to the view:
public function index(){
return view('view.name', [
'locations' => Location::withCount('jobs')->get()
]);
}
In the view:
#foreach ($locations as $location)
{{ $location->name }} has {{ $location->jobs_count }} jobs
#endforeach
You can return the collection of locations to the view and then loop through each object in the collection like so:
return view('index', [
'locations'=> $locations,
]);
Then in your index.blade.php you can use something like a #foreach or #forelse loop
#foreach ($locations as $location)
{{ $location->id }}
#endfoeach
EDIT
From the looks of it you would be better off defining a relationship between locations and jobs (i.e. a "many to many" or "one to many" relationship). this would allow you to get the counts for jobs at given locations very easily like so:
$location->jobs->count()
Eloquent relationships are explained in the documentation here
https://laravel.com/docs/5.5/eloquent-relationships
It would be more efficient if construct your query to fetch the count of related models instead of looping through all the results.
Have a look at Counting Related Models in the documentations.
For example, to get the count of all jobs related to a location, you could do:
$locations = App\Location::withCount('jobs')->get();
foreach ($locations as $location) {
echo $location->jobs_count;
}
You need to adjust the code according to your models structure.
Do this
public function index(){
$locations = Location::all();
return view('index', compact('locations'));
}
In your Location model make a relationship by adding this
public function jobs(){
return $this->hasMany(Job::class);
}
In your index view do this
#foreach ($locations as $location)
{{$location->jobs->count}}
#endforeach
Please note that Job should be there in your your model

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');

Paginate a relationship?

Im trying to find a user and paginate their posts, I've tried:
User::find($id)->posts()->paginate();
This paginates the posts, but I lose the users information. I also need to get the users information out along with their posts.
How can I do this?
This can be done by passing a function when eager loading:
User::find($id)->with(['posts' => function($query) use ($limit) {
$query->paginate($limit);
}])->get();
Just inverse it
$posts = Post::where('user_id',$user_id)->with('user')->paginate();
Access user
foreach ($posts as $post){
$post->user;
}
I have not tested this but I believe it could work something like this
$user = User::find($id)
Send that to the view and then you can access the User as
{{ $user->property }}
and for his posts
#foreach ($user->posts()->paginate(15) as $post)
// do something
#endforeach
{{ $user->posts()->links() }}
UPDATE
However this is not the best practice.
You could also send both $user and $user->posts()->paginate() to the view.

Resources