Ваш метод имеет квадратичную c n ^ 2 производительность, так как количество запросов умножается на количество событий и посещаемости.
Первым шагом к сокращению количества запросов может быть извлечение этого запроса из самого внутреннего l oop
Attendance::where('student_id', $enrollment->student_id)->where('event_id', $event->id)->count() == 0
и получать посещаемость заранее
public function getMissingAttendanceAttribute()
{
$eventsWithMissingAttendanceCount = 0;
$eventsIDs = $this->events_with_expected_attendance->pluck('id');
$studentIDs = $this->enrollments->pluck('student_id');
// Collection of attendances
$attendances = Attendance::whereIn('student_id', $studentIDs)
->whereIn('event_id', $eventsIDs)
->get();
// loop through every event supposed to have attendance
foreach ($this->events_with_expected_attendance as $event)
{
// loop through every student
foreach ($this->enrollments as $enrollment)
{
$hasNotAttended = $attendances->where('student_id', $enrollment->student_id)
->where('event_id', $event->id)
->isEmpty();
if ($hasNotAttended) {
$eventsWithMissingAttendanceCount++;
break;
}
}
}
return $eventsWithMissingAttendanceCount;
}
Это должно повысить производительность, поскольку количество запросов не масштабируется с количеством событий и регистраций, а остается постоянным.
Например, вы можете извлечь $hasNotAttended
для метода модели регистрации.
public function getMissingAttendanceAttribute()
{
$eventsWithMissingAttendanceCount = 0;
$eventsIDs = $this->events_with_expected_attendance->pluck('id');
$studentIDs = $this->enrollments->pluck('student_id');
// Collection of attendances
$attendances = Attendance::whereIn('student_id', $studentIDs)
->whereIn('event_id', $eventsIDs)
->get();
// loop through every event supposed to have attendance
foreach ($this->events_with_expected_attendance as $event)
{
// loop through every student
foreach ($this->enrollments as $enrollment)
{
// pass preloaded attendances.
// alternatively you could preload this relationship then no need to pass $attendances
if ($enrollment->hasNotAttended($event->id, $attendances)) {
$eventsWithMissingAttendanceCount++;
break;
}
}
}
return $eventsWithMissingAttendanceCount;
}
Затем вы можете расширить $this->enrollments
collection https://laravel.com/docs/6.x/collections#extending -collections , извлекая следующее.
if ($enrollment->hasNotAttended($event->id, $attendances)) {
$eventsWithMissingAttendanceCount++;
break;
}
Таким образом, это будет упрощено до
public function getMissingAttendanceAttribute()
{
$eventsWithMissingAttendanceCount = 0;
$eventsIDs = $this->events_with_expected_attendance->pluck('id');
$studentIDs = $this->enrollments->pluck('student_id');
// Collection of attendances
$attendances = Attendance::whereIn('student_id', $studentIDs)
->whereIn('event_id', $eventsIDs)
->get();
// loop through every event supposed to have attendance
foreach ($this->events_with_expected_attendance as $event)
{
if ($this->enrollments->hasNotAttended($event->id, $attendances)) {
$eventsWithMissingAttendanceCount++;
}
}
return $eventsWithMissingAttendanceCount;
}