#laravel #eloquent #laravel-relations
Вопрос:
У меня есть этот запрос, чтобы перечислить всех пользователей с их соответствующими отношениями.
у пользователя много задач
у каждой задачи есть много рабочих часов, и у этих рабочих часов могут быть разные пользователи
т. е. каждая задача может быть разделена разными пользователями, следовательно, у них есть индивидуальное рабочее время для каждой задачи.
я попробовал приведенный ниже код
$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();
здесь задачи по взаимоотношениям.время работы также позволяет получать рабочее время других пользователей (что отчасти ожидаемо), но я хочу ограничить это, чтобы получать только рабочее время родительского пользователя.
кто-нибудь, пожалуйста, помогите мне выяснить, какое еще условие я должен использовать для достижения этой цели?
Модели
User.php
public function tasks()
{
return $this->belongsToMany(Task::class, 'task_members')->withTimestamps();
}
Task.php
public function worktimes()
{
return $this->hasMany(Worktime::class, 'task_id');
}
Worktime.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');
}
Ответ №1:
$query
В закрытии по-прежнему является экземпляром QueryBuilder, поэтому вы также можете загружать его
$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
У вас уже есть отношение users ( belongsToMany
) в модели рабочего времени. Определение обратной зависимости в пользовательской модели будет лучше всего работать в этой ситуации.
//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();
Надеюсь, это поможет.
Комментарии:
1. да, рабочее время группируется по задачам, но и с другими пользователями рабочее время тоже. я хочу ограничить время работы других пользователей отношениями task => рабочее время
2. Если это так, то вы можете прервать заявления. Поскольку вам нужен способ доступа
user_id
, сначала вам нужно получить пользователей, а затем лениво загрузить время работы для каждого из пользователей. Не элегантно, особенно если много пользователей, но все равно работает! Лучшим решением будет определить прямую связь между пользователями и рабочим временем. У вас уже есть отношение users (belongsToMany
)в модели рабочего времени, вам просто нужно определить обратное. Проверьте редактирование3. Я не вхожу в решение #edit1, так как это вызывает проблему n 1. В настоящее время я выбираю все время работы для каждой задачи, а затем фильтрую на основе идентификатора пользователя, но это может быть проблемой с производительностью, если для каждой задачи зарегистрировано много времени работы. Edit2 кажется мне хорошим, я постараюсь принять ответ, если он сработает (я думаю, что так и будет). Спасибо, что уделили мне время.