Laravel > nested eager load with restriction - laravel

Assumed we've got users, friends and restaurants. Don't want to go to deep into the Model and relationship setup.
While me as a user is logged in: How can I get all friends who are "customers" of the restaurant?
I've got this and it's already working:
$friends = array_dot(Auth::user()->friends()->select('users.id')->get());
$customers = Restaurant::with(['users' => function($query) use($friends) {
$query->whereIn('users.id', $friends);
}])->find(restaurant_id);
But is this even possible with a single query?

It sounds like you want to find all of your friends that have a relationship to the restaurant. If so, you're looking for whereHas(). General idea:
$restaurantId = 1;
$user = Auth::user();
$friendCustomers = $user->friends()->whereHas('restaurant', function ($query) use ($restaurantId) {
$query->where('id', $restaurant_id);
})->get();
You can read more about querying relations, and whereHas, here.

Related

Laravel eloquet check non existing many to many relation

I'm having trouble to write query in laravel eloquent ORM.
I have a proyect table, where you can assign users, in a many to many relationship
In the view to asign users, I have a selector, but I want to show only the users not already assigned to the proyect and checking also that the user belongs to the company that created the proyect (user.company_id=proyect_id)
In a normal query should me something like this, having $company_id and $proyect_id from the controller.
select * from users u left join proyect_user pu on u.id=pu.user_id and
pu.proyect_id = $proyect_id where u.company_id=$company_i and
proyect_id is null;
The query works, but I would like to use Eloquent. ¿Any idea how to do it?
It depends on how you declared the relationship in the User model. But I would do something like this:
$users = User::whereHas('company', function ($query) use ($companyId) {
$query->where('id', $companyId)
})->whereDoesntHave('proyects', function ($query) use ($proyectId) {
$query->where('id', $proyectId);
})->get();

Refactor whereHas to use via global scopes in Laravel

I've 2 models, CoreChallenge and Challenge. Below are relations between table.
I want to fetch Challenges which has core_challenges active. I tried to do putting global scope in CoreChallenge model, but when I'm getting null in relationship when Corechallenge is inactive.
I've done it this way
$challenges = Challenge::with('core_challenge')->whereHas('core_challenge', function($q){
$q->where('status', '=', 'active');
})->get();
I want to do it using global scopes
Global scope on CoreChallenge gives me null, but I want that it's parent (Challenge) should not load even, like in whereHas. Is there any way?
I have stumbled to the same approach, but when the table got bigger (core_challenges_table in your scenario), whereHas ended up being very slow (around 1min response time).
So I used a solution like this:
$ids = CoreChallenge::where('status', 'active')->pluck('id');
$challenges = Challenge::with('core_challenges')
->whereIn('core_challenge_id', $ids)
->get();
With this approach, my query reduced to 600~ms from 1min.
Which can be translated to Model scopes
class Challenge {
public function scopeActive($query) {
$activeIds = CoreChallenge::where('status', 'active')->pluck('id');
return $query->whereIn('core_challenge_id', $ids);
}
}
Challenge::with('core_challenges')->active()->get();

Where clause inside whereHas being ignored in Eloquent

Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.

Laravel Eloquent: Get current id from inner function

I know, we can do this in the controller:
User::with('post')->get();
It will get every user's post from the database, based on users.id.
But the problem is, I want to do this:
User::with(['post' => function($query) {
# Throw users.id here...
}])->get();
How to do that?
You should get the users first, and then load related posts with a separate query and merge them manually.
$users = User::get();
$posts = Post::whereIn('user_id', $users->pluck('id'))->get(); // Get your additional data in this query
$users->each(function ($user) use ($posts)
{
$user->posts = $posts->where('user_id', $user->id);
});
Note: I did not test the code above. It's just an example to show you how to accomplish what you are trying to do.

Laravel database relations - get all children from more than one parent

I have users and books.
User model:
public function books() {
return $this->hasMany('Books');
}
I can do the following:
$user = User::find(1);
$books = $user->books;
Now, I want to get all books from several users with the name Brian.
So what I did is:
$users = User::where('name', 'Brian')->get();
$books = $users->books;
Of course this does not work because books() is a method of a user and not of a group of users.
How can I can all books from all users named Brian? I could loop through all Brians but that does not seem best practice.
How could I do this?
This is the perfect spot for a whereHas call:
Give books a user relationship, then simply do:
Book::whereHas('user', function($q) {
$q->whereName('Brian');
})->get();

Resources