AttendanceController   F
last analyzed

Complexity

Total Complexity 87

Size/Duplication

Total Lines 590
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 345
dl 0
loc 590
rs 2
c 1
b 0
f 0
wmc 87

11 Methods

Rating   Name   Duplication   Size   Complexity  
A listWithDoneCount() 0 28 4
A generateQrCode() 0 35 5
B exportToXls() 0 75 11
B getUsersWithFaults() 0 54 9
A getFullAttendanceData() 0 12 2
A __construct() 0 5 1
F saveAttendanceSheet() 0 118 22
F exportToPdf() 0 140 19
B getStudentDates() 0 55 7
A updateAttendanceResults() 0 31 6
A saveAttendanceLog() 0 11 1

How to fix   Complexity   

Complex Class

Complex classes like AttendanceController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AttendanceController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chamilo\CoreBundle\Controller;
6
7
use Chamilo\CoreBundle\Entity\Course;
8
use Chamilo\CoreBundle\Entity\CourseRelUser;
9
use Chamilo\CoreBundle\Entity\Session;
10
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Repository\Node\UserRepository;
13
use Chamilo\CourseBundle\Entity\CAttendance;
14
use Chamilo\CourseBundle\Entity\CAttendanceCalendar;
15
use Chamilo\CourseBundle\Entity\CAttendanceResult;
16
use Chamilo\CourseBundle\Entity\CAttendanceResultComment;
17
use Chamilo\CourseBundle\Entity\CAttendanceSheet;
18
use Chamilo\CourseBundle\Entity\CAttendanceSheetLog;
19
use Chamilo\CourseBundle\Repository\CAttendanceCalendarRepository;
20
use Chamilo\CourseBundle\Repository\CAttendanceSheetRepository;
21
use DateTime;
22
use Doctrine\ORM\EntityManagerInterface;
23
use Endroid\QrCode\Builder\Builder;
24
use Exception;
25
use Mpdf\Mpdf;
26
use Mpdf\MpdfException;
27
use Mpdf\Output\Destination;
28
use PhpOffice\PhpSpreadsheet\Spreadsheet;
29
use PhpOffice\PhpSpreadsheet\Writer\Xls;
30
use RuntimeException;
31
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
32
use Symfony\Component\HttpFoundation\JsonResponse;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
36
use Symfony\Component\HttpFoundation\StreamedResponse;
37
use Symfony\Component\Routing\Attribute\Route;
38
use Symfony\Contracts\Translation\TranslatorInterface;
39
40
#[Route('/attendance')]
41
class AttendanceController extends AbstractController
42
{
43
    public function __construct(
44
        private readonly CAttendanceCalendarRepository $attendanceCalendarRepository,
45
        private readonly EntityManagerInterface $em,
46
        private readonly TranslatorInterface $translator
47
    ) {}
48
49
    #[Route('/full-data', name: 'chamilo_core_attendance_get_full_data', methods: ['GET'])]
50
    public function getFullAttendanceData(Request $request): JsonResponse
51
    {
52
        $attendanceId = (int) $request->query->get('attendanceId', 0);
53
54
        if (!$attendanceId) {
55
            return $this->json(['error' => 'Attendance ID is required'], 400);
56
        }
57
58
        $data = $this->attendanceCalendarRepository->findAttendanceWithData($attendanceId);
59
60
        return $this->json($data, 200);
61
    }
62
63
    #[Route('/{id}/users/context', name: 'chamilo_core_get_users_with_faults', methods: ['GET'])]
64
    public function getUsersWithFaults(
65
        int $id,
66
        Request $request,
67
        UserRepository $userRepository,
68
        CAttendanceCalendarRepository $calendarRepository,
69
        CAttendanceSheetRepository $sheetRepository
70
    ): JsonResponse {
71
        $courseId = (int) $request->query->get('courseId', 0);
72
        $sessionId = $request->query->get('sessionId') ? (int) $request->query->get('sessionId') : null;
73
        $groupId = $request->query->get('groupId') ? (int) $request->query->get('groupId') : null;
74
75
        $attendance = $this->em->getRepository(CAttendance::class)->find($id);
76
        if (!$attendance) {
77
            return $this->json(['error' => 'Attendance not found'], 404);
78
        }
79
80
        $calendars = $attendance->getCalendars();
81
        $totalCalendars = \count($calendars);
82
83
        $users = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
84
85
        $formattedUsers = array_map(function ($user) use ($userRepository, $sheetRepository, $calendars) {
86
            $absences = 0;
87
88
            foreach ($calendars as $calendar) {
89
                $sheet = $sheetRepository->findOneBy([
90
                    'user' => $user,
91
                    'attendanceCalendar' => $calendar,
92
                ]);
93
94
                if (!$sheet || null === $sheet->getPresence()) {
95
                    continue;
96
                }
97
98
                if (1 !== $sheet->getPresence()) {
99
                    $absences++;
100
                }
101
            }
102
103
            $percentage = \count($calendars) > 0 ? round(($absences * 100) / \count($calendars)) : 0;
104
105
            return [
106
                'id' => $user->getId(),
107
                'firstname' => $user->getFirstname(),
108
                'lastname' => $user->getLastname(),
109
                'email' => $user->getEmail(),
110
                'username' => $user->getUsername(),
111
                'photo' => $userRepository->getUserPicture($user->getId()),
112
                'notAttended' => "$absences/".\count($calendars)." ({$percentage}%)",
113
            ];
114
        }, $users);
115
116
        return $this->json($formattedUsers, 200);
117
    }
118
119
    #[Route('/list_with_done_count', name: 'attendance_list_with_done_count', methods: ['GET'])]
120
    public function listWithDoneCount(Request $request): JsonResponse
121
    {
122
        $courseId = (int) $request->query->get('cid', 0);
123
        $sessionId = $request->query->get('sid') ? (int) $request->query->get('sid') : null;
124
        $groupId = $request->query->get('gid') ? (int) $request->query->get('gid') : null;
125
        $parentNode = (int) $request->query->get('resourceNode.parent', 0);
126
127
        $attendances = $this->em->getRepository(CAttendance::class)->findBy([
128
            'active' => 1,
129
        ]);
130
131
        $result = [];
132
        foreach ($attendances as $attendance) {
133
            $doneCount = $this->attendanceCalendarRepository->countDoneAttendanceByAttendanceAndGroup($attendance->getIid(), $groupId);
134
135
            $result[] = [
136
                'id' => $attendance->getIid(),
137
                'title' => $attendance->getTitle(),
138
                'description' => $attendance->getDescription(),
139
                'attendanceWeight' => $attendance->getAttendanceWeight(),
140
                'attendanceQualifyTitle' => $attendance->getAttendanceQualifyTitle(),
141
                'resourceLinkListFromEntity' => $attendance->getResourceLinkListFromEntity(),
142
                'doneCalendars' => $doneCount,
143
            ];
144
        }
145
146
        return $this->json($result);
147
    }
148
149
    #[Route('/{id}/export/pdf', name: 'attendance_export_pdf', methods: ['GET'])]
150
    public function exportToPdf(int $id, Request $request): Response
151
    {
152
        $courseId = (int) $request->query->get('cid');
153
        $sessionId = ((int) $request->query->get('sid')) ?: null;
154
        $groupId = ((int) $request->query->get('gid')) ?: null;
155
156
        $attendance = $this->em->getRepository(CAttendance::class)->find($id);
157
        if (!$attendance) {
158
            throw $this->createNotFoundException('Attendance not found');
159
        }
160
161
        $calendars = $attendance->getCalendars();
162
        $totalCalendars = \count($calendars);
163
164
        $students = $this->em->getRepository(User::class)->findUsersByContext($courseId, $sessionId, $groupId);
165
        $sheetRepo = $this->em->getRepository(CAttendanceSheet::class);
166
167
        $course = $this->em->getRepository(Course::class)->find($courseId);
168
        $teacher = null;
169
170
        if ($sessionId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sessionId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
171
            $session = $this->em->getRepository(Session::class)->find($sessionId);
172
            $rel = $session?->getCourseCoachesSubscriptions()
173
                ->filter(fn ($rel) => $rel->getCourse()?->getId() === $courseId)
174
                ->first()
175
            ;
176
177
            $teacher = $rel instanceof SessionRelCourseRelUser
178
                ? $rel->getUser()?->getFullname()
179
                : null;
180
        } else {
181
            $rel = $course?->getTeachersSubscriptions()?->first();
182
183
            $teacher = $rel instanceof CourseRelUser
184
                ? $rel->getUser()?->getFullname()
185
                : null;
186
        }
187
188
        // Header
189
        $dataTable = [];
190
        $header = ['#', 'Last Name', 'First Name', 'Not Attended'];
191
        foreach ($calendars as $calendar) {
192
            $header[] = $calendar->getDateTime()->format('d/m H:i');
193
        }
194
        $dataTable[] = $header;
195
196
        // Rows
197
        $count = 1;
198
        $stateLabels = CAttendanceSheet::getPresenceLabels();
199
200
        foreach ($students as $student) {
201
            $row = [
202
                $count++,
203
                $student->getLastname(),
204
                $student->getFirstname(),
205
                '',
206
            ];
207
208
            $absences = 0;
209
            foreach ($calendars as $calendar) {
210
                $sheetEntity = $sheetRepo->findOneBy([
211
                    'user' => $student,
212
                    'attendanceCalendar' => $calendar,
213
                ]);
214
215
                if (!$sheetEntity || null === $sheetEntity->getPresence()) {
216
                    $row[] = '';
217
218
                    continue;
219
                }
220
221
                $presence = $sheetEntity->getPresence();
222
                $row[] = $stateLabels[$presence] ?? 'NP';
223
224
                if (CAttendanceSheet::ABSENT === $presence) {
225
                    $absences++;
226
                }
227
            }
228
229
            $percentage = $totalCalendars > 0 ? round(($absences * 100) / $totalCalendars) : 0;
230
            $row[3] = "$absences/$totalCalendars ($percentage%)";
231
            $dataTable[] = $row;
232
        }
233
234
        // Render HTML
235
        $html = '
236
            <style>
237
                body { font-family: sans-serif; font-size: 12px; }
238
                h2 { text-align: center; margin-bottom: 5px; }
239
                table.meta { margin: 0 auto 10px auto; width: 80%; }
240
                table.meta td { padding: 2px 5px; }
241
                table.attendance { border-collapse: collapse; width: 100%; }
242
                .attendance th, .attendance td { border: 1px solid #000; padding: 4px; text-align: center; }
243
                .np { color: red; font-weight: bold; }
244
            </style>
245
246
            <h2>'.htmlspecialchars($attendance->getTitle()).'</h2>
247
248
            <table class="meta">
249
                <tr><td><strong>Trainer:</strong></td><td>'.htmlspecialchars($teacher ?? '-').'</td></tr>
250
                <tr><td><strong>Course:</strong></td><td>'.htmlspecialchars($course?->getTitleAndCode() ?? '-').'</td></tr>
251
                <tr><td><strong>Date:</strong></td><td>'.date('F d, Y \a\t h:i A').'</td></tr>
252
            </table>
253
254
            <table class="attendance">
255
            <tr>';
256
        foreach ($dataTable[0] as $cell) {
257
            $html .= '<th>'.htmlspecialchars((string) $cell).'</th>';
258
        }
259
        $html .= '</tr>';
260
261
        foreach (\array_slice($dataTable, 1) as $row) {
262
            $html .= '<tr>';
263
            foreach ($row as $cell) {
264
                $class = 'NP' === $cell ? ' class="np"' : '';
265
                $html .= "<td$class>".htmlspecialchars((string) $cell).'</td>';
266
            }
267
            $html .= '</tr>';
268
        }
269
270
        $html .= '</table>';
271
272
        try {
273
            $mpdf = new Mpdf([
274
                'orientation' => 'L',
275
                'tempDir' => api_get_path(SYS_ARCHIVE_PATH).'mpdf/',
276
            ]);
277
            $mpdf->WriteHTML($html);
278
279
            return new Response(
280
                $mpdf->Output('', Destination::INLINE),
281
                200,
282
                [
283
                    'Content-Type' => 'application/pdf',
284
                    'Content-Disposition' => 'attachment; filename="attendance-'.$id.'.pdf"',
285
                ]
286
            );
287
        } catch (MpdfException $e) {
288
            throw new RuntimeException('Failed to generate PDF: '.$e->getMessage(), 500, $e);
289
        }
290
    }
291
292
    #[Route('/{id}/export/xls', name: 'attendance_export_xls', methods: ['GET'])]
293
    public function exportToXls(int $id, Request $request): Response
294
    {
295
        $courseId = (int) $request->query->get('cid');
296
        $sessionId = $request->query->get('sid') ? (int) $request->query->get('sid') : null;
297
        $groupId = $request->query->get('gid') ? (int) $request->query->get('gid') : null;
298
299
        $attendance = $this->em->getRepository(CAttendance::class)->find($id);
300
        if (!$attendance) {
301
            throw $this->createNotFoundException('Attendance not found');
302
        }
303
304
        $calendars = $attendance->getCalendars();
305
        $totalCalendars = \count($calendars);
306
        $students = $this->em->getRepository(User::class)->findUsersByContext($courseId, $sessionId, $groupId);
307
        $sheetRepo = $this->em->getRepository(CAttendanceSheet::class);
308
309
        $stateLabels = CAttendanceSheet::getPresenceLabels();
310
311
        $spreadsheet = new Spreadsheet();
312
        $sheet = $spreadsheet->getActiveSheet();
313
        $sheet->setTitle('Attendance');
314
315
        // Header
316
        $headers = ['#', 'Last Name', 'First Name', 'Not Attended'];
317
        foreach ($calendars as $calendar) {
318
            $headers[] = $calendar->getDateTime()->format('d/m H:i');
319
        }
320
        $sheet->fromArray($headers, null, 'A1');
321
322
        // Rows
323
        $rowNumber = 2;
324
        $count = 1;
325
        foreach ($students as $student) {
326
            $row = [$count++, $student->getLastname(), $student->getFirstname()];
327
            $absences = 0;
328
329
            foreach ($calendars as $calendar) {
330
                $sheetEntity = $sheetRepo->findOneBy([
331
                    'user' => $student,
332
                    'attendanceCalendar' => $calendar,
333
                ]);
334
335
                if (!$sheetEntity || null === $sheetEntity->getPresence()) {
336
                    $row[] = '';
337
338
                    continue;
339
                }
340
341
                $presence = $sheetEntity->getPresence();
342
                $row[] = $stateLabels[$presence] ?? 'NP';
343
344
                if (CAttendanceSheet::ABSENT === $presence) {
345
                    $absences++;
346
                }
347
            }
348
349
            $percentage = $totalCalendars > 0 ? round(($absences * 100) / $totalCalendars) : 0;
350
            array_splice($row, 3, 0, "$absences/$totalCalendars ($percentage%)");
351
352
            $sheet->fromArray($row, null, 'A'.$rowNumber++);
353
        }
354
355
        // Output
356
        $writer = new Xls($spreadsheet);
357
        $response = new StreamedResponse(fn () => $writer->save('php://output'));
358
        $disposition = $response->headers->makeDisposition(
359
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
360
            "attendance-$id.xls"
361
        );
362
363
        $response->headers->set('Content-Type', 'application/vnd.ms-excel');
364
        $response->headers->set('Content-Disposition', $disposition);
365
366
        return $response;
367
    }
368
369
    #[Route('/{id}/qrcode', name: 'attendance_qrcode', methods: ['GET'])]
370
    public function generateQrCode(int $id, Request $request): Response
371
    {
372
        $attendance = $this->em->getRepository(CAttendance::class)->find($id);
373
        if (!$attendance) {
374
            throw $this->createNotFoundException('Attendance not found');
375
        }
376
377
        $resourceNodeId = $attendance->getResourceNode()?->getParent()?->getId();
378
        if (!$resourceNodeId) {
379
            throw new RuntimeException('Missing resourceNode for course');
380
        }
381
382
        $sid = $request->query->get('sid');
383
        $gid = $request->query->get('gid');
384
385
        $query = 'readonly=1';
386
        if ($sid) {
387
            $query .= "&sid=$sid";
388
        }
389
        if ($gid) {
390
            $query .= "&gid=$gid";
391
        }
392
393
        $url = "/resources/attendance/$resourceNodeId/$id/sheet-list?$query";
394
        $fullUrl = $request->getSchemeAndHttpHost().$url;
395
396
        $result = Builder::create()
397
            ->data($fullUrl)
398
            ->size(300)
399
            ->margin(10)
400
            ->build()
401
        ;
402
403
        return new Response($result->getString(), 200, ['Content-Type' => $result->getMimeType()]);
404
    }
405
406
    #[Route('/sheet/save', name: 'chamilo_core_attendance_sheet_save', methods: ['POST'])]
407
    public function saveAttendanceSheet(
408
        Request $request,
409
        UserRepository $userRepository,
410
        CAttendanceSheetRepository $sheetRepository
411
    ): JsonResponse {
412
        $data = json_decode($request->getContent(), true);
413
414
        if (empty($data['attendanceData']) || empty($data['courseId'])) {
415
            return $this->json(['error' => 'Missing required parameters'], 400);
416
        }
417
418
        $attendanceData = $data['attendanceData'];
419
        $courseId = (int) $data['courseId'];
420
        $sessionId = isset($data['sessionId']) ? (int) $data['sessionId'] : null;
421
        $groupId = isset($data['groupId']) ? (int) $data['groupId'] : null;
422
423
        $usersInCourse = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
424
        $userIdsInCourse = array_map(fn (User $user) => $user->getId(), $usersInCourse);
425
426
        $affectedRows = 0;
427
428
        try {
429
            foreach ($attendanceData as $entry) {
430
                $userId = (int) $entry['userId'];
431
                $calendarId = (int) $entry['calendarId'];
432
                $presence = \array_key_exists('presence', $entry) ? $entry['presence'] : null;
433
                $signature = $entry['signature'] ?? null;
434
                $comment = $entry['comment'] ?? null;
435
436
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
437
                if (!$calendar) {
438
                    return $this->json(['error' => "Attendance calendar with ID $calendarId not found"], 404);
439
                }
440
441
                $user = $this->em->getRepository(User::class)->find($userId);
442
                if (!$user) {
443
                    continue;
444
                }
445
446
                $sheet = $sheetRepository->findOneBy([
447
                    'user' => $user,
448
                    'attendanceCalendar' => $calendar,
449
                ]);
450
451
                if ($sheet && null === $presence) {
452
                    $this->em->remove($sheet);
453
454
                    continue;
455
                }
456
457
                if (!$sheet && null === $presence) {
458
                    continue;
459
                }
460
461
                if (!$sheet) {
462
                    $sheet = new CAttendanceSheet();
463
                }
464
465
                $sheet->setUser($user)
466
                    ->setAttendanceCalendar($calendar)
467
                    ->setPresence($presence)
468
                    ->setSignature($signature)
469
                ;
470
471
                $this->em->persist($sheet);
472
473
                $this->em->flush();
474
475
                if (null !== $comment) {
476
                    $existingComment = $this->em->getRepository(CAttendanceResultComment::class)->findOneBy([
477
                        'attendanceSheetId' => $sheet->getIid(),
478
                        'userId' => $user->getId(),
479
                    ]);
480
481
                    if (!$existingComment) {
482
                        $existingComment = new CAttendanceResultComment();
483
                        $existingComment->setAttendanceSheetId($sheet->getIid());
484
                        $existingComment->setUserId($user->getId());
485
                        $existingComment->setAuthorUserId($this->getUser()->getId());
486
                    }
487
488
                    $existingComment->setComment($comment);
489
                    $existingComment->setUpdatedAt(new DateTime());
490
491
                    $this->em->persist($existingComment);
492
                }
493
            }
494
495
            $calendarIds = array_unique(array_column($attendanceData, 'calendarId'));
496
            foreach ($calendarIds as $calendarId) {
497
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
498
                if ($calendar && !$calendar->getDoneAttendance()) {
499
                    $calendar->setDoneAttendance(true);
500
                    $this->em->persist($calendar);
501
                }
502
            }
503
504
            $calendars = $this->attendanceCalendarRepository->findBy(['iid' => $calendarIds]);
505
            $attendance = $calendars[0]->getAttendance();
506
            $this->updateAttendanceResults($attendance);
507
508
            $lasteditType = $calendars[0]->getDoneAttendance()
509
                ? 'UPDATED_ATTENDANCE_LOG_TYPE'
510
                : 'DONE_ATTENDANCE_LOG_TYPE';
511
512
            foreach ($calendars as $calendar) {
513
                $this->saveAttendanceLog($attendance, $lasteditType, $calendar);
514
            }
515
516
            $this->em->flush();
517
518
            return $this->json([
519
                'message' => $this->translator->trans('Attendance data and comments saved successfully'),
520
                'affectedRows' => $affectedRows,
521
            ]);
522
        } catch (Exception $e) {
523
            return $this->json(['error' => 'An error occurred: '.$e->getMessage()], 500);
524
        }
525
    }
526
527
    #[Route('/{id}/student-dates', name: 'attendance_student_dates', methods: ['GET'])]
528
    public function getStudentDates(int $id): JsonResponse
529
    {
530
        $user = $this->getUser();
531
        if (!$user) {
532
            return $this->json(['error' => 'Unauthorized'], 401);
533
        }
534
535
        $attendance = $this->em->getRepository(CAttendance::class)->find($id);
536
        if (!$attendance) {
537
            return $this->json(['error' => 'Attendance not found'], 404);
538
        }
539
540
        $dates = $attendance->getCalendars()->map(function (CAttendanceCalendar $calendar) use ($user) {
541
            $sheet = $calendar->getSheets()->filter(
542
                fn ($s) => $s->getUser()->getId() === $user->getId()
543
            )->first() ?: null;
544
545
            return [
546
                'id' => $calendar->getIid(),
547
                'label' => $calendar->getDateTime()->format('M d, Y - h:i A'),
548
                'done' => $calendar->getDoneAttendance(),
549
                'presence' => $sheet ? $sheet->getPresence() : null,
550
                'sheetId' => $sheet?->getIid(),
551
                'signature' => $sheet?->getSignature(),
552
            ];
553
        })->toArray();
554
555
        $attendanceData = [];
556
        $commentData = [];
557
        $signatureData = [];
558
559
        foreach ($dates as $item) {
560
            $key = $user->getId().'-'.$item['id'];
561
            $attendanceData[$key] = $item['presence'];
562
            $signatureData[$key] = $item['signature'];
563
564
            if (!empty($item['sheetId'])) {
565
                $comment = $this->em->getRepository(CAttendanceResultComment::class)->findOneBy([
566
                    'attendanceSheetId' => $item['sheetId'],
567
                    'userId' => $user->getId(),
568
                ]);
569
                $commentData[$key] = $comment?->getComment();
570
            }
571
        }
572
573
        return $this->json([
574
            'attendanceDates' => array_map(fn ($d) => [
575
                'id' => $d['id'],
576
                'label' => $d['label'],
577
                'done' => $d['done'],
578
            ], $dates),
579
            'attendanceData' => $attendanceData,
580
            'commentData' => $commentData,
581
            'signatureData' => $signatureData,
582
        ]);
583
    }
584
585
    private function updateAttendanceResults(CAttendance $attendance): void
586
    {
587
        $sheets = $attendance->getCalendars()->map(fn ($calendar) => $calendar->getSheets())->toArray();
588
        $results = [];
589
590
        foreach ($sheets as $calendarSheets) {
591
            foreach ($calendarSheets as $sheet) {
592
                $userId = $sheet->getUser()->getId();
593
                $results[$userId] = ($results[$userId] ?? 0) + $sheet->getPresence();
594
            }
595
        }
596
597
        foreach ($results as $userId => $score) {
598
            $user = $this->em->getRepository(User::class)->find($userId);
599
            if (!$user) {
600
                continue;
601
            }
602
603
            $result = $this->em->getRepository(CAttendanceResult::class)->findOneBy([
604
                'user' => $user,
605
                'attendance' => $attendance,
606
            ]);
607
608
            if (!$result) {
609
                $result = new CAttendanceResult();
610
                $result->setUser($user);
611
                $result->setAttendance($attendance);
612
            }
613
614
            $result->setScore((int) $score);
615
            $this->em->persist($result);
616
        }
617
    }
618
619
    private function saveAttendanceLog(CAttendance $attendance, string $lasteditType, CAttendanceCalendar $calendar): void
620
    {
621
        $log = new CAttendanceSheetLog();
622
        $log->setAttendance($attendance)
623
            ->setLasteditDate(new DateTime())
624
            ->setLasteditType($lasteditType)
625
            ->setCalendarDateValue($calendar->getDateTime())
626
            ->setUser($this->getUser())
627
        ;
628
629
        $this->em->persist($log);
630
    }
631
}
632