reconstruction of the project
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\AttendanceTracking;
|
||||
|
||||
use App\Models\AttendanceEmailTemplate;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AttendanceEmailComposerService
|
||||
{
|
||||
public function __construct(
|
||||
protected AttendanceEmailTemplate $attendanceEmailTemplateModel
|
||||
) {
|
||||
}
|
||||
|
||||
public function buildTemplateContext(array $violation, ?array $parent = null): array
|
||||
{
|
||||
$studentName = (string) ($violation['name'] ?? '');
|
||||
$incident = (string) ($violation['last_date'] ?? date('Y-m-d'));
|
||||
|
||||
return [
|
||||
'{{parent_name}}' => (string) ($parent['parent_name'] ?? 'Parent/Guardian'),
|
||||
'{{student_name}}' => $studentName,
|
||||
'{{incident_date}}' => $incident,
|
||||
'{{school_phone}}' => '978-364-0219',
|
||||
'{{voicemail_phone}}' => (string) ($parent['phone'] ?? '—'),
|
||||
'{{class_time}}' => '10:00 AM',
|
||||
];
|
||||
}
|
||||
|
||||
public function renderTemplate(string $code, string $variant, array $context): ?array
|
||||
{
|
||||
$row = null;
|
||||
|
||||
if (method_exists($this->attendanceEmailTemplateModel, 'getTemplate')) {
|
||||
$row = $this->attendanceEmailTemplateModel->getTemplate($code, $variant)
|
||||
?: $this->attendanceEmailTemplateModel->getTemplate($code, 'default');
|
||||
} else {
|
||||
$row = $this->attendanceEmailTemplateModel->query()
|
||||
->where('code', $code)
|
||||
->where('variant', $variant)
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
|
||||
if (!$row) {
|
||||
$row = $this->attendanceEmailTemplateModel->query()
|
||||
->where('code', $code)
|
||||
->where('variant', 'default')
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
}
|
||||
|
||||
$row = $row?->toArray();
|
||||
}
|
||||
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$subject = strtr($row['subject'], $context);
|
||||
$body = strtr($row['body_html'], $context);
|
||||
|
||||
return [$subject, $body];
|
||||
}
|
||||
|
||||
public function renderWithEmailLayout(string $subject, string $bodyHtml): string
|
||||
{
|
||||
return view('emails._wrap_layout', [
|
||||
'title' => $subject,
|
||||
'body_html' => $bodyHtml,
|
||||
])->render();
|
||||
}
|
||||
|
||||
public function pickVariant(string $code, ?string $globalVariantOverride = null): string
|
||||
{
|
||||
if (!empty($globalVariantOverride)) {
|
||||
return $globalVariantOverride;
|
||||
}
|
||||
|
||||
return match ($code) {
|
||||
'ABS_2', 'ABS_2_IN3W' => 'no_answer',
|
||||
default => 'default',
|
||||
};
|
||||
}
|
||||
|
||||
public function buildFallbackAutoEmail(string $code, array $violation, string $parentName = ''): array
|
||||
{
|
||||
$subject = match ($code) {
|
||||
'ABS_1' => 'Attendance Notice: Unreported Absence',
|
||||
'LATE_2' => 'Attendance Notice: Repeated Lateness',
|
||||
default => 'Attendance Notice',
|
||||
};
|
||||
|
||||
$studentName = (string) ($violation['name'] ?? '');
|
||||
$date = (string) ($violation['last_date'] ?? date('Y-m-d'));
|
||||
|
||||
$body = "<p>Dear " . ($parentName ?: 'Parent/Guardian') . "</p>"
|
||||
. "<p>We'd like to inform you about your student's recent attendance:</p>"
|
||||
. "<ul>"
|
||||
. "<li><strong>Student:</strong> {$studentName}</li>"
|
||||
. "<li><strong>Issue:</strong> " . (string) ($violation['violation'] ?? '') . "</li>"
|
||||
. "<li><strong>As of:</strong> {$date}</li>"
|
||||
. "</ul>"
|
||||
. "<p>If you have any questions, please contact the school office.</p>";
|
||||
|
||||
return [$subject, $body];
|
||||
}
|
||||
|
||||
public function normalizeBodyToHtml(string $bodyInput): string
|
||||
{
|
||||
if ($bodyInput !== '' && preg_match('/<[^>]+>/', $bodyInput)) {
|
||||
return $bodyInput;
|
||||
}
|
||||
|
||||
if ($bodyInput !== '' && stripos($bodyInput, '<') !== false) {
|
||||
$decoded = html_entity_decode($bodyInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
if (preg_match('/<[^>]+>/', $decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return nl2br(e($bodyInput), false);
|
||||
}
|
||||
|
||||
public function plainTextToHtml(string $text): string
|
||||
{
|
||||
$text = preg_replace("/\r\n?/", "\n", trim($text));
|
||||
|
||||
if ($text === '') {
|
||||
return '<p></p>';
|
||||
}
|
||||
|
||||
$escaped = htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
|
||||
$escaped = preg_replace_callback(
|
||||
'#\bhttps?://[^\s<]+#i',
|
||||
static function ($m) {
|
||||
$url = $m[0];
|
||||
$urlAttr = htmlspecialchars($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
return '<a href="' . $urlAttr . '" target="_blank" rel="noopener noreferrer">' . $url . '</a>';
|
||||
},
|
||||
$escaped
|
||||
);
|
||||
|
||||
$paragraphs = preg_split("/\n{2,}/", $escaped);
|
||||
|
||||
$paragraphs = array_map(static function ($p) {
|
||||
$p = preg_replace("/\n/", "<br>", $p);
|
||||
return '<p>' . $p . '</p>';
|
||||
}, $paragraphs);
|
||||
|
||||
return implode("\n", $paragraphs);
|
||||
}
|
||||
|
||||
public function renderAutoEmailFor(array $violation, ?array $parent = null): ?array
|
||||
{
|
||||
$code = (string) ($violation['violation_code'] ?? $violation['code'] ?? '');
|
||||
$ctx = $this->buildTemplateContext($violation, $parent);
|
||||
$tpl = $this->renderTemplate($code, 'default', $ctx);
|
||||
|
||||
if (!$tpl) {
|
||||
return $this->buildFallbackAutoEmail($code, $violation, (string) ($parent['parent_name'] ?? ''));
|
||||
}
|
||||
|
||||
return $tpl;
|
||||
}
|
||||
|
||||
public function composePreview(
|
||||
int $studentId,
|
||||
array $student,
|
||||
?array $primaryParent,
|
||||
?array $secondaryParent,
|
||||
string $code,
|
||||
string $variant,
|
||||
?string $incidentDate = null
|
||||
): array {
|
||||
$lastDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) $incidentDate)
|
||||
? $incidentDate
|
||||
: date('Y-m-d');
|
||||
|
||||
$violation = [
|
||||
'id' => $studentId,
|
||||
'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
|
||||
'last_date' => $lastDate,
|
||||
'violation' => $code,
|
||||
'violation_code' => $code,
|
||||
];
|
||||
|
||||
$ctx = $this->buildTemplateContext($violation, $primaryParent);
|
||||
$rendered = $this->renderTemplate($code, $variant, $ctx);
|
||||
|
||||
if (!$rendered) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "Template not found for {$code} ({$variant}).",
|
||||
'status' => 404,
|
||||
];
|
||||
}
|
||||
|
||||
[$subject, $body] = $rendered;
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'student_id' => $studentId,
|
||||
'student_name' => $violation['name'],
|
||||
'parent_email' => (string) ($primaryParent['email'] ?? ''),
|
||||
'parent_name' => (string) ($primaryParent['parent_name'] ?? ''),
|
||||
'secondary_email' => (string) ($secondaryParent['email'] ?? ''),
|
||||
'secondary_name' => (string) ($secondaryParent['parent_name'] ?? ''),
|
||||
'code' => $code,
|
||||
'variant' => $variant,
|
||||
'subject' => $subject,
|
||||
'body_html' => $body,
|
||||
'incident_date' => $lastDate,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user