【问题标题】:如何获得过滤的 Laravel 关系模型?
【发布时间】:2022-01-23 16:43:00
【问题描述】:

在 Laravel 8.0 中是否有可能获得过滤的关系模型?

示例:在我拥有的控制器中

 $thread = Thread::find(1);

 // example logic between getting the thread and passing to JsonResponse
 $thread->messages = $thread->messages->filter(function (Message $message) {
     return $message->type_id === 3;
 });

 return new JsonResponse($thread);

感谢致电$thread->messages 我在响应中延迟加载消息,但它延迟加载属于该线程的所有消息,我只想获得过滤的消息。 我怎样才能做到这一点?

线程模型

public function messages(): HasMany
{
    return $this->hasMany(Message::class);
}

消息模型

public function type(): HasOne
{
    return $this->hasOne(MessageType::class, 'id', 'type_id');
}

【问题讨论】:

  • 在这里使用范围可能也很有趣:laravel.com/docs/8.x/eloquent#query-scopes
  • @PeterKrebs 你会怎么做?在文档中,我只能看到从同一模型声明和调用范围的示例(在 User 模型中声明了 scopePopular 方法,然后是 User::popular()->get())。就我而言,我有 Thread 模型,但范围将在 Message 模型中声明。
  • 我找到了这个教程。检查“范围与关系”部分:medium.com/@janaksan_/using-scope-with-laravel-7c80dd6a2c3d
  • 本教程展示了如何分别获取 $category 和 $activePosts,但我需要加载 $activePosts 的 $category
  • 您可以使用参数调用作用域,这将有助于减少重复代码。只是一个想法,我没有时间给出完整的答案。

标签: laravel


【解决方案1】:

您可以将闭包传递给load 方法以延迟加载它们。

$thread = Thread::find(1);

$thread->load(['messages' => function ($message) {
    return $message->where('type_id', 3);
}]);

return new JsonResponse($thread);

或使用with 方法执行相同操作。

$thread = Thread::with(['messages' => function ($message) {
    return $message->where('type_id', 3);
}])->find(1);

return new JsonResponse($thread);

简写闭包(PHP 版本 >= 7.4)

$thread = Thread::with(['messages' => fn ($m) => $m->where('type_id', 3)])->find(1);
$thread = Thread::find(1);

$thread->load(['messages' => fn ($m) => $m->where('type_id', 3)]);

分离关系

# Thread model
// or whatever name makes sense in your application
public function active_messages() 
{
    return $this->hasMany(Message::class)->where('type_id', 3);
}
$thread = Thread::with('active_messages')->find(1);
$thread = Thread::find(1);

$thread->load('active_messages');

在查询方面,所有选项都是一样的。

【讨论】:

  • 由于 PHP 7 已停产,因此使用如下箭头函数会更简洁 (IMO):$thread->load(['messages' => fn ($message) => $message->where('type_id', 3)]);
  • 是的。但是你会惊讶有多少地方还在使用 php5 :(
  • @IGP 感谢您的回答。有用!这是否意味着在我需要过滤这些消息的每个地方都需要通过闭包?有没有办法避免重复代码?
  • 如果您发现自己必须一遍又一遍地应用相同的过滤器,您可以让它成为自己的关系 (return $this->hasMany(Message::class)->where('type_id', 3);.),然后懒惰/急切地加载它。另一种选择是使用 miken32 建议的简写闭包。我个人更喜欢闭包/短闭包。重复没什么大不了的。
  • 我已经添加了示例
【解决方案2】:

您可以传递一个函数,在该函数中,您将在像这样与线程相关的急切加载器消息之前执行一些检查

Thread::with(["messages" => function($query){
    $query->where("type_id", 3);
})->find(1);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-23
    • 2017-07-07
    • 2018-02-16
    • 2020-05-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    相关资源
    最近更新 更多