Get paginated many to many records in laravel - laravel

for my app I made it so an user can favorite venues, this relationship between venues and user is many to many, problem is I don't know how to get favorite_venues paginated.
Right now what I'm doing is getting user with favorite_venues but that doesn't seem right to me, is there a way to get favorite venues paginated directly without having to get the user.
What I'm currently doing:
public function getFavorites($request)
{
$user = User::with(['favoritevenues','favoritevenues.category'])->findOrFail(1);
return $user;;
}
I set relationships like this:
User Model
public function favoritevenues()
{
return $this->belongsToMany('App\Models\Venue', 'favorite_venues', 'user_id', 'venue_id')->withTimeStamps();
}
Venue Model
public function favorites()
{
return $this->belongsToMany('App\Models\User', 'favorites', 'venue_id', 'user_id')->withTimeStamps();
}
Thanks in advance

you can do:
Venue::whereHas('favorites', function ($q) {
return $q->where('id', 1);
})->paginate(5);
This will get and paginate all the venues which are the favourites of user with id 1

Related

get posts where relationship count is equel to post's attribute

I have a model "Post" which has a field "daily" in the database.
$table->integer('daily'); // could be anything
The Model "Post" has a relationship to the model "Comments".
public function comments() {
return $this->hasMany(Comment::class);
}
public function completed() {
return $this->hasMany(Comment::class)->completed();
}
Comments model
public function scopeCompleted($query) {
return $query->....?
}
I want to get all user's posts where it's comments count are equal to the post's 'daily' field. For example: if the post's daily field is '5' and there are 5 comments to this posts, I want to see this post in the returned lists, otherwise don't return it.
I know I can get all of them and do it with loop, but I wanna know if there is any way to do this with eloquent only.
Try this
$user=User::with('posts','posts.comments')
->whereHas('posts.comments',function ($query){
//if any additional filters
},'=',DB::raw('posts.daily'))
->get();
or if not needed additional query then
$user=User::with('posts','posts.comments')
->whereHas('posts.comments',null,'=',DB::raw('posts.daily'))
->get();
Got it working like this
public function scopeCompleted($query) {
return $query->has('comments', '=', DB::raw('posts.comments'));
}

How to filter Eloquent collection with data from pivot table

