Laravel 5与wherePivot有关

who*_*boy 5 php laravel eloquent laravel-5

我正在与Laravel 5合作,我遇到了解决->wherePivot()多对多关系的问题.当我dd()使用SQL时,它看起来像Eloquent正在使用`pose_state`来查找数据透视表中的记录.`pose_id`为null`.

我希望这是一个简单的错误,而不是一个错误.任何想法都表示赞赏.

数据库结构

提出

id
name
type
Run Code Online (Sandbox Code Playgroud)

id
name
machine_name
Run Code Online (Sandbox Code Playgroud)

pose_state

pose_id
state_id
status
Run Code Online (Sandbox Code Playgroud)

楷模

提出

<?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);
  }
}
Run Code Online (Sandbox Code Playgroud)

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class State extends Model {

    public function poses()
    {
      return $this->belongsToMany('Pose')
                  ->withPivot('status_id')
                  ->withTimestamps();
    }

}
Run Code Online (Sandbox Code Playgroud)

PosesController功能

public function listPosesForReview(){
    $poses = Pose::withPendingReviews()->get();
    dd($poses->toArray() );
}
Run Code Online (Sandbox Code Playgroud)

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` = ?
Run Code Online (Sandbox Code Playgroud)

编辑

当我更新我的代码以删除其工作的范围.感谢@Deefour让我走上了正确的道路!也许范围还有其他我想念的东西.

public function pendingReviews()
{
  return $this->states()
              ->wherePivot('status_id','=', 10);
}
Run Code Online (Sandbox Code Playgroud)

再来一次编辑

我终于开始工作了.上面的解决方案给了我重复的条目.不知道为什么会这样,但确实如此,所以我会坚持下去.

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);
            });
}
Run Code Online (Sandbox Code Playgroud)

dee*_*our 3

我认为您的实现scopeWithPendingReviews()是对范围的预期用途的滥用。

范围应被视为附加到现有查询的可重用条件集,即使该查询只是简单的

SomeModel::newQuery()
Run Code Online (Sandbox Code Playgroud)

这个想法是,预先存在的查询将通过范围方法内的条件进一步细化(读取:“范围”),而不是生成新查询,并且绝对不会基于关联模型生成新查询。

默认情况下,传递给范围方法的第一个也是唯一的参数是查询构建器实例本身。

一旦您执行此操作,您Pose模型上的作用域实现实际上就是对表的查询states

$this->states()
Run Code Online (Sandbox Code Playgroud)

这就是您的 SQL 出现的原因。这也清楚地表明您滥用了范围。范围可能看起来像这样

public function scopeWithPendingReviews($query) {
  $query->join('pose_state', 'poses.id', '=', 'pose_state.pose.id')
        ->where('status_id', 10);
}
Run Code Online (Sandbox Code Playgroud)

pendingReviews()与基于模型返回查询的新方法不同State,此范围将优化模型上的查询Pose

现在您可以按照最初的预期使用示波器。

$poses = Pose::withPendingReviews();
Run Code Online (Sandbox Code Playgroud)

这可以翻译成更详细的

$poses = Pose::newQuery()->withPendingReviews();
Run Code Online (Sandbox Code Playgroud)

另请注意,上面的范围不返回值。它接受现有的查询构建器对象并添加到其中。

这个问题的另一个答案充满了错误信息。

  1. 您不能按wherePivot()原样使用声明。
  2. 您的使用withTimestamps()与您的问题完全无关
  3. 您无需执行任何“自定义工作”即可使时间戳发挥作用。withTimestamps()只需像您一样添加呼叫即可。只需确保连接表中有一个created_atand列即可。updated_at