src/Service/CoverSheetPdfService.php line 10

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use Mpdf\Mpdf;
  4. use Mpdf\Output\Destination;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class CoverSheetPdfService
  7. {
  8. public static function generate(
  9. $registration = null,
  10. $testSessionsRepository,
  11. $testSessionProctorsRepository,
  12. $schoolsRepository,
  13. $collegesRepository,
  14. $registrationsRepository,
  15. $testSessionsService,
  16. $locationsRepository,
  17. $talBatchesRepository,
  18. $studentsRepository,
  19. $examsRepository,
  20. $vendorsRepository,
  21. ?Mpdf $mpdf = null
  22. ) {
  23. $toBrowser = false;
  24. if ($registration === null) {
  25. $toBrowser = true;
  26. $registrationId = $_REQUEST['registrationId'];
  27. $registration = self::masterListRegistration($registrationId, $registrationsRepository, $testSessionsService);
  28. }
  29. $registrationId = $registration['id'];
  30. $testSessionId = $registration['testSessionId'];
  31. $locationName = self::getTestSessionLocationName($testSessionId, $testSessionsRepository, $schoolsRepository, $testSessionProctorsRepository, $locationsRepository);
  32. $testSession = $testSessionsRepository->find($testSessionId);
  33. $proctors = $testSessionProctorsRepository->getProctorsForSession($testSessionId);
  34. $proctorNames = [];
  35. foreach ($proctors as $proctor) {
  36. $proctorNames[] = $proctor['proctorTitle'] . ' ' . $proctor['proctorFirstName'] . ' ' . $proctor['proctorLastName'];
  37. }
  38. $student = $registration['student'];
  39. $fullStudent = $studentsRepository->find($student['id']);
  40. $exam = $registration['exam'];
  41. $fullExam = $examsRepository->find($exam['id']);
  42. $vendorName = $vendorsRepository->getVendorName($fullExam->getVendorId());
  43. $studentId = $registration['studentId'];
  44. if (!empty($registration['batchId'])) {
  45. $batch = $talBatchesRepository->find($registration['batchId']);
  46. $batchDate = self::jseDateFmt($batch->getBatchDate());
  47. } else {
  48. $batchDate = '';
  49. }
  50. $seat = $registration['seat'] ?? 'X';
  51. $serial = $registration['serialNumber'] ?? str_pad((string) $registrationId, 10, '0', STR_PAD_LEFT);
  52. $pastRegistrations = $registrationsRepository->getPastRegistrations($registration['id'], $studentId);
  53. $newStudent = $pastRegistrations == 0;
  54. $collegeId = $fullStudent->getCollege();
  55. $collegeName = $collegeId ? $collegesRepository->getCollegeById($collegeId)['name'] : '';
  56. $ownDoc = ($mpdf === null);
  57. if ($ownDoc) {
  58. $mpdf = self::makeMpdf();
  59. }
  60. $headerImagePath = realpath(__DIR__ . '/../../assets/images/JSEHeaderImage.JPG');
  61. $mpdf->SetHTMLHeader(self::coverSheetHeaderHtml($headerImagePath));
  62. $mpdf->AddPageByArray([
  63. 'orientation' => 'P',
  64. 'margin-left' => 15,
  65. 'margin-right' => 15,
  66. 'margin-top' => 50,
  67. 'margin-bottom' => 25,
  68. 'margin-header' => 3,
  69. 'margin-footer' => 0,
  70. 'resetpagenum' => 1,
  71. ]);
  72. $mpdf->SetHTMLFooter('');
  73. $lines = [
  74. ['title' => 'SEAT', 'data' => (string) $seat],
  75. ['title' => 'Name', 'data' => (string) $student['lastName'] . ', ' . (string) $student['firstName']],
  76. ['title' => 'Student ID', 'data' => (string) self::reJseId($fullStudent->getJseId()), 'checkbox' => true],
  77. ['title' => 'Address', 'data' => [$fullStudent->getAddress(), $fullStudent->getCity() . ', ' . $fullStudent->getState() . ' ' . $fullStudent->getZip()]],
  78. ['title' => 'DOB', 'data' => (string) self::jseDateFmt($fullStudent->getDob()), 'checkbox' => true],
  79. ['title' => 'Phone', 'data' => (string) $fullStudent->getPhone()],
  80. ['title' => 'Email', 'data' => (string) $fullStudent->getEmail()],
  81. ['title' => 'College', 'data' => (string) $collegeName, 'checkbox' => true],
  82. ['title' => 'Exam', 'data' => (string) $fullExam->getSubject() . ' - ' . (string) $vendorName . ' (' . (string) $fullExam->getDuration() . ' min.)', 'border' => true],
  83. ['title' => 'Exam Date', 'data' => (string) self::jseDateFmt($testSession->getDate())],
  84. ['title' => 'Location', 'data' => (string) $locationName],
  85. ['title' => 'Proctors', 'data' => implode(', ', $proctorNames)],
  86. ['title' => 'New Student', 'data' => (string) ($newStudent ? 'YES' : 'NO')],
  87. ['title' => 'Batch Date', 'data' => (string) $batchDate],
  88. ['title' => 'Serial Number', 'data' => (string) $serial],
  89. ];
  90. if (!empty($registration['returnDueDate'])) {
  91. $lines[] = ['title' => 'EXAM DUE', 'data' => (string) self::jseDateFmt($registration['returnDueDate'])];
  92. } elseif ($testSession->getSessionType() == 22 && $testSession->getReturnDueDate()) {
  93. $lines[] = ['title' => 'EXAM DUE', 'data' => (string) self::jseDateFmt($testSession->getReturnDueDate())];
  94. }
  95. $mpdf->WriteHTML(self::coverSheetBodyHtml($lines, $serial));
  96. if (!$ownDoc) {
  97. return null;
  98. }
  99. $ret = $mpdf->Output('', Destination::STRING_RETURN);
  100. if ($toBrowser) {
  101. $studentName = $student['lastName'] . '-' . $student['firstName'];
  102. $mpdf->Output("coverSheet-$studentName.pdf", Destination::DOWNLOAD);
  103. return null;
  104. }
  105. return $ret;
  106. }
  107. private static function makeMpdf(): Mpdf
  108. {
  109. return new Mpdf([
  110. 'mode' => 'utf-8',
  111. 'format' => 'A4',
  112. 'margin_left' => 15,
  113. 'margin_right' => 15,
  114. 'margin_top' => 50,
  115. 'margin_bottom' => 25,
  116. 'margin_header' => 3,
  117. 'margin_footer' => 0,
  118. 'default_font' => 'arial',
  119. ]);
  120. }
  121. private static function coverSheetHeaderHtml(string $imagePath): string
  122. {
  123. return '
  124. <div style="text-align:center; margin:0; padding:0;">
  125. <img src="' . htmlspecialchars($imagePath) . '" style="width:180mm; height:45mm;" />
  126. <div style="border-bottom:0.3mm solid #000000; width:180mm; margin-top:1mm;"></div>
  127. </div>
  128. ';
  129. }
  130. private static function coverSheetBodyHtml(array $lines, string $serial): string
  131. {
  132. $html = '
  133. <div style="font-family:Times; font-weight:bold; font-size:12pt; text-align:center;">
  134. Please review the following data, correct any inaccuracies<br/>
  135. and complete any missing information.
  136. </div>
  137. <div style="font-family:Times; font-weight:bold; text-decoration:underline; font-size:20pt;
  138. text-align:center; margin-top:3mm; margin-bottom:5mm;">
  139. Cover Sheet
  140. </div>
  141. ';
  142. $html .= '<table style="width:180mm; font-family:Arial; font-size:11pt;
  143. border-collapse:collapse;" cellpadding="1">';
  144. foreach ($lines as $line) {
  145. $title = htmlspecialchars($line['title']);
  146. if (isset($line['border'])) {
  147. $data = htmlspecialchars((string) $line['data']);
  148. $html .= '
  149. <tr>
  150. <td colspan="3" style="border:0.2mm solid #000000; padding:1.5mm;">
  151. <table cellpadding="0" cellspacing="0" style="width:100%; border-collapse:collapse;">
  152. <tr>
  153. <td style="width:30mm; vertical-align:top;">' . $title . ':</td>
  154. <td style="width:14mm; vertical-align:top;"></td>
  155. <td style="vertical-align:top;">' . $data . '</td>
  156. </tr>
  157. </table>
  158. </td>
  159. </tr>
  160. <tr><td colspan="3" style="height:4.8mm;"></td></tr>
  161. ';
  162. }
  163. elseif (is_array($line['data'])) {
  164. $addrLines = array_map('htmlspecialchars', $line['data']);
  165. $html .= '
  166. <tr>
  167. <td style="width:30mm; vertical-align:top;">' . $title . ':</td>
  168. <td style="width:15mm; vertical-align:top;"></td>
  169. <td style="vertical-align:top;">' . implode('<br/>', $addrLines) . '</td>
  170. </tr>
  171. <tr><td colspan="3" style="height:4.8mm;"></td></tr>
  172. ';
  173. } elseif (isset($line['checkbox'])) {
  174. $data = htmlspecialchars((string) $line['data']);
  175. $html .= '
  176. <tr>
  177. <td style="width:30mm; vertical-align:middle;">' . $title . ':</td>
  178. <td style="width:15mm; vertical-align:middle; text-align:center;">
  179. <table cellpadding="0" cellspacing="0" style="border-collapse:collapse; margin:0 auto;">
  180. <tr>
  181. <td style="border:0.2mm solid #000000; width:5mm; height:5mm;">&nbsp;</td>
  182. </tr>
  183. <tr>
  184. <td style="font-size:7pt; text-align:center;">OK</td>
  185. </tr>
  186. </table>
  187. </td>
  188. <td style="vertical-align:middle;">' . $data . '</td>
  189. </tr>
  190. <tr><td colspan="3" style="height:4.8mm;"></td></tr>
  191. ';
  192. } else {
  193. $data = htmlspecialchars((string) $line['data']);
  194. $html .= '
  195. <tr>
  196. <td style="width:30mm; vertical-align:top;">' . $title . ':</td>
  197. <td style="width:15mm; vertical-align:top;"></td>
  198. <td style="vertical-align:top;">' . $data . '</td>
  199. </tr>
  200. <tr><td colspan="3" style="height:4.8mm;"></td></tr>
  201. ';
  202. }
  203. }
  204. $html .= '
  205. <tr><td colspan="3" style="height:4.8mm;"></td></tr>
  206. <tr>
  207. <td colspan="3" style="text-align: center;">
  208. <barcode
  209. code="' . htmlspecialchars($serial, ENT_QUOTES, 'UTF-8') . '"
  210. type="C128B"
  211. size="1"
  212. text="0"
  213. />
  214. </td>
  215. </tr>
  216. ';
  217. $html .= '</table>';
  218. return $html;
  219. }
  220. public static function masterListRegistration($registrationId, $registrationsRepository, $testSessionsService)
  221. {
  222. $testSessionId = $registrationsRepository->find($registrationId)->getTestSessionId();
  223. if (!$testSessionId) {
  224. return null;
  225. }
  226. $masterListData = $testSessionsService->getMasterListData($testSessionId);
  227. foreach ($masterListData['sections'] as $section) {
  228. foreach ($section['registrations'] as $registration) {
  229. if ($registration['id'] == $registrationId) {
  230. $registration['testSessionId'] = $testSessionId;
  231. return $registration;
  232. }
  233. }
  234. }
  235. return null;
  236. }
  237. public static function getTestSessionLocationName($testSessionId, $testSessionsRepository, $schoolsRepository, $proctorsRepository, $locationsRepository)
  238. {
  239. $testSession = $testSessionsRepository->find($testSessionId);
  240. if ($testSession->getSessionType() == 21) {
  241. $locationId = $testSession->getLocationId();
  242. if ($locationId) {
  243. return $locationsRepository->find($locationId)->getName();
  244. }
  245. } elseif ($testSession->getSessionType() == 22) {
  246. return $schoolsRepository->find($testSession->getSchoolId())->getName();
  247. } elseif ($testSession->getSessionType() == 23) {
  248. $proctor = $proctorsRepository->find($testSession->getProctorId());
  249. return trim($proctor->getCity() . ', ' . $proctor->getState(), ' ,') . ': ' . $proctor->getLast() . ', ' . $proctor->getFirst();
  250. }
  251. return '';
  252. }
  253. public static function getNewStudentStatus($registrationId, $studentId, $registrationsRepository): int
  254. {
  255. $thisRegistrations = $registrationsRepository->findTestSessionInfoForRegistration($registrationId);
  256. if ($thisRegistrations['sessionType'] == 23) {
  257. $compareDate = $thisRegistrations['returnDueDate'];
  258. } else {
  259. $compareDate = $thisRegistrations['date'];
  260. }
  261. $allRegistrations = $registrationsRepository->findPreviousRegistrations($registrationId, $studentId, $compareDate);
  262. return !$allRegistrations ? 0 : 1;
  263. }
  264. public static function jseDateFmt($dt): string
  265. {
  266. if (!$dt) {
  267. return '';
  268. }
  269. if ($dt instanceof \DateTime || $dt instanceof \DateTimeImmutable) {
  270. return $dt->format('n/j/Y');
  271. }
  272. try {
  273. return (new \DateTime($dt))->format('n/j/Y');
  274. } catch (\Exception $e) {
  275. return '';
  276. }
  277. }
  278. public static function reJseId($jseId)
  279. {
  280. if (strlen($jseId) == 12) {
  281. return $jseId;
  282. }
  283. [$mmddyy, $ssn] = explode('-', $jseId);
  284. if (!$mmddyy || !$ssn) {
  285. return $jseId;
  286. }
  287. $mmdd = substr($mmddyy, 0, 4);
  288. $yy = substr($mmddyy, -2);
  289. return "$mmdd-$yy-$ssn";
  290. }
  291. }