首页 > 解决方案 > 使用联合时,雄辩的查询返回错误的数据

问题描述

我的代码中有公共数据和用户特定数据之间的联合。我想要实现的是,如果没有用户登录,我返回 public 为 true 的数据。如果我有一个用户,我会进行另一个查询,其中 user_id 是登录用户。一切正常,直到我想获得我不应该被允许的用户的特定数据 ID。

例如我有数据:

[
   'id' => 1,
   'user_id' => 1,
   'public' => true,
],
[
   'id' => 2,
   'user_id' => 1,
   'public' => false,
],

我当前的代码:

    public function getQuery() : Builder
    {
      $publicData = $this->model->where('public', true);

      // $this->user is passed thought another method which is $request->user() result. 
      if (!isset($this->user)) {
        return $publicData;
      }

      if ($this->user->isAdmin()) {
        return $this->model->newQuery();
      }

      return $this->model
        ->where('user_id', $this->user->id)
        ->union($publicData);
    }

现在我们假设 $this->user->id 为 10,我尝试获取 id 不允许的数据。

    $data = $this->getQuery()
        ->where('id', 2)
        ->first();

在这种情况下,总是会返回第一个公共数据,在这种情况下是 id 1,我希望收到 null。

我不确定如何为此找到解决方案,也不确定我错过了什么。目前我使用 Laravel 6

标签: phplaraveleloquent

解决方案


您的代码中的潜在问题,它使用一个查询来进行联合和结果查询。

您可以尝试检查:

public function getQuery() : Builder
{
  // HERE ADDED newQuery
  $publicData = $this->model->newQuery()->where('public', true);

  // $this->user is passed thought another method which is $request->user() result. 
  if (!isset($this->user)) {
    return $publicData;
  }

  if ($this->user->isAdmin()) {
    return $this->model->newQuery();
  }

  return $this->model
    ->where('user_id', $this->user->id)
    ->union($publicData);
}

但是您建议简化查询,而不使用联合,因为这里不需要联合,例如:

public function getQuery() : Builder
{
  $query = $this->model->newQuery();

  if ($this->user->isAdmin()) {
    return $query;
  }

  return $query->where(function ($builder) {
    $builder->where('public', true);

    if (isset($this->user)) {
       $builder->orWhere('user_id', $this->user->id);
    }
  });
}

推荐阅读