Passed
Pull Request — master (#6053)
by
unknown
08:30
created

AttendanceController::saveAttendanceSheet()   F

Complexity

Conditions 17
Paths 2029

Size

Total Lines 104
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 17
eloc 66
c 1
b 0
f 0
nc 2029
nop 3
dl 0
loc 104
rs 1.0499

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chamilo\CoreBundle\Controller;
6
7
use Chamilo\CoreBundle\Entity\User;
8
use Chamilo\CoreBundle\Repository\Node\UserRepository;
9
use Chamilo\CourseBundle\Entity\CAttendance;
10
use Chamilo\CourseBundle\Entity\CAttendanceCalendar;
11
use Chamilo\CourseBundle\Entity\CAttendanceResult;
12
use Chamilo\CourseBundle\Entity\CAttendanceResultComment;
13
use Chamilo\CourseBundle\Entity\CAttendanceSheet;
14
use Chamilo\CourseBundle\Entity\CAttendanceSheetLog;
15
use Chamilo\CourseBundle\Repository\CAttendanceCalendarRepository;
16
use Chamilo\CourseBundle\Repository\CAttendanceSheetRepository;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
19
use Symfony\Component\HttpFoundation\JsonResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\Routing\Attribute\Route;
22
23
#[Route('/attendance')]
24
class AttendanceController extends AbstractController
25
{
26
27
    public function __construct(
28
        private readonly CAttendanceCalendarRepository $attendanceCalendarRepository,
29
        private readonly EntityManagerInterface $em
30
    ) {}
31
32
    #[Route('/full-data', name: 'chamilo_core_attendance_get_full_data', methods: ['GET'])]
33
    public function getFullAttendanceData(Request $request): JsonResponse
34
    {
35
        $attendanceId = (int) $request->query->get('attendanceId', 0);
36
37
        if (!$attendanceId) {
38
            return $this->json(['error' => 'Attendance ID is required'], 400);
39
        }
40
41
        $data = $this->attendanceCalendarRepository->findAttendanceWithData($attendanceId);
42
43
        return $this->json($data, 200);
44
    }
45
46
    #[Route('/users/context', name: 'chamilo_core_get_users_with_faults', methods: ['GET'])]
47
    public function getUsersWithFaults(
48
        Request $request,
49
        UserRepository $userRepository,
50
        CAttendanceCalendarRepository $calendarRepository,
51
        CAttendanceSheetRepository $sheetRepository
52
    ): JsonResponse {
53
        $courseId = (int) $request->query->get('courseId', 0);
54
        $sessionId = $request->query->get('sessionId') ? (int) $request->query->get('sessionId') : null;
55
        $groupId = $request->query->get('groupId') ? (int) $request->query->get('groupId') : null;
56
57
        if (!$courseId) {
58
            return $this->json(['error' => 'Course ID is required'], 400);
59
        }
60
61
        try {
62
            $users = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
63
64
            $totalCalendars = $calendarRepository->countByAttendanceAndGroup($courseId, $groupId);
65
66
            $formattedUsers = array_map(function ($user) use ($sheetRepository, $calendarRepository, $userRepository, $courseId, $groupId, $totalCalendars) {
0 ignored issues
show
Unused Code introduced by
The import $calendarRepository is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
67
                $userScore = $sheetRepository->getUserScore($user->getId(), $courseId, $groupId);
68
69
                $faults = max(0, $totalCalendars - $userScore);
70
                $faultsPercent = $totalCalendars > 0 ? round(($faults * 100) / $totalCalendars, 0) : 0;
71
72
                return [
73
                    'id' => $user->getId(),
74
                    'firstname' => $user->getFirstname(),
75
                    'lastname' => $user->getLastname(),
76
                    'email' => $user->getEmail(),
77
                    'username' => $user->getUsername(),
78
                    'photo' => $userRepository->getUserPicture($user->getId()),
79
                    'notAttended' => "$faults/$totalCalendars ({$faultsPercent}%)",
80
                ];
81
            }, $users);
82
83
            return $this->json($formattedUsers, 200);
84
        } catch (\Exception $e) {
85
            return $this->json(['error' => 'An error occurred: ' . $e->getMessage()], 500);
86
        }
87
    }
88
89
    #[Route('/sheet/save', name: 'chamilo_core_attendance_sheet_save', methods: ['POST'])]
90
    public function saveAttendanceSheet(
91
        Request $request,
92
        UserRepository $userRepository,
93
        CAttendanceSheetRepository $sheetRepository
94
    ): JsonResponse {
95
        $data = json_decode($request->getContent(), true);
96
97
        if (empty($data['attendanceData']) || empty($data['courseId'])) {
98
            return $this->json(['error' => 'Missing required parameters'], 400);
99
        }
100
101
        $attendanceData = $data['attendanceData'];
102
        $courseId = (int) $data['courseId'];
103
        $sessionId = isset($data['sessionId']) ? (int) $data['sessionId'] : null;
104
        $groupId = isset($data['groupId']) ? (int) $data['groupId'] : null;
105
106
        $usersInCourse = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
107
        $userIdsInCourse = array_map(fn(User $user) => $user->getId(), $usersInCourse);
108
109
        $affectedRows = 0;
110
111
        try {
112
            foreach ($attendanceData as $entry) {
113
                $userId = (int) $entry['userId'];
114
                $calendarId = (int) $entry['calendarId'];
115
                $presence = isset($entry['presence']) ? (int)$entry['presence'] : null;
116
                $signature = $entry['signature'] ?? null;
117
                $comment = $entry['comment'] ?? null;
118
119
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
120
                if (!$calendar) {
121
                    return $this->json(['error' => "Attendance calendar with ID $calendarId not found"], 404);
122
                }
123
124
                $user = $this->em->getRepository(User::class)->find($userId);
125
                if (!$user) {
126
                    continue;
127
                }
128
129
                $sheet = $sheetRepository->findOneBy([
130
                    'user' => $user,
131
                    'attendanceCalendar' => $calendar,
132
                ]) ?? new CAttendanceSheet();
133
134
                $sheet->setUser($user)
135
                    ->setAttendanceCalendar($calendar)
136
                    ->setPresence($presence)
137
                    ->setSignature($signature);
138
139
                $this->em->persist($sheet);
140
141
                $this->em->flush();
142
143
                if ($comment !== null) {
144
                    $existingComment = $this->em->getRepository(CAttendanceResultComment::class)->findOneBy([
145
                        'attendanceSheetId' => $sheet->getIid(),
146
                        'userId' => $user->getId(),
147
                    ]);
148
149
                    if (!$existingComment) {
150
                        $existingComment = new CAttendanceResultComment();
151
                        $existingComment->setAttendanceSheetId($sheet->getIid());
152
                        $existingComment->setUserId($user->getId());
153
                        $existingComment->setAuthorUserId($this->getUser()->getId());
154
                    }
155
156
                    $existingComment->setComment($comment);
157
                    $existingComment->setUpdatedAt(new \DateTime());
158
159
                    $this->em->persist($existingComment);
160
                }
161
            }
162
163
            $calendarIds = array_unique(array_column($attendanceData, 'calendarId'));
164
            foreach ($calendarIds as $calendarId) {
165
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
166
                if ($calendar && !$calendar->getDoneAttendance()) {
167
                    $calendar->setDoneAttendance(true);
168
                    $this->em->persist($calendar);
169
                }
170
            }
171
172
            $calendars = $this->attendanceCalendarRepository->findBy(['iid' => $calendarIds]);
173
            $attendance = $calendars[0]->getAttendance();
174
            $this->updateAttendanceResults($attendance);
175
176
            $lasteditType = $calendars[0]->getDoneAttendance()
177
                ? 'UPDATED_ATTENDANCE_LOG_TYPE'
178
                : 'DONE_ATTENDANCE_LOG_TYPE';
179
180
            foreach ($calendars as $calendar) {
181
                $this->saveAttendanceLog($attendance, $lasteditType, $calendar);
182
            }
183
184
            $this->em->flush();
185
186
            return $this->json([
187
                'message' => 'Attendance data and comments saved successfully',
188
                'affectedRows' => $affectedRows,
189
            ]);
190
191
        } catch (\Exception $e) {
192
            return $this->json(['error' => 'An error occurred: ' . $e->getMessage()], 500);
193
        }
194
    }
195
196
    private function updateAttendanceResults(CAttendance $attendance): void
197
    {
198
        $sheets = $attendance->getCalendars()->map(fn ($calendar) => $calendar->getSheets())->toArray();
199
        $results = [];
200
201
        foreach ($sheets as $calendarSheets) {
202
            foreach ($calendarSheets as $sheet) {
203
                $userId = $sheet->getUser()->getId();
204
                $results[$userId] = ($results[$userId] ?? 0) + $sheet->getPresence();
205
            }
206
        }
207
208
        foreach ($results as $userId => $score) {
209
            $user = $this->em->getRepository(User::class)->find($userId);
210
            if (!$user) {
211
                continue;
212
            }
213
214
            $result = $this->em->getRepository(CAttendanceResult::class)->findOneBy([
215
                'user' => $user,
216
                'attendance' => $attendance,
217
            ]);
218
219
            if (!$result) {
220
                $result = new CAttendanceResult();
221
                $result->setUser($user);
222
                $result->setAttendance($attendance);
223
            }
224
225
            $result->setScore((int) $score);
226
            $this->em->persist($result);
227
        }
228
    }
229
230
    private function saveAttendanceLog(CAttendance $attendance, string $lasteditType, CAttendanceCalendar $calendar): void
231
    {
232
        $log = new CAttendanceSheetLog();
233
        $log->setAttendance($attendance)
234
            ->setLasteditDate(new \DateTime())
235
            ->setLasteditType($lasteditType)
236
            ->setCalendarDateValue($calendar->getDateTime())
237
            ->setUser($this->getUser());
238
239
        $this->em->persist($log);
240
    }
241
}
242