How to use where conditional in with Laravel? - laravel

I do request using query:
return Baber::where(function ($query) use ($request) {
// HERE CONDITION WHERE FOR USER TABLE
})->with("user")->orderBy('id', 'desc')->get();
How can I use where() inside query, that it will be comparabled with user table in with("user")?
I mean the following:
return Baber::where(function ($query) use ($request) {
$query->where('user.created_at', $request->date);
})->with("user")->orderBy('id', 'desc')->get();

It's known as constraining eager loads.
Baber::with(['user' => function ($query) use ($request) {
$query->where('user.created_at', '=', $request->date);
}])
->orderBy('id', 'desc')
->get();

Related

Laravel Eloquent making select on whereHas()

How can I select on whereHas() some columns in relation.
My current query looks like as it follows
Location::select(['title'])
->withCount(['job' => function($q) {
return $q->where('language_id', 1)->whereNull('deleted_at');
}])->whereHas('country', function ($q) {
return $q->where('id', '=', 80);
})->get();
and I tried
Location::select(['title', 'id as value'])->withCount(['job' => function($q) {
return $q->where('language_id', 1)->whereNull('deleted_at');
}])->whereHas('country', function ($q) {
return $q->select('title', 'iso3')->where('id', '=', 80);
})->get();
but nothing is getting returned on country relation. How do I refactor this query to get it work?
whereHas() doesn't eager load the relation, only filters results based on it. To eager load, use with().
Location::with('country:id,title,iso3')
->select(['title', 'id as value', 'country_id'])
->withCount(['job' => function($q) {
$q->where('language_id', 1)->whereNull('deleted_at');
}])
->whereHas('country', function ($q) {
$q->where('id', '=', 80);
})->get();

Laravel 5.8: orWhere anulls the whereHas effect

I'm trying to do a simple search function. For that, I implemented the following query:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where('username', 'LIKE', "%{$search}%")
->paginate(20);
The whereHas selects the profiles that the user with $id has.
Then, with the where we figure out if the search match with some username in the database.
Finally, we paginate the results.
All right so far.
The problem comes when I add a orWhere like that:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where('username', 'LIKE', "%{$search}%")
->orWhere('fullname', 'LIKE', "%{$search}%")
->paginate(20);
I want that the query analyses if the search matchs with the username and/or the fullname. When I add the orWhere works, but the whereHas doesn't do its work and the results are from all the users.
You need to do it like this:
Profile::whereHas('accounts', function ($query) use ($id) {
$query->where('user_id', $id);
})
->where(function($query) use ($search) {
$query->where('username', 'LIKE', "%{$search}%")
->orWhere('fullname', 'LIKE', "%{$search}%");
})
->paginate(20);

Orderby Desc in Eloquent, Laravel

I have a query 3 tables are joined together, I want to order the results in Descending order from created_at in messages table, please help. Thank you.
controller:
return new AllChats(Chat::latest('created_at')->whereHas('messages')->with(['messages.users', 'users' =>
function ($query) {
$query->where('id', '!=', Auth::id());
}])->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
Display the results in desc order but from messages.created_at??
You need to just add the ->orderBy on your created at field in your query.
return new AllChats(Chat::latest('created_at')->whereHas('messages')->with(['messages.users',
'users' => function ($query) {
$query->where('id', '!=', Auth::id());
}])
->orderBy('created_at', 'desc')
->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
Reference: https://laravel.com/docs/5.7/eloquent
use like this
return new AllChats(Chat::latest('created_at')>>whereHas('messages',function($q){
$q->orderBy('created_at', 'desc');
})->with(['messages.users', 'users' =>
function ($query) {
$query->where('id', '!=', Auth::id());
}])->whereHas('users', function ($query) {
$query->where('id', '=', Auth::id());
})->get());
You can use a modified withCount():
$chats = Chat::withCount(['messages as latest_message' => function($query) {
$query->select(DB::raw('max(created_at)'));
}])
->orderByDesc('latest_message')
[...]
->get();

Constrain which relationship models are returned on whereHas

An example from the documentation:
$posts = App\Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
This will look for posts that has at least one comment with foo. It will return the post model with all comments. Is there a way to restrict this to return post model and related comments that only have foo?
I'm aware we can loop through $posts with a conditional later on but I'm looking for a solution via the query builder if possible.
From the docs:
https://laravel.com/docs/5.7/eloquent-relationships#constraining-eager-loads
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
Edit, the other answer is correct.. you should add it to you actual query, not just replace it as i suggested first:
So, from your example it would look like this:
$posts = App\Post::with('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
You could also just add a lazy loading after your query
$posts->load(['comments' => function ($query) {
$query->where('content', 'like', 'foo%');
}]);
Edit, solution suggested by #HelenChe (original asker), it's basically the same, useful if with and wherehas are going to have the same filter function.
$posts = Post::whereHas('comments', $filter = function ($query) {
$query->where('content', 'like', 'foo%');
})->with(['comments' => $filter])->get();
If you want only the posts that has at least one comment with foo with those comments. you have to combine these two function, whereHas() and with()
$posts = App\Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
->with('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();

How to use whereHas for ignoring empty array in eager loading

I don't know how to ignore empty array values in my case. In my query I'm eager loading messages, but it gives me
messages => []
with my query when deleted_from_sender is set to 1 (but I want to ignore it for pagination)
static::with(['messages' => function ($q) use ($id) {
return $q->where(function ($q) use ($id) {
$q->where('user_id', $id)
->where('deleted_from_sender', 0);
})
->orWhere(function ($q) use ($id) {
$q->where('user_id', '!=', $id);
$q->where('deleted_from_receiver', 0);
})->latest();
}])->get();
I tried has and whereHas with the same query and whereNotNull, but no luck.

Resources