1 | <?php |
||||
2 | |||||
3 | namespace App\Http\Controllers; |
||||
4 | |||||
5 | use App\Models\Attendance; |
||||
6 | use App\Models\AttendanceType; |
||||
7 | use App\Models\Course; |
||||
8 | use App\Models\Event; |
||||
9 | use App\Models\Student; |
||||
10 | use App\Traits\PeriodSelection; |
||||
11 | use Carbon\Carbon; |
||||
12 | use Illuminate\Http\Request; |
||||
13 | use Illuminate\Support\Facades\Gate; |
||||
14 | use Illuminate\Support\Facades\Log; |
||||
15 | use Prologue\Alerts\Facades\Alert; |
||||
16 | |||||
17 | class AttendanceController extends Controller |
||||
18 | { |
||||
19 | use PeriodSelection; |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
20 | |||||
21 | public function __construct() |
||||
22 | { |
||||
23 | parent::__construct(); |
||||
24 | $this->middleware('permission:attendance.view', ['except' => ['showCourse', 'showEvent', 'showStudentAttendanceForCourse', 'store']]); |
||||
25 | } |
||||
26 | |||||
27 | /** |
||||
28 | * Monitor attendance for all students. |
||||
29 | */ |
||||
30 | public function index(Request $request) |
||||
31 | { |
||||
32 | Log::info('Attendance dashboard viewed by '.backpack_user()->id); |
||||
0 ignored issues
–
show
|
|||||
33 | $selected_period = $this->selectPeriod($request); |
||||
34 | |||||
35 | // student attendance overview |
||||
36 | $absences = (new Attendance())->get_absence_count_per_student($selected_period); |
||||
37 | |||||
38 | // get all courses for period and preload relations |
||||
39 | $courses = $selected_period->courses()->whereHas('events')->whereHas('enrollments')->with('attendance')->with('events')->get(); |
||||
40 | |||||
41 | // loop through all courses and get the number of events with incomplete attendance |
||||
42 | foreach ($courses as $course) { |
||||
43 | $eventsWithMissingAttendanceCount = 0; |
||||
44 | $coursesdata[$course->id]['name'] = $course->name; |
||||
45 | $coursesdata[$course->id]['id'] = $course->id; |
||||
46 | $coursesdata[$course->id]['exempt_attendance'] = $course->exempt_attendance; |
||||
47 | $coursesdata[$course->id]['teachername'] = $course->course_teacher_name; |
||||
48 | |||||
49 | foreach ($course->eventsWithExpectedAttendance as $event) { |
||||
50 | foreach ($course->enrollments as $enrollment) { |
||||
51 | // if a student has no attendance record for the class (event) |
||||
52 | $hasNotAttended = $course->attendance->where('student_id', $enrollment->student_id) |
||||
53 | ->where('event_id', $event->id) |
||||
54 | ->isEmpty(); |
||||
55 | |||||
56 | // count one and break loop |
||||
57 | if ($hasNotAttended) { |
||||
58 | $eventsWithMissingAttendanceCount++; |
||||
59 | break; |
||||
60 | } |
||||
61 | } |
||||
62 | } |
||||
63 | |||||
64 | $coursesdata[$course->id]['missing'] = $eventsWithMissingAttendanceCount; |
||||
65 | } |
||||
66 | |||||
67 | // sort by number of events with missing attendance |
||||
68 | $courses = collect($coursesdata ?? [])->sortByDesc('missing')->toArray(); |
||||
69 | $isadmin = backpack_user()->hasPermissionTo('courses.edit'); |
||||
0 ignored issues
–
show
The method
hasPermissionTo() does not exist on Illuminate\Contracts\Auth\Authenticatable . It seems like you code against a sub-type of Illuminate\Contracts\Auth\Authenticatable such as Illuminate\Foundation\Auth\User .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
70 | |||||
71 | return view('attendance.monitor', compact('absences', 'courses', 'selected_period', 'isadmin')); |
||||
72 | } |
||||
73 | |||||
74 | /** |
||||
75 | * Store a newly created attendance record. |
||||
76 | */ |
||||
77 | public function store(Request $request) |
||||
78 | { |
||||
79 | $event = Event::findOrFail($request->input('event_id')); |
||||
80 | |||||
81 | // If the user is not allowed to perform this action |
||||
82 | if (Gate::forUser(backpack_user())->denies('edit-attendance', $event)) { |
||||
83 | abort(403); |
||||
84 | } |
||||
85 | |||||
86 | $student = Student::findOrFail($request->input('student_id')); |
||||
87 | $attendance_type = AttendanceType::findOrFail($request->input('attendance_type_id')); |
||||
88 | |||||
89 | $attendance = Attendance::firstOrNew([ |
||||
90 | 'student_id' => $student->id, |
||||
91 | 'event_id' => $event->id, |
||||
92 | ]); |
||||
93 | |||||
94 | $attendance->attendance_type_id = $attendance_type->id; |
||||
95 | |||||
96 | $attendance->save(); |
||||
97 | |||||
98 | Log::info('Attendance recorded by '.backpack_user()->id); |
||||
0 ignored issues
–
show
|
|||||
99 | |||||
100 | return $attendance; |
||||
101 | } |
||||
102 | |||||
103 | /** |
||||
104 | * Show the attendance records for a course. |
||||
105 | */ |
||||
106 | public function showCourse(Course $course) |
||||
107 | { |
||||
108 | |||||
109 | // The current is not allowed to view the page |
||||
110 | if (Gate::forUser(backpack_user())->denies('view-course-attendance', $course)) { |
||||
111 | abort(403); |
||||
112 | } |
||||
113 | |||||
114 | // get past events for the course |
||||
115 | $events = $course->events->filter(fn ($value, $key) => Carbon::parse($value->start) < Carbon::now())->sortByDesc('start'); |
||||
0 ignored issues
–
show
The parameter
$key is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
116 | |||||
117 | // if the course has any past events |
||||
118 | if (($events->count() == 0) || ($course->enrollments()->count() == 0)) { |
||||
119 | Alert::add('error', 'This course has no events.')->flash(); |
||||
120 | |||||
121 | return redirect()->back(); |
||||
122 | } |
||||
123 | |||||
124 | $enrollments = $course->enrollments()->with('student')->get(); |
||||
125 | $attendances = []; |
||||
126 | |||||
127 | foreach ($enrollments as $enrollment) { |
||||
128 | foreach ($events as $event) { |
||||
129 | if ($event->exempt_attendance == 1) { |
||||
130 | $attendances[$enrollment->student->id][]['attendance'] = ''; |
||||
131 | } else { |
||||
132 | $attendances[$enrollment->student->id]['student'] = $enrollment->student->firstname.' '.$enrollment->student->lastname; |
||||
133 | $attendances[$enrollment->student->id][]['attendance'] = $event->attendance->where('student_id', $enrollment->student_id)->first(); |
||||
134 | } |
||||
135 | } |
||||
136 | } |
||||
137 | Log::info('Attendance for course viewed by '.backpack_user()->id); |
||||
0 ignored issues
–
show
|
|||||
138 | |||||
139 | $isadmin = backpack_user()->hasPermissionTo('courses.edit'); |
||||
140 | |||||
141 | return view('attendance/course', compact('attendances', 'isadmin', 'course', 'events')); |
||||
142 | } |
||||
143 | |||||
144 | public function showEvent(Event $event) |
||||
145 | { |
||||
146 | |||||
147 | // The current is not allowed to view the page |
||||
148 | if (Gate::forUser(backpack_user())->denies('view-event-attendance', $event)) { |
||||
149 | abort(403); |
||||
150 | } |
||||
151 | |||||
152 | // get students |
||||
153 | $enrollments = $event->enrollments()->with('student')->get(); |
||||
154 | |||||
155 | // get the attendance record for the event |
||||
156 | $attendance = $event->attendance; |
||||
157 | |||||
158 | $attendances = []; |
||||
159 | |||||
160 | $attendance_types = AttendanceType::all(); |
||||
161 | |||||
162 | // build a collection : for each student, display attendance |
||||
163 | |||||
164 | foreach ($enrollments as $enrollment) { |
||||
165 | $attendances[$enrollment->student->id]['student'] = $enrollment->student->name; |
||||
166 | $attendances[$enrollment->student->id]['student_id'] = $enrollment->student->id; |
||||
167 | $attendances[$enrollment->student->id]['attendance'] = $attendance->where('student_id', $enrollment->student->id)->first() ?? '[attendance][attendance_type_id]'; |
||||
168 | } |
||||
169 | Log::info('Attendance for event viewed by '.backpack_user()->id); |
||||
0 ignored issues
–
show
|
|||||
170 | |||||
171 | return view('attendance/event', compact('attendances', 'event', 'attendance_types')); |
||||
172 | } |
||||
173 | |||||
174 | public function showStudentAttendanceForCourse(Student $student, Request $request) |
||||
175 | { |
||||
176 | if ($request->query('course_id') == null) { |
||||
0 ignored issues
–
show
|
|||||
177 | $selectedCourse = $student->enrollments->last()->course; |
||||
178 | } else { |
||||
179 | $selectedCourse = Course::find($request->query('course_id')); |
||||
180 | } |
||||
181 | |||||
182 | // If the current is not allowed to view the page |
||||
183 | if (Gate::forUser(backpack_user())->denies('view-course-attendance', $selectedCourse)) { |
||||
184 | abort(403); |
||||
185 | } |
||||
186 | |||||
187 | $studentEnrollments = $student->enrollments()->with('course')->get(); |
||||
188 | $courseEventIds = $selectedCourse->events->pluck('id'); |
||||
189 | |||||
190 | $attendances = $student->attendance()->with('event')->get()->whereIn('event_id', $courseEventIds); |
||||
191 | $enrollment = $studentEnrollments->where('course_id', $selectedCourse->id)->first(); |
||||
192 | $attendanceratio = $enrollment->attendance_ratio; |
||||
193 | |||||
194 | return view('attendance.student', compact('student', 'selectedCourse', 'studentEnrollments', 'attendances', 'attendanceratio')); |
||||
195 | } |
||||
196 | |||||
197 | public function toggleEventAttendanceStatus(Event $event, Request $request) |
||||
198 | { |
||||
199 | if (! backpack_user()->hasPermissionTo('courses.edit')) { |
||||
200 | abort(403); |
||||
201 | } |
||||
202 | $event->exempt_attendance = (int) $request->status; |
||||
203 | $event->save(); |
||||
204 | |||||
205 | return (int) $event->exempt_attendance; |
||||
206 | } |
||||
207 | |||||
208 | public function toggleCourseAttendanceStatus(Course $course, Request $request) |
||||
209 | { |
||||
210 | if (! backpack_user()->hasPermissionTo('courses.edit')) { |
||||
211 | abort(403); |
||||
212 | } |
||||
213 | $course->exempt_attendance = (int) $request->status; |
||||
214 | $course->save(); |
||||
215 | |||||
216 | // apply the same change to all course events |
||||
217 | foreach ($course->events as $event) { |
||||
218 | $event->exempt_attendance = (int) $request->status; |
||||
219 | $event->save(); |
||||
220 | } |
||||
221 | |||||
222 | return (int) $course->exempt_attendance; |
||||
223 | } |
||||
224 | } |
||||
225 |