首页 > 解决方案 > Laravel 渴望加载与基于父级的条件的关系

问题描述

我有这个查询来列出所有用户及其对应关系。

用户有很多任务
每个任务有很多工作时间,这些工作时间可以有不同的用户

即,每个任务可以由不同的用户共享,因此他们对每个任务都有单独的工作时间。

我试过下面的代码

$users = User::select('users.id', 'users.first_name', 'users.last_name', 'users.contract_type')
    ->with([
        'tasks' => function($query) use ($from, $to){
            $query->whereBetween('date', [$from, $to])
                ->select('tasks.id', 'tasks.date');
        },
        'tasks.worktimes' => function($query) {
            //$query->where('user_id', ?)
            $query->withCount([
                    'tags as late_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 1);
                    },
                    'tags as early_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 2);
                    },
                    'tags as others_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 3);
                    }
                ]
            );
        }
     ])
     ->get();     

这里的关系tasks.worktimes还获取其他用户的工作时间(这是预期的),但我想将其限制为仅获取父用户的工作时间。任何人请帮我弄清楚我应该使用什么其他条件来实现这一目标?

楷模

用户.php

public function tasks()
{
    return $this->belongsToMany(Task::class, 'task_members')->withTimestamps();
}   

任务.php

public function worktimes()
{
    return $this->hasMany(Worktime::class, 'task_id');
}   

工作时间.php

public function task()
{
    return $this->belongsTo(Task::class);
} 

public function users()
{
    return $this->belongsToMany(User::class, 'task_members', 'task_id', 'user_id', 'task_id');
}

标签: laraveleloquentlaravel-relations

解决方案


闭包中的$queryQueryBuilder 仍然是一个实例,因此您也可以预先加载它

$users = User::select('users.id', 'users.first_name', 'users.last_name', 'users.contract_type')
            ->with([
                'tasks' => function ($query) use ($from, $to) {
                    $query->with([
                        'worktimes' => function ($subQuery) {
                            $subQuery->withCount(
                                [
                                    'tags as late_tag_count' => function ($subsubQuery) {
                                        $subsubQuery->where('tags.id', 1);
                                    },
                                    'tags as early_tag_count' => function ($subsubQuery) {
                                        $subsubQuery->where('tags.id', 2);
                                    },
                                    'tags as others_tag_count' => function ($subsubQuery) {
                                        $subsubQuery->where('tags.id', 3);
                                    }
                                ]
                            );
                        }
                    ])
                        ->whereBetween('date', [$from, $to])
                        ->select('tasks.id', 'tasks.date');
                }
            ])
            ->get();    

这样,工作时间和总计数按任务分组,任务按用户分组

编辑 1

在您必须先检索每个用户之后,您可以延迟加载每个用户的工作时间。然而,这不是很好,特别是如果有很多用户

$users = User::select('users.id', 'users.first_name', 'users.last_name', 'users.contract_type')
    ->with([
        'tasks' => function ($query) use ($from, $to) {
            $query->whereBetween('date', [$from, $to])->select('tasks.id', 'tasks.date');
        }
    ])
    ->get();

foreach ($users as $user) {
    $user->tasks->load([
        'worktimes' => function ($query) use ($user) {
            $query->where('user_id', $user->id)
                ->withCount([
                    'tags as late_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 1);
                    },
                    'tags as early_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 2);
                    },
                    'tags as others_tag_count' => function ($subQuery) {
                        $subQuery->where('tags.id', 3);
                    }
                ]);
        }
    ]);
}

编辑 2

您已经belongsToMany在 Worktime 模型上建立了用户 ( ) 关系。在这种情况下,在 User 模型上定义该关系的倒数将最有效。

//User.php

public function worktimes()
{
    return $this->belongsToMany(Worktimes::class, 'task_members', 'user_id', 'task_id', 'user_id');
}

//YourController.php
$users = User::select('users.id', 'users.first_name', 'users.last_name', 'users.contract_type')
    ->with(
        [
            'tasks' => function ($query) use ($from, $to) {
                $query->whereBetween('date', [$from, $to])->select('tasks.id', 'tasks.date');
            },
            'worktimes' => function ($query) {
                $query->withCount([
                    'tags as late_tag_count' => function ($subsubQuery) {
                        $subsubQuery->where('tags.id', 1);
                    },
                    'tags as early_tag_count' => function ($subsubQuery) {
                        $subsubQuery->where('tags.id', 2);
                    },
                    'tags as others_tag_count' => function ($subsubQuery) {
                        $subsubQuery->where('tags.id', 3);
                    }
                ]);
            }
        ]
    )
    ->get();

希望这可以帮助。


推荐阅读