Laravel has on where function - php

I'm currently using this function to gather all of my users with a relationship
$users = users::with(array('statusCurrent' => function($query)
{
$query->where('status.status', 'in');
$query->orderBy('status.date', 'DESC');
}));
$users = $users->get();
This returns both of my users, and if status = 'in' then it returns the relationship aswell, but if status = 'out' it still returns the row, but with status_current = null.
Basically I want to ignore the user completely if the arguments inside the with query builder function are not true.
I have tried $candidates = $candidates->has('statusCurrent')->get(); to try and only get results where the relationship is not null, but it still returns users where the StatusCurrent relationship is null.
How do I do it so that foreach of the users, if whatever arguments I pass into the with(array('statusCurrent' => function(){}) are not true, it is ignored completely?
EDIT
Users Model
public function statusCurrent(){
return $this->hasOne('App\Status', 'user_id', 'id')->orderBy('date', 'desc')->limit(1);
}
The user can have many status', but the StatusCurrent relationship is meant to return their 1 most recent status based on the status.date

You need whereHas to filter out users based on their relationship
$users = users::with(array('statusCurrent' => function($query)
{
$query->orderBy('status.date', 'DESC');
}))
->whereHas('statusCurrent', function ($query) {
$query->where('status', 'in');
})
->get();
See Querying Relationship Existence

Related

Get datas from relation table (with()) with a condition

I have an 'implementation' table that contains relationships to retrieve projects and scores.
The scores table contains a" user_id "field.
I would like to collect all the implementations but with only the score which contains the user_id.
My original query.
public function getImplementations($id, $student)
{
$data = Implementation::where('event_id', $id)->where('student_id', $student)->with('project', 'score')->get();
return response()->json($data);
}
My test for get only the score from specific user (only one score per user per implementation, so no conflict possible)
$data = Implementation::where('event_id', $id)
->where('student_id', $student)->with('project', 'score')
->whereHas('score', function ($query) {
$query->where('user_id', Auth::user()->id);
})->get();
But that does not give the expected result. This is not the right method and I do not know the right one.
Thanks for your help
I am not sure if there's a need to eager-load and constrain a relationship simultaneously. Does the following provide you with the expected result?
$data = Implementation::where('event_id', $id)
->with([
'project',
'score' => function ($query) {
$query->where('user_id', Auth::id());
}
])
->where('student_id', $student)
->get();

Eloquent relation clarification

Following is my query
$user = User::with(['session' => function ($query) {
$query->select('id','device_id');
$query->where('api_token', '=', '123456');
}])->get();
session: hasMany relation with User.
I am expecting a user with a session having api_token = 123456. Instead I am getting whole users here. I know I am doing something wrong.
I am referring this doc. In the doc it is saying that we can add constraint to the query. But here $query->where('api_token', '=', '123456'); this where is not working.
You are not filtering the User, you are filtering the result of the eager loading of 'session'. Eager loading does not have any effect on the base result set in anyway.
It sounds like you want to filter User by the 'existence' of a relationship in the database.
User::whereHas('session', function ($q) {
$q->where('api_token', '12345');
})->get(); // ->first();
Get all Users that have a Session where 'api_token' == '12345'.
Laravel 5.5 Docs - Eloquent - Relationships - Querying Relationship Existence
Finally I got it worked.
$sessionSelect = function ($query) {
return $query->select( 'user_id', 'device_id');
};
$detailSelect = function ($query) {
return $query->select('user_id', 'dob', 'gender');
};
$sessionWhere = function ($query) use ($key) {
return $query->where('api_token', $key);
};
$users = User::with(['session' => $sessionSelect,'detail'=>$detailSelect])
->whereHas('session', $sessionWhere)
->first();

Laravel sub query not removing results when using a nested with

I have a 'user' table that has a pivot table for services that a user offers:
// App\User
public function services()
{
return $this->hasMany('App\ServiceUser');
}
On the ServiceUser model I then have another relationship to get the service information:
public function service()
{
return $this->hasOne('App\Service', 'id');
}
When fetching a team (using Laravel Spark) the query I am using is:
Team::with('users')->withUserCustomerServices()->where('id', $teamId)->first();
The scope for this query is in the Team model:
public function scopeWithCustomerServices($query)
{
$query = $query;
$query->with('users.services');
$query->with(['users.services.service' => function($q) {
$q->where('visible_to_customers', 1);
}]);
return $query;
}
When outputting (using Vue.js):
{{ user.services.length }}
I get (in this example) 6 results returned. However, one of the services has a database field 'visible_to_customers' set to 0.
Initially I thought my query would work as expected and only return 5 services however it actually still returns them all, but doesn't return the relationship (service) if the field is 0.
How can I can I only return the pivot table result where the relationship has a certain field value?
EDIT
I have updated the query to use a whereHas on the first nested relation:
$query->with(['users.services' => function($q) {
$q->whereHas('service', function($q) {
$q->where('visible_to_customers', 1);
});
}]);
This works great, only returns the pivot table rows where the services table has a field value of 1 for visible_to_customers.
However, that doesn't fetch the related row itself.
If I then chain on:
$query->with(['users.services' => function($q) {
$q->whereHas('service', function($q) {
$q->where('visible_to_customers', 1);
});
}]);
$query->with(['users.services.service' => function($q) {
$q->where('visible_to_customers', 1);
}]);
It remains the same issue where it fetch all of the rows but then only the related rows where the field is 1.
Fixed this issue by using a where has on the first relationship that is the pivot:
$query->with(['users.services' => function($q) {
$q->whereHas('service', function($q) {
$q->where('visible_to_customers', 1);
})->with('service');
}]);
I then appended the ->with('service') to the end of the chain.

Eloquent Querying pivot table for all users - and also include records where there is no users

I'm querying a table, which finds all tasks assigned to a given user (the one signed in).
I have a pivot table for the tasks/users relation, as more than one user can be assigned to a task. The function below successfully grabs all the tasks the user is assigned too. No issue there.
However, I also want to include tasks that NO users have been assigned to in the function below (in my platform, no users assigned to a task means it's for "everyone").
$user_tasks = Team::currentTeam()->tasks()->with('user', 'comments')->whereHas('user', function($query) {
$query->where('user_id', Auth::user()->id);
})->get();
Probably something like this should work:
$user_tasks = Team::currentTeam()->tasks()->with('user', 'comments')->whereHas('user', function($query) {
$query->where('user_id', Auth::user()->id);
})->doesntHave('user','or')->get();
because there is no function orDoesntHave. There's only:
public function doesntHave($relation, $boolean = 'and', Closure $callback = null)
{
return $this->has($relation, '<', 1, $boolean, $callback);
}
defined, so you need to use doesntHave and specify operator as 2nd argument.
You can get the unassigned tasks separately:
$unassigned_tasks = Task::unassigned()->get(); // Uses a scope that says where user_id is null
And then something like:
$user_tasks->tasks->push($unassigned_tasks);

Laravel / Eloquent : hasManyThrough WHERE

In the documentation of Eloquent it is said that I can pass the keys of a desired relationship to hasManyThrough.
Lets say I have Models named Country, User, Post. A Country model might have many Posts through a Users model. That said I simply could call:
$this->hasManyThrough('Post', 'User', 'country_id', 'user_id');
This is fine so far! But how can I get these posts only for the user with the id of 3 ?
Can anybody help here?
So here it goes:
models: Country has many User has many Post
This allows us to use hasManyThrough like in your question:
// Country model
public function posts()
{
return $this->hasManyThrough('Post', 'User', 'country_id', 'user_id');
}
You want to get posts of a given user for this relation, so:
$country = Country::first();
$country->load(['posts' => function ($q) {
$q->where('user_id', '=', 3);
}]);
// or
$country->load(['posts' => function ($q) {
$q->has('user', function ($q) {
$q->where('users.id', '=', 3);
});
})
$country->posts; // collection of posts related to user with id 3
BUT it will be easier, more readable and more eloquent if you use this instead:
(since it has nothing to do with country when you are looking for the posts of user with id 3)
// User model
public function posts()
{
return $this->hasMany('Post');
}
// then
$user = User::find(3);
// lazy load
$user->load('posts');
// or use dynamic property
$user->posts; // it will load the posts automatically
// or eager load
$user = User::with('posts')->find(3);
$user->posts; // collection of posts for given user
To sum up: hasManyThrough is a way to get nested relation directly, ie. all the posts for given country, but rather not to search for specific through model.
$user_id = 3;
$country = Country::find($country_id);
$country->posts()->where('users.id', '=', $user_id)->get();
$this->hasManyThrough('Post', 'User', 'country_id', 'user_id')->where(column,x);
What happen here is you get the collection in return you can put any condition you want at the end.

Categories