recreate project
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user