I'm searching for a fine and neat solution to filter my Eloquent collection with the data in the related pivot table. I actually found a solution to my problem already though it feels like my solution is somehow bad. Here is, what I got:
Two models Video and User where every user can track separately the progress on a video. For this I need to save the progress for every video in the ratings table related to the user. When you want to search for just the progress you can do that besides some other filters (category, full text search). What I find a bit quirky is that I have to double "where()" the part where I'm checking the video progress for the logged in user.
Video.php
class Video extends Model
{
use SearchableTrait;
use Taggable;
[...]
public function videocreator(){
return $this->belongsTo('App\User', 'create_user_id');
}
public function users(){
return $this->belongsToMany('App\User', 'progress', 'video_id', 'user_id')
->withPivot('progress_index')
->withTimestamps();
}
[...]
}
User.php
class User extends Authenticatable
{
use Notifiable;
[...]
public function videoscreated(){
return $this->hasMany('App\Video');
}
public function videos(){
return $this->belongsToMany('App\Video', 'progress', 'user_id', 'video_id')
->withPivot('progress_index')
->withTimestamps();;
}
}
VideoController.php
class VideoController extends Controller
{
public function index(Request $request)
{
[...]
$videos = Video::with('videocreator')->with(['users' => function ($query) {
$query->where('users.id', '=', auth()->user()->id);
}])->latest();
if($request->filled('progress') && $request['progress'] !== 'all'){
$videos = $videos->whereHas('users', function($query) use($selectedProgress) {
$query->where('progress_index', $selectedProgress)->where('users.id', '=', auth()->user()->id);
});
}
$videos = $videos->get();
[...]
}
As you can see this part where('users.id', '=', auth()->user()->id) is duplicated. A friend of mine from the Ruby on Rails Faction proposed to come from the User Model first and then fetch the Videos (that's how you would do it there). Though this way you would limit the videos to the user from the progress table. This is not what you want. The App shall track only the per user progress per video, meaning, all the users can see all the videos (just not the progress which is not their own.
Another approach would be to put the part where you filter for the user into the relationship. A method like: myProgress() or something similar.
What is your opinion to that? Is there a more 'eloquent' way to solve that?
Thanks in advance for reading this post!
I would do something like this :
// Get an instance of the videos relationship of the current authenticated user
// Eager load the videocreator relationship
$videoQuery = request()->user()->videos()->with('videocreator');
if ($request->filled('progress') && $request->input('progress') !== "all") {
// Constrain the query : only get the videos with rated_index equal to $selectedProgress
$videoQuery = $videoQuery->wherePivot('rated_index', $selectedProgress);
}
// Finally, run the query against the database
$videos = $videoQuery->latest()->get();

Getting 2 lots of relationship data from a Laravel collection with Yajra Datatables

I am trying to get my Yajra Datatable working correctly but struggling.
Basically I want to get all clients appointments in which the client belongs to the logged in user. I then want to access the Client name and then the appointment data. I have used the following to get the appointment data
$user = User::find(Auth::user()->id);
$data = $user->clients()->with('appointments')->get()->pluck('appointments')->flatten();
return Datatables::of($data)
->make(true);
This allows me to show a row for each appointment that exists for the user-owned clients appointments. But how can I also access the clients name from this?
I have tried many different ways but if I use something like
$data = $user->clients()->with('appointments')->get();
I can access all of the data I need but it shows the existing clients in each row, not all appointments owned by the clients.
My setup is
User Model
public function clients(){
return $this->hasMany(Client::class);
}
public function appointments()
{
return $this->hasManyThrough(Appointment::class, Client::class);
}
Client Model
public function appointments(){
return $this->hasMany(Appointment::class);
}
public function users(){
return $this->belongsTo(User::class);
}
Appointment Model
public function client(){
return $this->belongsTo(Client::class);
}
Thank you
You might be looking for whereHas:
$appointments = Appointment::with('client')
->whereHas('client.users', function ($query) use ($user) {
$query->where('users.id', $user->id)
})
->get();
This translates to: "Give me all the appointments that belong to clients of a specific user".
Just a suggestion, it might be wise (not required at all) to alter your database structure to something more flexible. What if you for instance keep track in you appointment which user is present?
appointments
- user_id
- client_id
This would make your query a bit simpler
// In User
public function appointments()
{
return $this->hasMany(Appointment::class);
}
$user->appointments()->with('client')->get();
You could go even further by making the relation between User and Appointment, Client and Appointment many to many so you could have appointments with more than one user and/or client.

How to retrieve multiple relations with multiple tables in laravel eloquent

I'm using Laravel 5.8 to build a babysitting site. I have 4 tables with different relationships as below:
please see this image
The relationships are:
Babysitter->hasMany(session)
Sessions->hasOne(Review)
Sessions->hasOne(Kids)
Sessions->hasOne(Babysitter)
Sessions->hasOne(Parent)
I want to achieve 2 things:
First one
I want to show this result when listing all babysitters. I'm showing this information for each babysitter:
plsease see this image
See here what I couldn't achieve
plsease see this image
This is my code
Sitters::where('Status', 'active')->where('Verified', 1)->get();
Second one
Also, I've tried to show kids name with parent review as shown here:
plsease see this image
This is what i'm using
Sessions::select('Reviews.*', 'Sessions.Parent_id')->join('Reviews', 'Reviews.Session_id', '=', 'Sessions.id')->with('owner')->where('Trainer_id', session('user')->Id)->where('Status', '=', 'complete')->with('owner')->orderBy('Sessions.id', 'DESC')->get();
Here is Session.php Model
public function owner(){
return $this->belongsTo('App\Models\Parents', 'Parent_id');
}
As discussed change the relations:
Babysitter->hasMany(sesstion)
Sessions->hasOne(Review)
Sessions->belongsTo(Kids)
Sessions->belongsTo(Babysitter)
Sessions->belongsTo(Parent)
First one
in Babysitter.php declare the following attributes
class Babysitter extends Model
{
public function reviews()
{
$this->hasManyThrough(Review::class, Session::class);
}
public function getAverageReviewAttribute()
{
return $this->reviews()->avg('Rating');
}
}
Then you just need to call it on the model instance.
$babysitter = Babysitter::first();
return $babysitter->average_review;
Second one
Just use the relation
$babysitter = BabySitter::with(['sessions' => public function ($session) {
$session->with(['review','parent','kids']);
})->where('trainer_id', '=', session('user')->Id) //did not understand this condition
->first();
This assumes you have parent, kids and review relation declared on Session::class. (change the names if needed)
After a few days of searching & testing, this is what worked for me:
Inside (Sitters) Model, put this relation
public function sessions()
{
return $this->hasMany(Sessions::class, 'sitter_id')
->withCount('reviews')
->withCount(['reviews as review_avg' => function($query){
$query->select(DB::raw('AVG(Rating)'));
}]);
}
Also, inside (Sessions) Model, put this relation
public function reviews()
{
return $this->hasOne(Reviews::class, 'Session_id');
}
Now you query like this
return $sitters = Sitters::with('sessions')->get();
I hope this can help someone :)

How to attach extra data on eagerloaded relationship Laravel

I have this function that eagerloads the posts,
public function getUserPosts()
{
return User::with('posts')->where("organization_id", $this->getOrganization()->id)->get()->toArray();
}
This returns fine the user with posts, my question is can I add some extra data on eagerload something like
public function getUserPosts()
{
return User::with('posts', function(){
//say I fetch an array of posts here,
// I want to attach this array of posts with the eagerloaded posts
})->where("organization_id", $this->getOrganization()->id)->get()->toArray();
}
return User::with(['posts', function($query){
//here you have the query to the relationship, and can do normal query stuff with it
//like this:
$query->with('comments')->select('id', 'title')->where('created_at','>',Carbon::now());
}])->where("organization_id", $this->getOrganization()->id)->get()->toArray();

Resources