<?php
namespace App\Service;
use Mpdf\Mpdf;
use Mpdf\Output\Destination;
use Symfony\Component\HttpFoundation\Response;
class CoverSheetPdfService
{
public static function generate(
$registration = null,
$testSessionsRepository,
$testSessionProctorsRepository,
$schoolsRepository,
$collegesRepository,
$registrationsRepository,
$testSessionsService,
$locationsRepository,
$talBatchesRepository,
$studentsRepository,
$examsRepository,
$vendorsRepository,
?Mpdf $mpdf = null
) {
$toBrowser = false;
if ($registration === null) {
$toBrowser = true;
$registrationId = $_REQUEST['registrationId'];
$registration = self::masterListRegistration($registrationId, $registrationsRepository, $testSessionsService);
}
$registrationId = $registration['id'];
$testSessionId = $registration['testSessionId'];
$locationName = self::getTestSessionLocationName($testSessionId, $testSessionsRepository, $schoolsRepository, $testSessionProctorsRepository, $locationsRepository);
$testSession = $testSessionsRepository->find($testSessionId);
$proctors = $testSessionProctorsRepository->getProctorsForSession($testSessionId);
$proctorNames = [];
foreach ($proctors as $proctor) {
$proctorNames[] = $proctor['proctorTitle'] . ' ' . $proctor['proctorFirstName'] . ' ' . $proctor['proctorLastName'];
}
$student = $registration['student'];
$fullStudent = $studentsRepository->find($student['id']);
$exam = $registration['exam'];
$fullExam = $examsRepository->find($exam['id']);
$vendorName = $vendorsRepository->getVendorName($fullExam->getVendorId());
$studentId = $registration['studentId'];
if (!empty($registration['batchId'])) {
$batch = $talBatchesRepository->find($registration['batchId']);
$batchDate = self::jseDateFmt($batch->getBatchDate());
} else {
$batchDate = '';
}
$seat = $registration['seat'] ?? 'X';
$serial = $registration['serialNumber'] ?? str_pad((string) $registrationId, 10, '0', STR_PAD_LEFT);
$pastRegistrations = $registrationsRepository->getPastRegistrations($registration['id'], $studentId);
$newStudent = $pastRegistrations == 0;
$collegeId = $fullStudent->getCollege();
$collegeName = $collegeId ? $collegesRepository->getCollegeById($collegeId)['name'] : '';
$ownDoc = ($mpdf === null);
if ($ownDoc) {
$mpdf = self::makeMpdf();
}
$headerImagePath = realpath(__DIR__ . '/../../assets/images/JSEHeaderImage.JPG');
$mpdf->SetHTMLHeader(self::coverSheetHeaderHtml($headerImagePath));
$mpdf->AddPageByArray([
'orientation' => 'P',
'margin-left' => 15,
'margin-right' => 15,
'margin-top' => 50,
'margin-bottom' => 25,
'margin-header' => 3,
'margin-footer' => 0,
'resetpagenum' => 1,
]);
$mpdf->SetHTMLFooter('');
$lines = [
['title' => 'SEAT', 'data' => (string) $seat],
['title' => 'Name', 'data' => (string) $student['lastName'] . ', ' . (string) $student['firstName']],
['title' => 'Student ID', 'data' => (string) self::reJseId($fullStudent->getJseId()), 'checkbox' => true],
['title' => 'Address', 'data' => [$fullStudent->getAddress(), $fullStudent->getCity() . ', ' . $fullStudent->getState() . ' ' . $fullStudent->getZip()]],
['title' => 'DOB', 'data' => (string) self::jseDateFmt($fullStudent->getDob()), 'checkbox' => true],
['title' => 'Phone', 'data' => (string) $fullStudent->getPhone()],
['title' => 'Email', 'data' => (string) $fullStudent->getEmail()],
['title' => 'College', 'data' => (string) $collegeName, 'checkbox' => true],
['title' => 'Exam', 'data' => (string) $fullExam->getSubject() . ' - ' . (string) $vendorName . ' (' . (string) $fullExam->getDuration() . ' min.)', 'border' => true],
['title' => 'Exam Date', 'data' => (string) self::jseDateFmt($testSession->getDate())],
['title' => 'Location', 'data' => (string) $locationName],
['title' => 'Proctors', 'data' => implode(', ', $proctorNames)],
['title' => 'New Student', 'data' => (string) ($newStudent ? 'YES' : 'NO')],
['title' => 'Batch Date', 'data' => (string) $batchDate],
['title' => 'Serial Number', 'data' => (string) $serial],
];
if (!empty($registration['returnDueDate'])) {
$lines[] = ['title' => 'EXAM DUE', 'data' => (string) self::jseDateFmt($registration['returnDueDate'])];
} elseif ($testSession->getSessionType() == 22 && $testSession->getReturnDueDate()) {
$lines[] = ['title' => 'EXAM DUE', 'data' => (string) self::jseDateFmt($testSession->getReturnDueDate())];
}
$mpdf->WriteHTML(self::coverSheetBodyHtml($lines, $serial));
if (!$ownDoc) {
return null;
}
$ret = $mpdf->Output('', Destination::STRING_RETURN);
if ($toBrowser) {
$studentName = $student['lastName'] . '-' . $student['firstName'];
$mpdf->Output("coverSheet-$studentName.pdf", Destination::DOWNLOAD);
return null;
}
return $ret;
}
private static function makeMpdf(): Mpdf
{
return new Mpdf([
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 15,
'margin_right' => 15,
'margin_top' => 50,
'margin_bottom' => 25,
'margin_header' => 3,
'margin_footer' => 0,
'default_font' => 'arial',
]);
}
private static function coverSheetHeaderHtml(string $imagePath): string
{
return '
<div style="text-align:center; margin:0; padding:0;">
<img src="' . htmlspecialchars($imagePath) . '" style="width:180mm; height:45mm;" />
<div style="border-bottom:0.3mm solid #000000; width:180mm; margin-top:1mm;"></div>
</div>
';
}
private static function coverSheetBodyHtml(array $lines, string $serial): string
{
$html = '
<div style="font-family:Times; font-weight:bold; font-size:12pt; text-align:center;">
Please review the following data, correct any inaccuracies<br/>
and complete any missing information.
</div>
<div style="font-family:Times; font-weight:bold; text-decoration:underline; font-size:20pt;
text-align:center; margin-top:3mm; margin-bottom:5mm;">
Cover Sheet
</div>
';
$html .= '<table style="width:180mm; font-family:Arial; font-size:11pt;
border-collapse:collapse;" cellpadding="1">';
foreach ($lines as $line) {
$title = htmlspecialchars($line['title']);
if (isset($line['border'])) {
$data = htmlspecialchars((string) $line['data']);
$html .= '
<tr>
<td colspan="3" style="border:0.2mm solid #000000; padding:1.5mm;">
<table cellpadding="0" cellspacing="0" style="width:100%; border-collapse:collapse;">
<tr>
<td style="width:30mm; vertical-align:top;">' . $title . ':</td>
<td style="width:14mm; vertical-align:top;"></td>
<td style="vertical-align:top;">' . $data . '</td>
</tr>
</table>
</td>
</tr>
<tr><td colspan="3" style="height:4.8mm;"></td></tr>
';
}
elseif (is_array($line['data'])) {
$addrLines = array_map('htmlspecialchars', $line['data']);
$html .= '
<tr>
<td style="width:30mm; vertical-align:top;">' . $title . ':</td>
<td style="width:15mm; vertical-align:top;"></td>
<td style="vertical-align:top;">' . implode('<br/>', $addrLines) . '</td>
</tr>
<tr><td colspan="3" style="height:4.8mm;"></td></tr>
';
} elseif (isset($line['checkbox'])) {
$data = htmlspecialchars((string) $line['data']);
$html .= '
<tr>
<td style="width:30mm; vertical-align:middle;">' . $title . ':</td>
<td style="width:15mm; vertical-align:middle; text-align:center;">
<table cellpadding="0" cellspacing="0" style="border-collapse:collapse; margin:0 auto;">
<tr>
<td style="border:0.2mm solid #000000; width:5mm; height:5mm;"> </td>
</tr>
<tr>
<td style="font-size:7pt; text-align:center;">OK</td>
</tr>
</table>
</td>
<td style="vertical-align:middle;">' . $data . '</td>
</tr>
<tr><td colspan="3" style="height:4.8mm;"></td></tr>
';
} else {
$data = htmlspecialchars((string) $line['data']);
$html .= '
<tr>
<td style="width:30mm; vertical-align:top;">' . $title . ':</td>
<td style="width:15mm; vertical-align:top;"></td>
<td style="vertical-align:top;">' . $data . '</td>
</tr>
<tr><td colspan="3" style="height:4.8mm;"></td></tr>
';
}
}
$html .= '
<tr><td colspan="3" style="height:4.8mm;"></td></tr>
<tr>
<td colspan="3" style="text-align: center;">
<barcode
code="' . htmlspecialchars($serial, ENT_QUOTES, 'UTF-8') . '"
type="C128B"
size="1"
text="0"
/>
</td>
</tr>
';
$html .= '</table>';
return $html;
}
public static function masterListRegistration($registrationId, $registrationsRepository, $testSessionsService)
{
$testSessionId = $registrationsRepository->find($registrationId)->getTestSessionId();
if (!$testSessionId) {
return null;
}
$masterListData = $testSessionsService->getMasterListData($testSessionId);
foreach ($masterListData['sections'] as $section) {
foreach ($section['registrations'] as $registration) {
if ($registration['id'] == $registrationId) {
$registration['testSessionId'] = $testSessionId;
return $registration;
}
}
}
return null;
}
public static function getTestSessionLocationName($testSessionId, $testSessionsRepository, $schoolsRepository, $proctorsRepository, $locationsRepository)
{
$testSession = $testSessionsRepository->find($testSessionId);
if ($testSession->getSessionType() == 21) {
$locationId = $testSession->getLocationId();
if ($locationId) {
return $locationsRepository->find($locationId)->getName();
}
} elseif ($testSession->getSessionType() == 22) {
return $schoolsRepository->find($testSession->getSchoolId())->getName();
} elseif ($testSession->getSessionType() == 23) {
$proctor = $proctorsRepository->find($testSession->getProctorId());
return trim($proctor->getCity() . ', ' . $proctor->getState(), ' ,') . ': ' . $proctor->getLast() . ', ' . $proctor->getFirst();
}
return '';
}
public static function getNewStudentStatus($registrationId, $studentId, $registrationsRepository): int
{
$thisRegistrations = $registrationsRepository->findTestSessionInfoForRegistration($registrationId);
if ($thisRegistrations['sessionType'] == 23) {
$compareDate = $thisRegistrations['returnDueDate'];
} else {
$compareDate = $thisRegistrations['date'];
}
$allRegistrations = $registrationsRepository->findPreviousRegistrations($registrationId, $studentId, $compareDate);
return !$allRegistrations ? 0 : 1;
}
public static function jseDateFmt($dt): string
{
if (!$dt) {
return '';
}
if ($dt instanceof \DateTime || $dt instanceof \DateTimeImmutable) {
return $dt->format('n/j/Y');
}
try {
return (new \DateTime($dt))->format('n/j/Y');
} catch (\Exception $e) {
return '';
}
}
public static function reJseId($jseId)
{
if (strlen($jseId) == 12) {
return $jseId;
}
[$mmddyy, $ssn] = explode('-', $jseId);
if (!$mmddyy || !$ssn) {
return $jseId;
}
$mmdd = substr($mmddyy, 0, 4);
$yy = substr($mmddyy, -2);
return "$mmdd-$yy-$ssn";
}
}