Files
2026-02-10 22:11:06 -05:00

173 lines
7.9 KiB
PHP

<?php
namespace App\Controllers\View;
use App\Controllers\BaseController;
use App\Models\StudentModel;
use App\Models\FamilyModel;
use App\Models\FamilyStudentModel;
use App\Models\FamilyGuardianModel;
use App\Models\FamilyCommPrefModel; // optional
use App\Models\EmailTemplateModel;
use App\Models\CommunicationLogModel;
class CommunicationController extends BaseController
{
protected StudentModel $studentModel;
protected FamilyModel $familyModel;
protected FamilyStudentModel $fsModel;
protected FamilyGuardianModel $fgModel;
protected ?FamilyCommPrefModel $fcpModel = null;
protected EmailTemplateModel $templateModel;
protected CommunicationLogModel $logModel;
public function __construct()
{
$this->studentModel = new StudentModel();
$this->familyModel = new FamilyModel();
$this->fsModel = new FamilyStudentModel();
$this->fgModel = new FamilyGuardianModel();
if (class_exists(FamilyCommPrefModel::class)) {
$this->fcpModel = new FamilyCommPrefModel();
}
$this->templateModel = new EmailTemplateModel();
$this->logModel = new CommunicationLogModel();
}
public function index()
{
$students = $this->studentModel->orderBy('lastname, firstname', 'asc')->findAll();
$templates = $this->templateModel->getActiveTemplates();
return view('communications/index', compact('students','templates'));
}
// AJAX: families for a student
public function families(int $studentId)
{
if (!$this->request->isAJAX()) return $this->response->setStatusCode(400)->setJSON(['error' => 'Bad request']);
$families = $this->fsModel->getFamiliesForStudent($studentId);
return $this->response->setJSON(['data' => $families]);
}
// AJAX: guardians for a family
public function guardians(int $familyId)
{
if (!$this->request->isAJAX()) return $this->response->setStatusCode(400)->setJSON(['error' => 'Bad request']);
$db = \Config\Database::connect();
$rows = $db->query("SELECT u.id as user_id, u.firstname, u.lastname, u.email, fg.relation, fg.is_primary, fg.receive_emails, fg.receive_sms\n FROM family_guardians fg\n JOIN users u ON u.id = fg.user_id\n WHERE fg.family_id = ?", [$familyId])->getResultArray();
return $this->response->setJSON(['data' => $rows]);
}
public function preview()
{
if (!$this->request->isAJAX()) return $this->response->setStatusCode(400)->setJSON(['error' => 'Bad request']);
$templateKey = (string) $this->request->getPost('template_key');
$studentId = (int) $this->request->getPost('student_id');
$familyId = (int) $this->request->getPost('family_id');
$varsPost = $this->request->getPost('vars');
$vars = is_array($varsPost) ? $varsPost : json_decode((string)$varsPost, true) ?? [];
$template = $this->templateModel->findByKey($templateKey);
if (!$template) return $this->response->setStatusCode(404)->setJSON(['error' => 'Template not found']);
$student = $this->studentModel->getStudentBasic($studentId);
if (!$student) return $this->response->setStatusCode(404)->setJSON(['error' => 'Student not found']);
// Build salutation from guardians in the chosen family
$db = \Config\Database::connect();
$gs = $db->query("SELECT u.firstname, u.lastname\n FROM family_guardians fg\n JOIN users u ON u.id = fg.user_id\n WHERE fg.family_id = ? AND fg.receive_emails = 1\n ORDER BY fg.is_primary DESC, u.lastname, u.firstname", [$familyId])->getResultArray();
$sal = 'Parent/Guardian';
if ($gs) {
$names = array_map(fn($r)=> trim(($r['firstname']??'').' '.($r['lastname']??'')), $gs);
$sal = implode(' & ', $names);
}
$autoVars = [
'student_fullname' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')),
'student_grade' => $student['grade'] ?? '',
'parent_salutation'=> $sal,
'date' => local_date(utc_now(), 'Y-m-d'),
'school_name' => 'Al Rahma Sunday School',
'teacher_name' => (string)(session('display_name') ?? 'Teacher'),
];
$all = array_merge($autoVars, $vars);
$subject = $this->renderTwig($template['subject'], $all);
$body = nl2br($this->renderTwig($template['body'], $all));
return $this->response->setJSON(['subject' => $subject, 'html' => $body]);
}
public function send()
{
$rules = [
'student_id' => 'required|integer',
'family_id' => 'required|integer',
'template_key' => 'required|string',
'subject' => 'required|string',
'body' => 'required|string',
'recipients' => 'required|string' // JSON array
];
if (!$this->validate($rules)) {
return redirect()->back()->with('error', 'Invalid form submission.');
}
$studentId = (int) $this->request->getPost('student_id');
$familyId = (int) $this->request->getPost('family_id');
$templateKey = (string) $this->request->getPost('template_key');
$subject = (string) $this->request->getPost('subject');
$bodyHtml = (string) $this->request->getPost('body');
$recipients = json_decode((string)$this->request->getPost('recipients'), true) ?? [];
$cc = json_decode((string)($this->request->getPost('cc') ?? '[]'), true) ?? [];
$bcc = json_decode((string)($this->request->getPost('bcc') ?? '[]'), true) ?? [];
$student = $this->studentModel->getStudentBasic($studentId);
if (!$student) return redirect()->back()->with('error', 'Student not found');
// Send email (PHPMailer via service('mailer'))
$sendOk = false; $error = null;
try {
$mailer = service('mailer');
foreach (array_unique($recipients) as $to) { if ($to) $mailer->addAddress($to); }
foreach (array_unique($cc) as $c) { if ($c) $mailer->addCC($c); }
foreach (array_unique($bcc) as $b){ if ($b) $mailer->addBCC($b); }
$mailer->Subject = $subject;
$mailer->isHTML(true);
$mailer->Body = $bodyHtml;
$mailer->AltBody = strip_tags($bodyHtml);
$sendOk = $mailer->send();
} catch (\Throwable $t) {
$error = $t->getMessage();
}
// Log
$this->logModel->insert([
'student_id' => $studentId,
'family_id' => $familyId,
'student_name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')),
'template_key' => $templateKey,
'subject' => $subject,
'body' => $bodyHtml,
'recipients' => json_encode(array_values($recipients)),
'cc' => json_encode(array_values($cc)),
'bcc' => json_encode(array_values($bcc)),
'status' => $sendOk ? 'sent' : 'failed',
'error_message'=> $error,
'sent_by' => (int)(session('user_id') ?? 0),
'metadata' => null,
]);
return $sendOk
? redirect()->to('/communications')->with('success', 'Email sent successfully.')
: redirect()->back()->with('error', 'Failed to send email: '.($error ?? 'Unknown error'));
}
private function renderTwig(string $template, array $vars): string
{
return preg_replace_callback('/\{\{\s*([a-zA-Z0-9_\.]+)\s*\}\}/', function($m) use ($vars) {
$key = $m[1];
return htmlspecialchars((string)($vars[$key] ?? ''), ENT_QUOTES, 'UTF-8');
}, $template);
}
}