我正在尝试在查询生成器中使用 Laravel each 方法,但我在 every 方法中添加的属性不会保留到集合中。当我在每个方法中
dd($task);
时,我的属性确实会显示。
$projects =
Project::with(['tasks' => function($query) {
$query
->whereBetween('start_date', ['2024-04-21', '2024-04-28'])
->orWhereBetween('end_date', ['2024-04-21', '2024-04-28'])
->each(function($task, $key) {
//if statements here
$task->test = 'test';
$task->setAttribute('date', $task->end_date);
// dd($task); <- this returns the 'test' and 'date' attributes above
});
}])
->status(['Active', 'Scheduled'])->sortByDesc('last_status.start_date');
// dd($projects->first()->tasks->first()); <- this is missing the 'test' and 'date' attributes from above
TL;博士
您不能在
each
中使用 with
,因为它实际上并未返回模型,它只是使用查询并稍后组合数据。
跳至下面的解决方法部分以获取潜在的解决方案。
“与”如何运作
Eloquent 使用
with
允许嵌套关系作为层次结构返回。这与 join
查询不同,其中两个模型的属性都作为包含所有属性的一个对象返回
在幕后,Eloquent 对每个
with
关系执行单独的查询,然后在返回结果之前在内存中构建对象层次结构。
在你的情况下会有一个
select *
from projects
随后
select *
from tasks
where project_id in (1,2,3 ...) -- all the project.id values
and ... -- your additional where clauses
然后使用任务对象中的外键将
projects
集合与其相关的 tasks
合并。
按照合同,
each
是一个回调,应用于查询执行后返回的所有模型。通过在 each
内的查询上使用
with
,它会强制 Eloquent 立即执行它并返回查询以供以后执行;但在构建对象层次结构时似乎忽略了
each
。在我的本地项目上进行测试时,我看到第二个查询 -
with
闭包内的查询 - 执行了两次,尽管只需要一次即可获取与
tasks
关联的所有
project
。
解决方法
要向task
模型添加属性,您可以执行单独的查询并组合结果。
// Get all the projects
$projects = Project::all();
// Get tasks for these projects
$projectIds = $projects->pluck('id');
// Add attributes to the task
$tasks = Task::whereIn('project_id', $projectIds)->get()->each(function ($task) {
$task->test = 'test';
})->groupBy('project_id');
// Combine projects and tasks
foreach ($projects as $project) {
$project->tasks = $tasks[$project->id] ?? collect();
}