Files
alrahma_sunday_school/app/Controllers/ParentProgressController.php
T

320 lines
11 KiB
PHP

<?php
namespace App\Controllers;
use App\Controllers\ClassProgressController;
use App\Models\ClassProgressAttachmentModel;
use App\Models\ClassProgressReportModel;
use App\Models\EnrollmentModel;
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Exceptions\PageNotFoundException;
use Config\Database;
class ParentProgressController extends BaseController
{
protected ClassProgressReportModel $reportModel;
protected ClassProgressAttachmentModel $attachmentModel;
protected EnrollmentModel $enrollmentModel;
protected BaseConnection $db;
private ?array $parentSectionIds = null;
public function __construct()
{
helper(['url', 'form']);
$this->reportModel = new ClassProgressReportModel();
$this->attachmentModel = new ClassProgressAttachmentModel();
$this->enrollmentModel = new EnrollmentModel();
$this->db = Database::connect();
}
public function index()
{
$students = $this->getParentStudents();
$sectionIds = array_values(array_unique(array_filter(array_map(
static fn (array $student): int => (int) ($student['class_section_id'] ?? 0),
$students
))));
$subjectSections = ClassProgressController::SUBJECT_SECTIONS;
$rows = [];
if (! empty($sectionIds)) {
$builder = $this->reportModel
->select('class_progress_reports.*, cs.class_section_name, CONCAT(IFNULL(u.firstname, ""), " ", IFNULL(u.lastname, "")) AS teacher_name')
->join('classSection cs', 'cs.class_section_id = class_progress_reports.class_section_id', 'left')
->join('users u', 'u.id = class_progress_reports.teacher_id', 'left')
->whereIn('class_progress_reports.class_section_id', $sectionIds);
$rows = $builder
->orderBy('week_start', 'DESC')
->findAll();
}
$studentReportGroups = [];
foreach ($students as $student) {
$studentId = (int) ($student['student_id'] ?? 0);
if ($studentId === 0) {
continue;
}
$classSectionId = (int) ($student['class_section_id'] ?? 0);
$studentRows = $classSectionId
? array_values(array_filter(
$rows,
static fn (array $row): bool => (int) ($row['class_section_id'] ?? 0) === $classSectionId
))
: [];
$studentReportGroups[$studentId] = $this->groupReportsByWeek($studentRows);
}
return view('parent/class_progress_list', [
'students' => $students,
'studentReportGroups' => $studentReportGroups,
'subjectSections' => $subjectSections,
'hasStudents' => ! empty($students),
]);
}
public function view($id)
{
$row = $this->reportModel
->select('class_progress_reports.*, cs.class_section_name, CONCAT(IFNULL(u.firstname, ""), " ", IFNULL(u.lastname, "")) AS teacher_name')
->join('classSection cs', 'cs.class_section_id = class_progress_reports.class_section_id', 'left')
->join('users u', 'u.id = class_progress_reports.teacher_id', 'left')
->find((int) $id);
if (! $row || ! $this->isSectionAccessible($row['class_section_id'] ?? null)) {
throw new PageNotFoundException('Progress report not found.');
}
$row['status_label'] = ClassProgressController::STATUS_OPTIONS[$row['status']] ?? 'Unknown';
$row['flags'] = $this->decodeFlags($row['flags_json']);
$weeklyReports = $this->reportModel
->select('class_progress_reports.*')
->where('class_section_id', $row['class_section_id'])
->where('week_start', $row['week_start'])
->orderBy('subject', 'ASC')
->findAll();
$attachmentMap = $this->loadAttachmentsForReports(array_column($weeklyReports, 'id'));
foreach ($weeklyReports as &$report) {
$report['attachments'] = $attachmentMap[$report['id']] ?? [];
if (empty($report['attachments']) && ! empty($report['attachment_path'])) {
$report['attachments'][] = [
'id' => $report['id'],
'name' => basename((string) $report['attachment_path']),
'legacy' => true,
];
}
}
return view('parent/class_progress_view', [
'row' => $row,
'weeklyReports' => $weeklyReports,
'subjectSections' => ClassProgressController::SUBJECT_SECTIONS,
]);
}
public function attachment($id)
{
$row = $this->reportModel->find((int) $id);
if (! $row || ! $this->isSectionAccessible($row['class_section_id'] ?? null) || empty($row['attachment_path'])) {
throw new PageNotFoundException('Attachment not found.');
}
$file = $this->resolveAttachmentFile($row);
if (! $file) {
throw new PageNotFoundException('Attachment missing.');
}
return $this->response->download($file, null)->setFileName(basename($file));
}
public function attachmentFile($id)
{
$attachment = $this->attachmentModel->find((int) $id);
if (! $attachment || empty($attachment['file_path'])) {
throw new PageNotFoundException('Attachment not found.');
}
$report = $this->reportModel->find((int) ($attachment['report_id'] ?? 0));
if (! $report || ! $this->isSectionAccessible($report['class_section_id'] ?? null)) {
throw new PageNotFoundException('Attachment not found.');
}
$file = $this->resolveAttachmentPath($attachment['file_path']);
if (! $file) {
throw new PageNotFoundException('Attachment missing.');
}
$downloadName = $attachment['original_name'] ?: basename($file);
return $this->response->download($file, null)->setFileName($downloadName);
}
protected function getParentSectionIds(): array
{
if ($this->parentSectionIds !== null) {
return $this->parentSectionIds;
}
$parentId = (int) session()->get('user_id');
if ($parentId === 0) {
$this->parentSectionIds = [];
return $this->parentSectionIds;
}
$rows = $this->enrollmentModel
->select('class_section_id')
->where('parent_id', $parentId)
->where('is_withdrawn', 0)
->groupBy('class_section_id')
->findAll();
$ids = [];
foreach ($rows as $row) {
$classSectionId = (int) ($row['class_section_id'] ?? 0);
if ($classSectionId > 0) {
$ids[] = $classSectionId;
}
}
$this->parentSectionIds = array_values(array_unique($ids));
return $this->parentSectionIds;
}
protected function buildSectionOptions(array $sectionIds): array
{
if (empty($sectionIds)) {
return [];
}
$rows = $this->db->table('classSection')
->select('class_section_id, class_section_name')
->whereIn('class_section_id', $sectionIds)
->orderBy('class_section_name', 'ASC')
->get()
->getResultArray();
$options = [];
foreach ($rows as $row) {
$options[(int) ($row['class_section_id'] ?? 0)] = $row['class_section_name'] ?? 'Unknown section';
}
return $options;
}
protected function getParentStudents(): array
{
$parentId = (int) session()->get('user_id');
if ($parentId === 0) {
return [];
}
$rows = $this->db->table('enrollments e')
->select('e.student_id, e.class_section_id, e.updated_at, e.created_at, s.firstname, s.lastname, cs.class_section_name')
->join('students s', 's.id = e.student_id')
->join('classSection cs', 'cs.class_section_id = e.class_section_id', 'left')
->where('e.parent_id', $parentId)
->where('e.is_withdrawn', 0)
->orderBy('e.updated_at', 'DESC')
->orderBy('e.created_at', 'DESC')
->get()
->getResultArray();
$students = [];
foreach ($rows as $row) {
$studentId = (int) ($row['student_id'] ?? 0);
if ($studentId === 0 || isset($students[$studentId])) {
continue;
}
$students[$studentId] = $row;
}
return array_values($students);
}
protected function groupReportsByWeek(array $rows): array
{
$reportGroups = [];
foreach ($rows as $row) {
$row['status_label'] = ClassProgressController::STATUS_OPTIONS[$row['status']] ?? 'Unknown';
$weekStart = $row['week_start'] ?? '';
$sectionId = (int) ($row['class_section_id'] ?? 0);
if ($weekStart === '' || $sectionId === 0) {
continue;
}
$key = $weekStart . ':' . $sectionId;
if (! isset($reportGroups[$key])) {
$reportGroups[$key] = [
'week_start' => $row['week_start'] ?? '',
'week_end' => $row['week_end'] ?? '',
'class_section_name' => $row['class_section_name'] ?? '',
'class_section_id' => $sectionId,
'reports' => [],
];
}
$reportGroups[$key]['reports'][$row['subject']] = $row;
}
return $reportGroups;
}
protected function isSectionAccessible(?int $classSectionId): bool
{
if (! $classSectionId) {
return false;
}
return in_array((int) $classSectionId, $this->getParentSectionIds(), true);
}
protected function resolveAttachmentFile(array $row): ?string
{
$path = trim((string) ($row['attachment_path'] ?? ''));
if ($path === '') {
return null;
}
return $this->resolveAttachmentPath($path);
}
protected function resolveAttachmentPath(string $path): ?string
{
$relative = preg_replace('#^writable/uploads/#', '', $path);
$absolute = WRITEPATH . 'uploads/' . ltrim($relative, '/');
return is_file($absolute) ? $absolute : null;
}
protected function loadAttachmentsForReports(array $reportIds): array
{
$reportIds = array_values(array_filter(array_map('intval', $reportIds)));
if (empty($reportIds)) {
return [];
}
$rows = $this->attachmentModel
->whereIn('report_id', $reportIds)
->orderBy('id', 'ASC')
->findAll();
$map = [];
foreach ($rows as $row) {
$reportId = (int) ($row['report_id'] ?? 0);
if ($reportId === 0) {
continue;
}
$map[$reportId][] = [
'id' => (int) $row['id'],
'name' => $row['original_name'] ?: basename((string) $row['file_path']),
];
}
return $map;
}
protected function decodeFlags(?string $json): array
{
if (! $json) {
return [];
}
$flags = json_decode($json, true);
return is_array($flags) ? $flags : [];
}
}