Laravel 5与wherePivot有关

时间:2015-04-10 00:35:38

标签: php laravel eloquent laravel-5

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

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

数据库结构

姿势

id
name
type

状态

id
name
machine_name

pose_state

pose_id
state_id
status

模型

姿

<?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);
  }
}

国家

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class State extends Model {

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

}

PosesController功能

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` = ?

修改

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

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

另一个编辑

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

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);
            });
}

4 个答案:

答案 0 :(得分:2)

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

除此之外,我相信您并没有正确使用wherePivot()。根据 the source ,方法签名为

public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')

但你将其视为

public function wherePivot($column, $value = null, $boolean = 'and')

这意味着

->wherePivot('status_id',10)

应该是

->wherePivot('status_id', '=', 10)

回应评论

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

SomeModel::newQuery()

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

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

您的Pose模型上的范围实施实际上只是在您执行此操作后对states表进行查询

$this->states()

这就是你的SQL出现的原因。它也是一个明确的指标,你滥用范围。范围可能看起来像这样

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

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

现在您可以按原定使用范围。

$poses = Pose::withPendingReviews();

可以翻译成更详细的

$poses = Pose::newQuery()->withPendingReviews();

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

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

  1. 您不能像声明那样使用wherePivot()
  2. 您对withTimestamps()的使用与您的问题完全无关
  3. 你不必做任何&#34;定制工作&#34;让时间戳工作。只需添加withTimestamps()调用就可以了。只需确保您的联接表中有created_atupdated_at列。

答案 1 :(得分:2)

我认为你的范围实现很好,我看到的问题只是一个错字。您的架构显示该字段名为status,但您的where条件是指status_id

尝试:

->wherePivot('status', 10);

此外,withTimestamps()方法导致问题。您的模式中没有时间戳用于数据透视表(我可以看到),因此您不应将这些时间戳放在关系定义中,因为它正在尝试获取与创建/更新关系时相关的时间戳。如果您将数据透视表模式设置为具有时间戳字段,则可以执行此操作,但我认为您必须执行一些自定义工作才能使时间戳正确保存。

答案 2 :(得分:1)

这对我有用(Laravel 5.3):

$task = App\Models\PricingTask::find(1);
$task->products()->wherePivot('taggable_type', 'product')->get();

答案 3 :(得分:0)

如果您在wherePivot中使用的列尚未添加到withPivot,您也可能会遇到此问题(不返回任何结果)。