src/Controller/StudentController.php line 226

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Program;
  4. use App\Entity\Student;
  5. use App\Entity\Subscription;
  6. use App\Entity\ClassRoom;
  7. use App\Form\StudentType;
  8. use App\Repository\StudentRepository;
  9. use App\Repository\EvaluationRepository;
  10. use App\Repository\SequenceRepository;
  11. use App\Repository\MarkRepository;
  12. use Knp\Snappy\Pdf;
  13. use App\Repository\SchoolYearRepository;
  14. use App\Repository\SubscriptionRepository;
  15. use App\Repository\PaymentRepository;
  16. use App\Repository\QuaterRepository;
  17. use App\Repository\InstallmentRepository;
  18. use App\Repository\PaymentPlanRepository;
  19. use App\Repository\MainTeacherRepository;
  20. use App\Repository\ProgramRepository;
  21. use Doctrine\ORM\EntityManagerInterface;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  26. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  27. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  28. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  29. use App\Service\SchoolYearService;
  30. use App\Entity\User;
  31. /**
  32. * Studentme controller.
  33. *
  34. * @Route("/prof/students")
  35. */
  36. class StudentController extends AbstractController
  37. {
  38. private EntityManagerInterface $em;
  39. private $repo;
  40. private $scRepo;
  41. private $seqRepo;
  42. private SubscriptionRepository $subRepo;
  43. private $markRepo;
  44. private $evalRepo;
  45. private $qtRepo;
  46. private $snappy;
  47. private SchoolYearService $schoolYearService;
  48. private PaymentPlanRepository $ppRepo;
  49. private InstallmentRepository $instRepo;
  50. private PaymentRepository $pRepo;
  51. private MainTeacherRepository $mainTeacherRepo;
  52. private ProgramRepository $programRepo;
  53. public function __construct(
  54. PaymentRepository $pRepo,
  55. InstallmentRepository $instRepo,
  56. PaymentPlanRepository $ppRepo,
  57. SchoolYearService $schoolYearService,
  58. EntityManagerInterface $em,
  59. SubscriptionRepository $subRepo,
  60. MarkRepository $markRepo,
  61. EvaluationRepository $evalRepo,
  62. StudentRepository $repo,
  63. SequenceRepository $seqRepo,
  64. SchoolYearRepository $scRepo,
  65. QuaterRepository $qtRepo,
  66. MainTeacherRepository $mainTeacherRepo,
  67. ProgramRepository $programRepo,
  68. Pdf $snappy
  69. ) {
  70. $this->em = $em;
  71. $this->repo = $repo;
  72. $this->scRepo = $scRepo;
  73. $this->markRepo = $markRepo;
  74. $this->seqRepo = $seqRepo;
  75. $this->evalRepo = $evalRepo;
  76. $this->subRepo = $subRepo;
  77. $this->qtRepo = $qtRepo;
  78. $this->snappy = $snappy;
  79. $this->ppRepo = $ppRepo;
  80. $this->pRepo = $pRepo;
  81. $this->instRepo = $instRepo;
  82. $this->mainTeacherRepo = $mainTeacherRepo;
  83. $this->programRepo = $programRepo;
  84. $this->schoolYearService = $schoolYearService;
  85. }
  86. // =========================================================
  87. // Méthode privée mutualisée pour l'auth
  88. // Remplace les blocs répétés dans chaque action
  89. // =========================================================
  90. private function checkAuth(): ?Response
  91. {
  92. if (!$this->getUser()) {
  93. $this->addFlash('warning', 'You need login first!');
  94. return $this->redirectToRoute('app_login');
  95. }
  96. /** @var User $user */
  97. $user = $this->getUser();
  98. if (!$user->isVerified()) {
  99. $this->addFlash('warning', 'You need to have a verified account!');
  100. return $this->redirectToRoute('app_login');
  101. }
  102. return null;
  103. }
  104. /**
  105. * @Route("/create", name="admin_students_new", methods={"GET","POST"})
  106. */
  107. public function create(Request $request): Response
  108. {
  109. if ($redirect = $this->checkAuth()) return $redirect;
  110. $student = new Student();
  111. // Générer le matricule AVANT la construction du formulaire
  112. $numero = $this->repo->getNumeroDispo();
  113. $student->setMatricule($numero);
  114. $form = $this->createForm(StudentType::class, $student);
  115. $form->handleRequest($request);
  116. if ($form->isSubmitted() && $form->isValid()) {
  117. if ($student->getEntryClass() !== null) {
  118. $sub = new Subscription();
  119. $sub->setStudent($student);
  120. $sub->setClassRoom($student->getEntryClass());
  121. $sub->setSchoolYear($this->schoolYearService->sessionYearById());
  122. $this->em->persist($sub);
  123. }
  124. $this->em->persist($student);
  125. $this->em->flush();
  126. $this->addFlash('success', 'Student successfully created');
  127. return $this->redirectToRoute('admin_students', [
  128. 'type' => "new_students_not_yet_registered_checkbox",
  129. ]);
  130. }
  131. return $this->render('student/new.html.twig', [
  132. 'form' => $form->createView(),
  133. ]);
  134. }
  135. /**
  136. * Lists all Studentme entities.
  137. *
  138. * @Route("/{type}", name="admin_students")
  139. * @Method("GET")
  140. * @Template()
  141. */
  142. public function indexAction($type)
  143. {
  144. if ($redirect = $this->checkAuth()) return $redirect;
  145. $year = $this->schoolYearService->sessionYearById();
  146. switch ($type) {
  147. case "new_students_not_yet_registered_checkbox":
  148. $students = $this->repo->findNewStudents($year);
  149. break;
  150. case "new_registered_students_checkbox":
  151. $students = $this->repo->findNewRegisteredStudents($year);
  152. break;
  153. case "registered_former_students_checkbox":
  154. $students = $this->repo->findFormerRegisteredStudents($year);
  155. break;
  156. case "complete_registered_students_checkbox":
  157. $students = $this->repo->findEnrolledStudentsThisYear2($year);
  158. break;
  159. default:
  160. $students = $this->repo->findEnrolledStudentsThisYear2($year);
  161. break;
  162. }
  163. // Regrouper les élèves par classe
  164. $studentsByClass = [];
  165. foreach ($students as $student) {
  166. $class = $student->getEntryClass();
  167. if ($class) {
  168. $studentsByClass[$class->getId()]['class'] = $class;
  169. $studentsByClass[$class->getId()]['students'][] = $student;
  170. } else {
  171. $studentsByClass['no_class']['class'] = null;
  172. $studentsByClass['no_class']['students'][] = $student;
  173. }
  174. }
  175. // Récupération des programmes pour le filtre
  176. $programs = $this->programRepo->findAll();
  177. return $this->render('student/list.html.twig', [
  178. 'programs' => $programs,
  179. 'studentsByClass' => $studentsByClass,
  180. 'type' => $type,
  181. 'year' => $year,
  182. ]);
  183. }
  184. /**
  185. * @Route("/{id}/unregister/{room_id}", name="admin_students_unregister", requirements={"id"="\d+", "room_id"="\d+"})
  186. * @ParamConverter("std", options={"mapping": {"id": "id"}})
  187. * @ParamConverter("room", options={"mapping": {"room_id": "id"}})
  188. */
  189. public function unregisterAction(Student $std, ClassRoom $room)
  190. {
  191. if ($redirect = $this->checkAuth()) return $redirect;
  192. $year = $this->schoolYearService->sessionYearById();
  193. $sub = $this->subRepo->findOneBy(["student" => $std, "classRoom" => $room, "schoolYear" => $year]);
  194. $this->em->remove($sub);
  195. $this->em->flush();
  196. return $this->redirectToRoute('admin_classrooms_show', ["id" => $room->getId()]);
  197. }
  198. /**
  199. * Finds and displays a Studentme entity.
  200. *
  201. * @Route("/{id}/show", name="admin_students_show", requirements={"id"="\d+"})
  202. * @Method("GET")
  203. * @Template()
  204. */
  205. public function showAction(Student $student)
  206. {
  207. if ($redirect = $this->checkAuth()) return $redirect;
  208. $year = $this->schoolYearService->sessionYearById();
  209. $seq = $this->seqRepo->findOneBy(["activated" => true]);
  210. $sub = $this->subRepo->findOneBy(["student" => $student, "schoolYear" => $year]);
  211. $results = [
  212. 'student' => $student,
  213. 'cours' => null,
  214. 'session1' => null,
  215. 'session2' => null,
  216. 'session3' => null,
  217. 'session4' => null,
  218. 'session5' => null,
  219. 'session6' => null,
  220. ];
  221. $payments = $this->pRepo->findBy(["subscription" => $sub], ['updatedAt' => 'ASC']);
  222. $paymentPlan = $this->ppRepo->findOneBy(["schoolYear" => $year]);
  223. if ($sub !== null) {
  224. $installments = $this->instRepo->findBy(["paymentPlan" => $paymentPlan, "classRoom" => $sub->getClassRoom()]);
  225. } else {
  226. $installments = $this->instRepo->findBy(["paymentPlan" => $paymentPlan]);
  227. }
  228. $seqs = $this->seqRepo->findSequenceThisYear($year);
  229. $evalSeqs = [];
  230. if ($sub !== null) {
  231. foreach ($seqs as $s) {
  232. $evalSeqs[$s->getId()] = $this->evalRepo->findBy([
  233. "classRoom" => $sub->getClassRoom(),
  234. "sequence" => $s,
  235. ]);
  236. }
  237. $courses = [];
  238. $averageSeqs = [];
  239. if ($seq && isset($evalSeqs[$seq->getId()])) {
  240. foreach ($evalSeqs[$seq->getId()] as $eval) {
  241. $courses[] = $eval->getCourse()->getWording();
  242. }
  243. }
  244. foreach ($seqs as $s) {
  245. $average = [];
  246. foreach ($evalSeqs[$s->getId()] as $eval) {
  247. $mark = $this->markRepo->findOneBy(["student" => $student, "evaluation" => $eval]);
  248. if ($mark) {
  249. $average[] = $mark->getValue();
  250. }
  251. }
  252. $averageSeqs[$s->getId()] = $average;
  253. }
  254. $filename = "assets/images/student/" . $student->getMatricule() . ".jpg";
  255. $file_exists = file_exists($filename);
  256. $results['payments'] = $payments;
  257. $results['payment_plan'] = $paymentPlan;
  258. $results['installments'] = $installments;
  259. $results['sub'] = $sub;
  260. $results['file_exists'] = $file_exists;
  261. $results['cours'] = json_encode($courses);
  262. foreach ($seqs as $s) {
  263. $results[strtolower($s->getWording())] = json_encode($averageSeqs[$s->getId()]);
  264. }
  265. }
  266. return $this->render('student/show.html.twig', $results);
  267. }
  268. /**
  269. * Displays a form to edit an existing Studentme entity.
  270. *
  271. * @Route("/{id}/edit", name="admin_students_edit", requirements={"id"="\d+"}, methods={"GET","PUT"})
  272. * @Template()
  273. */
  274. public function edit(Request $request, Student $student): Response
  275. {
  276. if ($redirect = $this->checkAuth()) return $redirect;
  277. $form = $this->createForm(StudentType::class, $student, ['method' => 'PUT']);
  278. $form->handleRequest($request);
  279. if ($form->isSubmitted() && $form->isValid()) {
  280. $this->em->flush();
  281. $this->addFlash('success', 'Student successfully updated');
  282. $year = $this->schoolYearService->sessionYearById();
  283. $sub = $this->subRepo->findOneBy(["student" => $student, "schoolYear" => $year]);
  284. return $this->redirectToRoute('admin_classrooms_show', ["id" => $sub->getClassRoom()->getId()]);
  285. }
  286. return $this->render('student/edit.html.twig', [
  287. 'student' => $student,
  288. 'form' => $form->createView(),
  289. ]);
  290. }
  291. /**
  292. * Deletes a Studentme entity.
  293. *
  294. * @Route("/{id}/delete", name="admin_students_delete", requirements={"id"="\d+"}, methods={"DELETE"})
  295. */
  296. public function delete(Student $student, Request $request): Response
  297. {
  298. if ($redirect = $this->checkAuth()) return $redirect;
  299. if ($this->isCsrfTokenValid('students_deletion' . $student->getId(), $request->request->get('csrf_token'))) {
  300. $this->em->remove($student);
  301. $this->em->flush();
  302. $this->addFlash('info', 'Student successfully deleted');
  303. }
  304. return $this->redirectToRoute('admin_students', [
  305. 'type' => "new_students_not_yet_registered_checkbox",
  306. ]);
  307. }
  308. /**
  309. * Build student's school certificate
  310. *
  311. * @Route("/{id}/certificate", name="admin_student_certificate", requirements={"id"="\d+"})
  312. */
  313. public function schoolCertificate(Pdf $pdf, Student $std): Response
  314. {
  315. if ($redirect = $this->checkAuth()) return $redirect;
  316. $year = $this->schoolYearService->sessionYearById();
  317. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  318. $html = $this->renderView('student/school_certificate.html.twig', [
  319. 'year' => $year,
  320. 'std' => $std,
  321. 'sub' => $sub,
  322. ]);
  323. return new Response($pdf->getOutputFromHtml($html), 200, [
  324. 'Content-Type' => 'application/pdf',
  325. 'Content-Disposition' => 'inline; filename="certif_' . $std->getMatricule() . '.pdf"',
  326. ]);
  327. }
  328. /**
  329. * @Route("/{id}/receipt", name="admin_student_receipt", requirements={"id"="\d+"})
  330. */
  331. public function tuitionReceiptAction(Pdf $pdf, Student $std): Response
  332. {
  333. if ($redirect = $this->checkAuth()) return $redirect;
  334. $year = $this->schoolYearService->sessionYearById();
  335. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  336. $payments = $this->pRepo->findBy(["subscription" => $sub], ['updatedAt' => 'ASC']);
  337. $paymentPlan = $this->ppRepo->findOneBy(["schoolYear" => $year]);
  338. $installments = $this->instRepo->findBy(["paymentPlan" => $paymentPlan, "classRoom" => $sub->getClassRoom()]);
  339. $html = $this->renderView('student/templating/tuition_receipt.html.twig', [
  340. 'year' => $year,
  341. 'std' => $std,
  342. 'sub' => $sub,
  343. 'payments' => $payments,
  344. 'payment_plan' => $paymentPlan,
  345. 'installments' => $installments,
  346. ]);
  347. return new Response($pdf->getOutputFromHtml($html), 200, [
  348. 'Content-Type' => 'application/pdf',
  349. 'Content-Disposition' => 'inline; filename="recu_' . $std->getMatricule() . '.pdf"',
  350. ]);
  351. }
  352. /**
  353. * @Route("/{id}/badge", name="admin_student_badge", requirements={"id"="\d+"})
  354. */
  355. public function schoolBadge(Pdf $pdf, Student $std): Response
  356. {
  357. if ($redirect = $this->checkAuth()) return $redirect;
  358. $year = $this->schoolYearService->sessionYearById();
  359. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  360. $filename = "assets/images/student/" . $std->getMatricule() . ".jpg";
  361. $fileExist = file_exists($filename);
  362. $html = $this->renderView('student/badge.html.twig', [
  363. 'sub' => $sub,
  364. 'fileExist' => $fileExist,
  365. ]);
  366. return new Response($pdf->getOutputFromHtml($html), 200, [
  367. 'Content-Type' => 'application/pdf',
  368. 'Content-Disposition' => 'inline; filename="badge_' . $std->getMatricule() . '.pdf"',
  369. ]);
  370. }
  371. /**
  372. * @Route("/{id}/reportCardTrim2024", name="admin_students_reportcards_quat_2024", requirements={"id"="\d+"})
  373. * @Method("GET")
  374. * @Template()
  375. */
  376. public function reporCardTrimAction2024(Pdf $pdf, Student $std, Request $request)
  377. {
  378. if ($redirect = $this->checkAuth()) return $redirect;
  379. $headerFontSize = $request->request->get('header_font_size');
  380. $lineHeight = $request->request->get('line_height');
  381. $copyright = $request->request->get('copyright') == "on";
  382. $connection = $this->em->getConnection();
  383. $year = $this->schoolYearService->sessionYearById();
  384. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  385. $quater = $this->qtRepo->findOneBy(["activated" => true]);
  386. $students = $this->repo->findEnrolledStudentsThisYearInClass($sub->getClassRoom(), $year);
  387. $mainTeacher = $this->mainTeacherRepo->findOneBy([
  388. "classRoom" => $sub->getClassRoom(),
  389. "schoolYear" => $year,
  390. ])->getTeacher();
  391. $filename = "assets/images/student/" . $std->getMatricule() . ".jpg";
  392. $fileExist = file_exists($filename);
  393. $query = "SELECT DISTINCT sequence.id as sequence, course.id as course_id, course.wording, course.coefficient,
  394. mark.value, mark.weight, mark.rank2, evaluation.mini as mini, evaluation.maxi as maxi,
  395. evaluation.competence, attribution.teacher_id, school_year.id, user.full_name
  396. FROM sequence
  397. JOIN evaluation ON evaluation.sequence_id = sequence.id
  398. JOIN course ON evaluation.course_id = course.id
  399. JOIN attribution ON attribution.course_id = course.id
  400. JOIN user ON user.id = attribution.teacher_id
  401. JOIN mark ON evaluation.id = mark.evaluation_id
  402. JOIN quater ON sequence.quater_id = quater.id
  403. JOIN school_year ON quater.school_year_id = school_year.id AND school_year.id = attribution.year_id
  404. WHERE quater.id = :quater_id AND mark.student_id = :student_id
  405. ORDER BY course.id, sequence.id";
  406. $params = [
  407. 'quater_id' => $quater->getId(),
  408. 'student_id' => $std->getId(),
  409. ];
  410. $result = $connection->executeQuery($query, $params);
  411. $data = $result->fetchAllAssociative();
  412. $html = $this->renderView('student/reportcard/quaterly_2024.html.twig', [
  413. 'year' => $year,
  414. 'quater' => $quater,
  415. 'mainTeacher' => $mainTeacher,
  416. 'data' => $data,
  417. 'std' => $std,
  418. 'students' => $students,
  419. 'room' => $sub->getClassRoom(),
  420. 'lineHeight' => 0.75 * $lineHeight,
  421. 'headerFontSize' => 0.75 * $headerFontSize,
  422. 'copyright' => $copyright,
  423. 'fileExist' => $fileExist,
  424. ]);
  425. return new Response($pdf->getOutputFromHtml($html), 200, [
  426. 'Content-Type' => 'application/pdf',
  427. 'Content-Disposition' => 'inline; filename="bull_' . $quater->getId() . '_' . $std->getMatricule() . '.pdf"',
  428. ]);
  429. }
  430. /**
  431. * @Route("/{id}/reportCardTrim", name="admin_students_reportcards_quat", requirements={"id"="\d+"})
  432. * @Method("GET")
  433. * @Template()
  434. */
  435. public function reporCardTrimAction(Pdf $pdf, Student $std)
  436. {
  437. if ($redirect = $this->checkAuth()) return $redirect;
  438. $connection = $this->em->getConnection();
  439. $year = $this->schoolYearService->sessionYearById();
  440. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  441. $quater = $this->qtRepo->findOneBy(["activated" => true]);
  442. $sequences = $this->seqRepo->findBy(["quater" => $quater]);
  443. $filename = "assets/images/student/" . $std->getMatricule() . ".jpg";
  444. $fileExist = file_exists($filename);
  445. $i = 1;
  446. foreach ($sequences as $seq) {
  447. $sql = "CREATE OR REPLACE VIEW V_STUDENT_MARK_SEQ" . $i . " AS
  448. SELECT DISTINCT eval.id as eval, crs.id as crs, room.id as room,
  449. teach.full_name as teacher, modu.id as module, m.value as value, m.weight as weight
  450. FROM mark m
  451. JOIN student std ON m.student_id = std.id
  452. JOIN evaluation eval ON m.evaluation_id = eval.id
  453. JOIN class_room room ON eval.class_room_id = room.id
  454. JOIN course crs ON eval.course_id = crs.id
  455. JOIN attribution att ON att.course_id = crs.id
  456. JOIN user teach ON att.teacher_id = teach.id
  457. JOIN module modu ON modu.id = crs.module_id
  458. JOIN sequence seq ON seq.id = eval.sequence_id
  459. WHERE std.id = ? AND eval.sequence_id = ?
  460. ORDER BY crs.id";
  461. $connection->executeStatement($sql, [$std->getId(), $seq->getId()]);
  462. $i++;
  463. }
  464. $connection->executeStatement(
  465. "CREATE OR REPLACE VIEW V_STUDENT_MARK_QUATER AS
  466. SELECT DISTINCT seq1.crs as crs,
  467. (seq1.value * seq1.weight + seq2.value * seq2.weight) / (seq1.weight + seq2.weight) as value,
  468. greatest(seq1.weight, seq2.weight) as weight,
  469. seq1.weight as weight1, seq2.weight as weight2,
  470. seq1.value as value1, seq2.value as value2,
  471. seq1.teacher as teacher, seq1.module as module, seq1.room as room
  472. FROM V_STUDENT_MARK_SEQ1 seq1
  473. JOIN V_STUDENT_MARK_SEQ2 seq2 ON seq1.crs = seq2.crs
  474. ORDER BY seq1.crs"
  475. );
  476. $dataQuater = $connection->executeQuery("SELECT * FROM V_STUDENT_MARK_QUATER")->fetchAllAssociative();
  477. $html = $this->renderView('student/reportcardTrimApc.html.twig', [
  478. 'year' => $year,
  479. 'quater' => $quater,
  480. 'data' => $dataQuater,
  481. 'sequences' => $sequences,
  482. 'std' => $std,
  483. 'room' => $sub->getClassRoom(),
  484. 'fileExist' => $fileExist,
  485. ]);
  486. return new Response($pdf->getOutputFromHtml($html), 200, [
  487. 'Content-Type' => 'application/pdf',
  488. 'Content-Disposition' => 'inline; filename="bull_' . $quater->getId() . '_' . $std->getMatricule() . '.pdf"',
  489. ]);
  490. }
  491. /**
  492. * @Route("/{id}/reportCardYear", name="admin_students_reportcards_year", requirements={"id"="\d+"})
  493. * @Method("GET")
  494. * @Template()
  495. */
  496. public function reporCardYear(Student $std, Request $request)
  497. {
  498. if ($redirect = $this->checkAuth()) return $redirect;
  499. $headerFontSize = $request->request->get('header_font_size');
  500. $lineHeight = $request->request->get('line_height');
  501. $copyright = $request->request->get('copyright') == "on";
  502. $connection = $this->em->getConnection();
  503. $year = $this->schoolYearService->sessionYearById();
  504. $sequences = $this->seqRepo->findSequenceThisYear($year);
  505. $sub = $this->subRepo->findOneBy(["student" => $std, "schoolYear" => $year]);
  506. $filename = "assets/images/student/" . $std->getMatricule() . ".jpg";
  507. $fileExist = file_exists($filename);
  508. $i = 1;
  509. foreach ($sequences as $seq) {
  510. $sql = "CREATE OR REPLACE VIEW V_STUDENT_MARK_SEQ" . $i . " AS
  511. SELECT DISTINCT eval.id as eval, crs.id as crs, room.id as room, year.id as year,
  512. teach.id as teacher, modu.id as module, m.value as value, m.weight as weight
  513. FROM mark m
  514. JOIN student std ON m.student_id = std.id
  515. JOIN evaluation eval ON m.evaluation_id = eval.id
  516. JOIN class_room room ON eval.class_room_id = room.id
  517. JOIN course crs ON eval.course_id = crs.id
  518. JOIN attribution att ON att.course_id = crs.id
  519. JOIN user teach ON att.teacher_id = teach.id
  520. JOIN module modu ON modu.id = crs.module_id
  521. JOIN sequence seq ON seq.id = eval.sequence_id
  522. JOIN quater quat ON seq.quater_id = quat.id
  523. JOIN school_year year ON quat.school_year_id = year.id
  524. WHERE std.id = ? AND room.id = ? AND eval.sequence_id = ?
  525. ORDER BY crs.id";
  526. $connection->executeStatement($sql, [$std->getId(), $sub->getClassRoom()->getId(), $seq->getId()]);
  527. $i++;
  528. }
  529. $connection->executeStatement(
  530. "CREATE OR REPLACE VIEW V_STUDENT_MARK_QUATER1 AS
  531. SELECT DISTINCT seq1.crs as crs,
  532. (seq1.value * seq1.weight + seq2.value * seq2.weight) / (seq1.weight + seq2.weight) as value,
  533. greatest(seq1.weight, seq2.weight) as weight,
  534. seq1.teacher as teacher, seq1.module as modu, seq1.room as room
  535. FROM V_STUDENT_MARK_SEQ1 seq1
  536. JOIN V_STUDENT_MARK_SEQ2 seq2 ON seq1.crs = seq2.crs
  537. ORDER BY seq1.crs"
  538. );
  539. $connection->executeStatement(
  540. "CREATE OR REPLACE VIEW V_STUDENT_MARK_QUATER2 AS
  541. SELECT DISTINCT seq1.crs as crs,
  542. (seq1.value * seq1.weight + seq2.value * seq2.weight) / (seq1.weight + seq2.weight) as value,
  543. greatest(seq1.weight, seq2.weight) as weight,
  544. seq1.teacher as teacher, seq1.module as modu, seq1.room as room
  545. FROM V_STUDENT_MARK_SEQ3 seq1
  546. JOIN V_STUDENT_MARK_SEQ4 seq2 ON seq1.crs = seq2.crs
  547. ORDER BY seq1.crs"
  548. );
  549. $connection->executeStatement(
  550. "CREATE OR REPLACE VIEW V_STUDENT_MARK_QUATER3 AS
  551. SELECT DISTINCT seq1.crs as crs,
  552. (seq1.value * seq1.weight + seq2.value * seq2.weight) / (seq1.weight + seq2.weight) as value,
  553. greatest(seq1.weight, seq2.weight) as weight,
  554. seq1.teacher as teacher, seq1.module as modu, seq1.room as room
  555. FROM V_STUDENT_MARK_SEQ5 seq1
  556. JOIN V_STUDENT_MARK_SEQ6 seq2 ON seq1.crs = seq2.crs
  557. ORDER BY seq1.crs"
  558. );
  559. $connection->executeStatement(
  560. "CREATE OR REPLACE VIEW ANNUAL_DATA AS
  561. SELECT DISTINCT
  562. course.wording as course, course.coefficient as coef,
  563. module.name as module,
  564. user.full_name as teacher,
  565. quat1.value as value1, quat1.weight as weight1,
  566. quat2.value as value2, quat2.weight as weight2,
  567. quat3.value as value3, quat3.weight as weight3,
  568. (quat1.value * quat1.weight + quat2.value * quat2.weight + quat3.value * quat3.weight)
  569. / (quat1.weight + quat2.weight + quat3.weight) as value
  570. FROM V_STUDENT_MARK_QUATER1 quat1
  571. JOIN class_room ON class_room.id = quat1.room
  572. JOIN course ON course.id = quat1.crs
  573. JOIN module ON course.module_id = quat1.modu
  574. JOIN user ON user.id = quat1.teacher
  575. JOIN V_STUDENT_MARK_QUATER2 quat2 ON quat1.crs = quat2.crs
  576. JOIN V_STUDENT_MARK_QUATER3 quat3 ON quat2.crs = quat3.crs
  577. ORDER BY module"
  578. );
  579. $dataYear = $connection->executeQuery("SELECT * FROM ANNUAL_DATA")->fetchAllAssociative();
  580. $html = $this->renderView('student/reportcardYearApc.html.twig', [
  581. 'year' => $year,
  582. 'data' => $dataYear,
  583. 'std' => $std,
  584. 'room' => $sub->getClassRoom(),
  585. 'headerFontSize' => 0.75 * $headerFontSize,
  586. 'lineHeight' => 1.5 * $lineHeight,
  587. 'copyright' => $copyright,
  588. 'fileExist' => $fileExist,
  589. ]);
  590. return new Response($this->snappy->getOutputFromHtml($html), 200, [
  591. 'Content-Type' => 'application/pdf',
  592. 'Content-Disposition' => 'attachment; filename="BUL_ANN_' . $std->getMatricule() . '.pdf"',
  593. ]);
  594. }
  595. /**
  596. * Return classes for a selected program (AJAX)
  597. *
  598. * @Route("/admin/students/classes", name="admin_students_classes", methods={"GET"})
  599. */
  600. public function classesByProgram(Request $request)
  601. {
  602. $programId = $request->query->get('programId');
  603. if (!$programId) {
  604. return new Response('No program selected', 400);
  605. }
  606. $program = $this->em->getRepository(Program::class)->find($programId);
  607. if (!$program) {
  608. return new Response('Program not found', 404);
  609. }
  610. $classes = [];
  611. foreach ($program->getSections() as $section) {
  612. foreach ($section->getCycles() as $cycle) {
  613. foreach ($cycle->getLevels() as $level) {
  614. foreach ($level->getRooms() as $class) {
  615. $classes[] = $class;
  616. }
  617. }
  618. }
  619. }
  620. return $this->render('student/_classes_tabs.html.twig', [
  621. 'classes' => $classes,
  622. ]);
  623. }
  624. /**
  625. * Return students for a selected class and type (AJAX)
  626. *
  627. * @Route("/admin/students/list", name="admin_students_list", methods={"GET"})
  628. */
  629. public function studentList(Request $request)
  630. {
  631. $classId = $request->query->get('classId');
  632. $type = $request->query->get('type');
  633. if (!$classId) {
  634. return new Response('No class selected', 400);
  635. }
  636. $class = $this->em->getRepository(ClassRoom::class)->find($classId);
  637. if (!$class) {
  638. return new Response('Class not found', 404);
  639. }
  640. switch ($type) {
  641. case "new_students_not_yet_registered_checkbox":
  642. $students = $this->repo->findNewStudentsByClass($class);
  643. break;
  644. case "new_registered_students_checkbox":
  645. $students = $this->repo->findNewRegisteredStudentsByClass($class);
  646. break;
  647. case "registered_former_students_checkbox":
  648. $students = $this->repo->findFormerRegisteredStudentsByClass($class);
  649. break;
  650. case "complete_registered_students_checkbox":
  651. $students = $this->repo->findEnrolledStudentsByClass($class);
  652. break;
  653. default:
  654. $students = [];
  655. }
  656. return $this->render('student/_student_table.html.twig', [
  657. 'students' => $students,
  658. 'class' => $class,
  659. ]);
  660. }
  661. }