【问题标题】:Can you filter data on a retrieved relationship without creating a new attribute?您可以在不创建新属性的情况下过滤检索到的关系上的数据吗?
【发布时间】:2019-02-11 19:49:50
【问题描述】:

我在usersposts 之间有one to many 关系。

我想知道我是否渴望在帖子中加载,是否可以在不在 User 模型上创建新属性的情况下修改集合。

$user = User::with('posts')->get();

// Filter the posts on the user using business logic.
// Below is an example. I DO NOT want to do this logic in the db/query builder.

// Arbitrary business rule that is not easily possible to calculate in DB
$shouldGetTestPost = true;

$user->posts = $user->posts->filter(function($post) use ($shouldGetTestPost) {
    if ($shouldGetTestPost && $post->name = 'test') {
        return true;
    }

    return false;
});

dd($user);

如果我运行上面的代码,laravel 将创建一个名为 posts 的新属性并将集合分配给该属性,而不是修改关系。

例如

// I've removed irrelevant model data
App\User {#1145
  #table: "users"
  #attributes: array:6 [
    "id" => 1
    "email" => "test@test.com"
    "password" => "secret"
    "updated_at" => "2019-02-11 18:56:35"
    "created_at" => "2019-02-11 18:56:35"
    // Below is new
    "posts" => Illuminate\Database\Eloquent\Collection {#1217
      #items: array:1 [
        0 => App\Post {#1269
          #table: "posts"
          #attributes: array:24 [
            "id" => 1
            "name" => 'test'
            "user_id" => 1
          ]
        }
      ]
    }
  ]
  #original: array:5 [...]
  #relations: array:1 [
    "posts" => Illuminate\Database\Eloquent\Collection {#1264
      #items: array:2 [
        0 => App\Post {#1269}
        1 => App\Post {#1234
          #table: "posts"
          #attributes: array:24 [
            "id" => 1
            "name" => 'test'
            "user_id" => 1
          ]
        }
      ]
    }
  ]
]

发生的另一件有趣的事情是,在#relations 中,数据已从items 数组中删除,但引用仍然存在。见0 => App\Post {#1269}

这是为 laravel 设计的吗?我知道 laravel 将属性优先于关系,但它不会改变关系数组似乎很奇怪。

如何只更改关系集合而不创建新属性?

【问题讨论】:

  • 为什么要更改加载的关系数组?您能否描述您的实际问题而不是您尝试的解决方案,这样我们这里就没有 XY 问题。
  • @Devon 是业务逻辑原因,没有存入数据库。
  • 这不是一个描述性很强的答案。为什么不将条件添加到关系方法或限制急切加载,而不是加载所有数据并随后对其进行过滤?
  • 与您在检索数据后将逻辑应用于集合的原因相同。我将更改代码以澄清。
  • 更新了我的代码以澄清。

标签: php laravel


【解决方案1】:

setRelation 方法可用于覆盖关系中存储的内容。

$model->setRelation($relation, $value) 

https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_setRelation

但是,这在极少数情况下会有用,所以我仍然认为这是一个 XY 问题。您可以通过将闭包作为第二个参数传递给with() 来进行constrain the eager loading 查询,这将是有条件地检索相关项目的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-09
    • 2020-04-04
    • 1970-01-01
    • 2015-11-18
    • 2013-09-10
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    相关资源
    最近更新 更多