Laravel 5.2热切负载关系与汇总计算

时间:2016-04-23 07:32:30

标签: php eloquent laravel-5.2

我正在开发一个简单的任务应用程序。我想急切加载每个项目花费的总时间。我有两张桌子:

Table: task_project 
id, client_id, name, description

Table: task_entries
id, task_project_id, start_time, end_time

表之间的关系是通过task_project.id = task_entries.task_project_id确定的。

对于表task_project中的每个项目,我们会在task_entries中跟踪每项任务的时间。我创建了一个名为elapsed的方法来处理这个问题。

因此,在我的模型TaskProject中,我与taskselapsed建立了关系:

public function tasks()
{
    return $this->hasMany(TaskEntry::class, 'task_project_id');
}

public function elapsed()
{
    return $this->hasOne(TaskEntry::class, 'task_project_id')
        ->selectRaw('time_format(SUM(timediff(task_end_time, task_start_time)), "%H:%m:%s") AS hours')
        ->groupBy('task_entries.task_project_id');
}

然后在我的控制器中,我将其称为:

$tasks = TaskProject::with('elapsed')->paginate(15);

但是elapsed的关系是每个项目行的空值。

我想最终能够通过使用以下方式在我的刀片模板中访问此值:hh:mm:ss:

$task->elapsed->hours

感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

这是一个有趣的方法。我之前遇到过如何从Eloquent获取聚合列表的问题。这是我能够提出的最好的。

class TaskEntry
{
    public static function addElapsedTo($tasks)
    {
        $ids = $tasks->pluck('id');
        $placeholders = trim(str_repeat('?,', count($ids)), ',');

        $times = DB::select('
            SELECT 
                task_project_id,
                TIME_FORMAT(
                    SUM(TIMEDIFF(task_end_time, task_start_time)),
                    "%H:%m:%s"
                ) AS hours
            FROM task_entries
            WHERE task_project_id IN ('.$placeholders.')
            GROUP BY task_project_id
        ', $ids);

        $times = collect($times)->groupBy('task_project_id');

        foreach ($tasks as $task)
        {
            $task->setAttribute('elapsed', $times[$task->task_project_id]['hours']);
        }
        return $tasks;
    }
}

然后你可以像这样使用它。

$tasks = TaskProject::paginate(15);
$tasks = TaskEntry::addElapsedTo($tasks);

$task->elapsed包含已用时数值。

这样您就可以执行两个数据库查询而不是一个。但是你仍然避免对每个结果执行查询。

这样的方法对我来说效果很好。虽然感觉有点笨拙。我希望找到一个更好的方法。