I am working with Laravel 5 and I am having issue getting ->wherePivot()
to work on a Many-to-Many relationship. When I dd()
the SQL it looks like Eloquent is looking for records in the pivot table with a `pose_state`.`pose_id` is null`.
I am hoping it is a simple error and not a bug. Any ideas are appreciated.
Database Structure
pose
id
name
type
state
id
name
machine_name
pose_state
pose_id
state_id
status
Models
Pose
<?php namespace App;
use DB;
use App\State;
use Illuminate\Database\Eloquent\Model;
class Pose extends Model {
public function states()
{
return $this->belongsToMany('App\State')
->withPivot('status_id')
->withTimestamps();
}
public function scopeWithPendingReviews()
{
return $this->states()
->wherePivot('status_id',10);
}
}
State
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class State extends Model {
public function poses()
{
return $this->belongsToMany('Pose')
->withPivot('status_id')
->withTimestamps();
}
}
PosesController function
public function listPosesForReview(){
$poses = Pose::withPendingReviews()->get();
dd($poses->toArray() );
}
SQL
select
`states`.*, `pose_state`.`pose_id` as `pivot_pose_id`,
`pose_state`.`state_id` as `pivot_state_id`,
`pose_state`.`status_id` as `pivot_status_id`,
`pose_state`.`created_at` as `pivot_created_at`,
`pose_state`.`updated_at` as `pivot_updated_at`
from
`states` inner join `pose_state` on `states`.`id` = `pose_state`.`state_id`
where
`pose_state`.`pose_id` is null and `pose_state`.`status_id` = ?
EDIT
When I updated my code to removing the scope it worked. Thanks @Deefour for putting me on the right path! Maybe scope has something else to that I am missing.
public function pendingReviews()
{
return $this->states()
->wherePivot('status_id','=', 10);
}
YET ANOTHER EDIT
I finally got this to work. The solution above was giving me duplicate entries. No idea why this works, but it does, so I will stick with it.
public function scopeWithStatusCode($query, $tag)
{
$query->with(['states' => function($q) use ($tag)
{
$q->wherePivot('status_id','=', $tag);
}])
->whereHas('states',function($q) use ($tag)
{
$q->where('status_id', $tag);
});
}
I think that your implementation of scopes is fine, the problem I see is just a typo. Your schema shows that the field is called
status
but your where condition is referring to astatus_id
Try:
Also, the
withTimestamps()
method is causing issues. You don't have timestamps in your schema for the pivot (as I can see) so you shouldn't be putting these in the your relation definitions as it's trying to fetch the timestamps relating to when the relation was created/updated. You can do this if you set up your pivot table schema to have the timestamp fields, but I think you'll have to do some custom work to get the timestamps to save properly.I think your implementation of
scopeWithPendingReviews()
is an abuse of the intended use of scopes.That aside, I believe you're not using
wherePivot()
properly. According to the source, the method signature isbut you're treating it as
This means
should be
Responding to Comments
A scope should be thought of as a reusable set of conditions to append to an existing query, even if that query is simply
The idea is that a pre-existing query would be further refined (read: 'scoped') by the conditions within the scope method, not to generate a new query, and definitely not to generate a new query based on an associated model.
By default, the first and only argument passed to a scope method is the query builder instance itself.
Your scope implementation on your
Pose
model was really a query against thestates
table as soon as you did thisThis is why your SQL appears as it does. It's also a clear indicator you're misusing scopes. A scope might instead look like this
Unlike your new
pendingReviews()
method which is returning a query based on theState
model, this scope will refine a query on thePose
model.Now you can use your scope as you originally intended.
which could be translated into the more verbose
Notice also the scope above doesn't return a value. It's accepting the existing query builder object and adding onto it.
The other answer to this question is filled with misinformation.
wherePivot()
as is claims.withTimestamps()
is not at all related to your problemwithTimestamps()
call as you did is all that is needed. Just make sure you have acreated_at
andupdated_at
column in your join table.This worked for me (Laravel 5.3):
You can also have this problem (return no results) if the column you are using in
wherePivot
hasn't been added towithPivot
.