WhereBetween on many-to-many relationships - laravel

in my sensory model i have this query helper method
public function asAroma()
{
return $this->belongsToMany('App\SensoryEvaluationForm')->wherePivot('sensory_type', '=', 2);
}
How can I add a query to this?
I am using it like this
$cs = App\Sensory::first();
$cs->asAroma()->whereBetween('created_at', [$startingDate, $endingDate])->get();
It returns nothing. I think there is a different way on building queries with relationships?
What I'm trying to do is to add a wherebetween filter to the resulting relationship.

Use whereHas() and pass a callback to it.
CsModel::with('asAroma')->whereHas('asAroma', function($query) use ($start, $end) {
$query->whereBetween('created_at', [$start, $end]);
})->get();

I already found an answer, it seems I need to specify the table name of the created_at attribute I want to refer to in this case sensory_evaluation_forms.created_at

Related

Eloquent: How to combine eager loading and filter by pivot?

I have a many-to-many relationship between models. For a given model instance, I know how to filter the related models according to the value of a pivot. For example, in the case of users and roles, I would use:
User->roles()->wherePivot('admin',1);
Similarly, I know how to eager load all roles for a set of users:
User::where('active',1)->with('roles')->get();
What I am trying to do is combine these two concepts. For example, how do I retrieve a set of users with their eagerly loaded roles, where the users are filtered according to a field on the pivot?
I realise I can do this easily enough with raw SQL, but I would prefer to use Eloquent if possible.
You can restrict your eager loaded relations using a closure.
$users = User::with(['roles' => function ($query) {
return $query->wherePivot('admin', 1);
}])
->where('active', 1)
->get();
You can also query relations using whereHas.
$users = User::with('roles')
->whereHas('roles', function ($query) {
return $query->wherePivot('admin', 1);
})
->where('active', 1)
->get();
Pass a closure in to with when eager loading to add clauses to the query:
User::with(['roles' => function ($query) {
$query->where('admin', 1);
}])->where('active', 1)->get();

How to use where by second table Laravel?

I have the following query:
$objects = Object::with("prototypes");
As you can see I do request to model Object and join it with prototypes.
The prototypes table has structure:
prototype_id
name
How to make where in above query like as:
$objects = Object::with("prototypes")->where("prototype_id", 3);
Object model:
public function prototypes()
{
return $this->belongsToMany('App\Prototype', 'object_prototype', 'object_id');
}
Prototype model:
public function objects(){
return $this->belongsToMany("App\Object", "object_prototype", "prototype_id", "object_id");
}
If the relationship is correctly set in your Eloquent models, you can use the WhereHas function to query relationship existence.
$objects = Object::with('prototypes')
->whereHas('prototypes', function ($query) {
$query->where('prototype_id', 3);
})
->get();
Just to add on #Jerodev answer.
If you need even more power, you may use the whereHas and
orWhereHas methods to put "where" conditions on your has queries.
These methods allow you to add customized constraints to a
relationship constraint, such as checking the content of a comment:
// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
You can read more about Eloquent Relationships
And in your case you can also construct a your query like.
Object::whereHas('prototypes', function ($query)){
$query->where('prototype_id', 3);
})->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: how to get related records via whereHas() method?

For example, I can check every post with concrete date.
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
But suppose, what to do, if I want to compare a post model date (created_at) with the date attribute of user model?
For example:
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', ** $user->customDate ** ← look this);
})->get();
upd.
I use Eloquent outside of Laravel.
You can use a raw expression on the Eloquent sub query, by using $q->whereRaw.
In your example:
$users = User::whereHas('posts', function($q){
$q->whereRaw("created_at >= users.customDate");
})->get();
Unlike DB::raw, this can be used without Laravel's dependency injection of Illuminate\Database facade.
Assuming that your users table is just called users you can use DB::raw() to reference a value like you would in a normal query:
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', DB::raw('users.customDate'));
})->get();
Don't forget to either import the DB facade or just change it to \DB::raw(...).
If you're using this outside of Laravel and don't have facades you can cut out the middleman and do:
$q->where('created_at', '>=', new Illuminate\Database\Query\Expression(('users.customDate'));
Hope this helps!

Eloquent filter on pivot table created_at

I want to filter the contents of two tables which have an Eloquent belongsToMany() to each other based on the created_at column in the pivot table that joins them. Based on this SO question I came up with the following:
$data = ModelA::with(['ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
}])->get();
Here I'm using a simple test column to check if it's working, this should be 'created_at'.
What happens though is that I get all the instances of ModelA with the ModelB information if it fits the criteria in the wherePivot(). This makes sense because it's exactly what I'm telling it to do.
My question is how do I limit the results returned based on only the single column in the pivot table? Specifically, I want to get all instances of ModelA and ModelB that were linked after a specific date.
OK, here it goes, since the other answer is still wrong.
First off, wherePivot won't work in whereHas closure. It's BelongsToManys method and works only on the relation object (so it works when eager loading).
$data = ModelA::with(['relation' => function ($q) use ($someDate) {
$q->wherePivot('created_at', '>', $someDate);
// or
// $q->where('pivot_table.created_at', '>', $someDate);
// or if the relation defines withPivot('created_at')
// $q->where('pivot_created_at', '>', $someDate);
}])->whereHas('ModelB', function ($q) use ($someDate) {
// wherePivot won't work here, so:
$q->where('pivot_table.created_at', '>', $someDate);
})->get();
You are using Eager Loading Constraints, which constrain only, like you said, the results of the related table.
What you want to use is whereHas:
$data = ModelA::whereHas('ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
})->get();
Be aware that ModelB here refers to the name of the relationship.

Resources