Files
alrahma_sunday_school/app/Controllers/View/FlagController.php
T
2026-02-10 22:11:06 -05:00

569 lines
21 KiB
PHP

<?php
namespace App\Controllers\View;
use App\Models\CurrentFlagModel;
use App\Models\FlagModel;
use App\Models\StudentModel;
use App\Models\ClassSectionModel;
use App\Models\StudentClassModel;
use App\Models\ConfigurationModel;
use CodeIgniter\Controller;
class FlagController extends Controller
{
protected $userModel;
protected $db;
public function __construct()
{
$this->db = \Config\Database::connect();
//$this->userModel = new UserModel();
helper(['url', 'form']);
}
public function index()
{
$currentFlagModel = new CurrentFlagModel();
$classSectionModel = new ClassSectionModel();
$studentClassModel = new StudentClassModel();
$configModel = new ConfigurationModel();
// Format grades with id and name for passing to the view
$grades = [];
// Retrieve flags and class sections that currently have active students
$flags = $currentFlagModel->findAll();
$schoolYear = $configModel->getConfig('school_year');
$studentCounts = $studentClassModel->getStudentCountsBySection($schoolYear);
$classSections = [];
if (!empty($studentCounts)) {
$classSectionIdsWithStudents = array_keys($studentCounts);
$classSections = $classSectionModel
->orderBy('class_section_name', 'ASC')
->whereIn('class_section_id', $classSectionIdsWithStudents)
->findAll();
}
foreach ($classSections as $section) {
$grades[] = [
'id' => $section['class_section_id'],
'name' => $section['class_section_name']
];
}
// Map updater user IDs to display names for the view
$updaterIds = [];
foreach ($flags as $flag) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
if (!empty($flag[$key])) {
$updaterIds[(int)$flag[$key]] = true;
}
}
}
$updaterMap = [];
if (!empty($updaterIds)) {
$rows = $this->db->table('users')
->select('id, firstname, lastname')
->whereIn('id', array_keys($updaterIds))
->get()
->getResultArray();
foreach ($rows as $row) {
$name = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
$updaterMap[(int)$row['id']] = $name !== '' ? $name : ('User #' . $row['id']);
}
}
foreach ($flags as &$flag) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
$id = (int)($flag[$key] ?? 0);
$flag[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null;
}
}
unset($flag);
// Pass flags and formatted grades to the view
return view('flags/flags_management', [
'flags' => $flags,
'grades' => $grades // Now grades include both id and class_section_name
]);
}
public function history()
{
$flagModel = new FlagModel();
$schoolYear = (string)($this->request->getGet('school_year') ?? '');
$semester = (string)($this->request->getGet('semester') ?? '');
$builder = $flagModel->orderBy('flag_datetime', 'DESC');
if ($schoolYear !== '') {
$builder->where('school_year', $schoolYear);
}
if ($semester !== '') {
$builder->where('semester', $semester);
}
return $this->response->setJSON([
'flags' => $builder->findAll(),
]);
}
public function processedFlags()
{
$flagModel = new FlagModel();
$classSectionModel = new ClassSectionModel();
$schoolYear = (string)($this->request->getGet('school_year') ?? '');
$semester = (string)($this->request->getGet('semester') ?? '');
$builder = $flagModel->orderBy('flag_datetime', 'DESC');
if ($schoolYear !== '') {
$builder->where('school_year', $schoolYear);
}
if ($semester !== '') {
$builder->where('semester', $semester);
}
$flags = $builder->findAll();
$gradeIds = [];
foreach ($flags as $flag) {
$gradeValue = $flag['grade'] ?? '';
if (is_numeric($gradeValue)) {
$gradeIds[(int)$gradeValue] = true;
}
}
$gradeMap = [];
if (!empty($gradeIds)) {
$rows = $classSectionModel
->select('class_section_id, class_section_name')
->whereIn('class_section_id', array_keys($gradeIds))
->findAll();
foreach ($rows as $row) {
$gradeMap[(int)$row['class_section_id']] = (string)($row['class_section_name'] ?? '');
}
}
// Map updater user IDs to display names for the view
$updaterIds = [];
foreach ($flags as $flag) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
if (!empty($flag[$key])) {
$updaterIds[(int)$flag[$key]] = true;
}
}
}
$updaterMap = [];
if (!empty($updaterIds)) {
$rows = $this->db->table('users')
->select('id, firstname, lastname')
->whereIn('id', array_keys($updaterIds))
->get()
->getResultArray();
foreach ($rows as $row) {
$name = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
$updaterMap[(int)$row['id']] = $name !== '' ? $name : ('User #' . $row['id']);
}
}
foreach ($flags as &$flag) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
$id = (int)($flag[$key] ?? 0);
$flag[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null;
}
$gradeValue = $flag['grade'] ?? '';
if (is_numeric($gradeValue)) {
$flag['grade'] = $gradeMap[(int)$gradeValue] ?? (string)$gradeValue;
}
}
unset($flag);
return view('flags/processed_flags', [
'flags' => $flags
]);
}
public function incidentAnalysis()
{
$flagModel = new FlagModel();
$classSectionModel = new ClassSectionModel();
$schoolYear = (string)($this->request->getGet('school_year') ?? '');
$semester = (string)($this->request->getGet('semester') ?? '');
$builder = $flagModel->orderBy('flag_datetime', 'DESC');
if ($schoolYear !== '') {
$builder->where('school_year', $schoolYear);
}
if ($semester !== '') {
$builder->where('semester', $semester);
}
$flags = $builder->findAll();
$gradeIds = [];
foreach ($flags as $flag) {
$gradeValue = $flag['grade'] ?? '';
if (is_numeric($gradeValue)) {
$gradeIds[(int)$gradeValue] = true;
}
}
$gradeMap = [];
if (!empty($gradeIds)) {
$rows = $classSectionModel
->select('class_section_id, class_section_name')
->whereIn('class_section_id', array_keys($gradeIds))
->findAll();
foreach ($rows as $row) {
$gradeMap[(int)$row['class_section_id']] = (string)($row['class_section_name'] ?? '');
}
}
$students = [];
foreach ($flags as $flag) {
$studentId = (string)($flag['student_id'] ?? '');
$studentName = (string)($flag['student_name'] ?? '');
$studentKey = $studentId !== '' ? 'id:' . $studentId : 'name:' . strtolower(trim($studentName));
$gradeValue = $flag['grade'] ?? '';
$gradeLabel = $gradeValue;
if (is_numeric($gradeValue)) {
$gradeLabel = $gradeMap[(int)$gradeValue] ?? (string)$gradeValue;
}
if (!isset($students[$studentKey])) {
$students[$studentKey] = [
'student_id' => $studentId,
'student_name' => $studentName,
'grade' => (string)$gradeLabel,
'total' => 0,
'open' => 0,
'closed' => 0,
'canceled' => 0,
'last_incident' => null,
'logs' => [],
];
}
$students[$studentKey]['total'] += 1;
$state = (string)($flag['flag_state'] ?? '');
if ($state === 'Open') {
$students[$studentKey]['open'] += 1;
} elseif ($state === 'Closed') {
$students[$studentKey]['closed'] += 1;
} elseif ($state === 'Canceled') {
$students[$studentKey]['canceled'] += 1;
}
if ($students[$studentKey]['last_incident'] === null) {
$students[$studentKey]['last_incident'] = $flag['flag_datetime'] ?? null;
}
$students[$studentKey]['logs'][] = [
'flag' => $flag['flag'] ?? '',
'flag_state' => $state,
'flag_datetime' => $flag['flag_datetime'] ?? null,
'open_description' => $flag['open_description'] ?? null,
'close_description' => $flag['close_description'] ?? null,
'cancel_description' => $flag['cancel_description'] ?? null,
'action_taken' => $flag['action_taken'] ?? null,
];
}
$studentRows = array_values($students);
usort($studentRows, function ($a, $b) {
if ($a['total'] === $b['total']) {
return strcasecmp($a['student_name'], $b['student_name']);
}
return $b['total'] <=> $a['total'];
});
return view('flags/incident_analysis', [
'students' => $studentRows,
'schoolYear' => $schoolYear,
'semester' => $semester,
]);
}
public function getStudentsByGrade($gradeId)
{
$studentClassModel = new StudentClassModel(); // Model for the student_class table
$studentModel = new StudentModel(); // Model for the students table
// Fetch student IDs for the selected grade
$studentIds = $studentClassModel
->active()
->where('student_class.class_section_id', $gradeId)
->findColumn('student_id');
// If no student IDs are found, return an empty JSON array
if (empty($studentIds)) {
return $this->response->setJSON([]);
}
// Fetch student details from students table using the retrieved IDs
$students = $studentModel
->whereIn('id', $studentIds)
->where('is_active', 1)
->findAll();
// Prepare data for JSON response with both ID and full name
$studentData = [];
foreach ($students as $student) {
$studentData[] = [
'id' => $student['id'], // Student ID
'name' => $student['firstname'] . ' ' . $student['lastname'] // Full name
];
}
// Return JSON response with student ID and full name
return $this->response->setJSON($studentData);
}
public function addFlag()
{
$currentFlagModel = new CurrentFlagModel();
$studentModel = new StudentModel();
$configModel = new ConfigurationModel();
// Get the data from the form submission
$studentId = $this->request->getPost('student');
$flagType = $this->request->getPost('flag');
$description = $this->request->getPost('description');
$flagState = $this->request->getPost('flag_state');
$stateDescription = $this->request->getPost('state_description'); // Additional description for "Closed" or "Canceled"
// Retrieve student information from the database
$student = $studentModel->find($studentId);
if (!$student) {
session()->setFlashdata('error', 'Student not found.');
return $this->index();
}
// Get the user_id from the session for updated_by
$userId = session()->get('user_id');
// Get the semester and school year from configuration
$semester = $configModel->getConfig('semester');
$schoolYear = $configModel->getConfig('school_year');
// Set the current system date and time for flag_datetime
$currentDateTime = utc_now();
// Check if a flag of the same type already exists for this student
$existingFlag = $currentFlagModel->where('student_id', $studentId)
->where('flag', $flagType)
->first();
if ($existingFlag) {
// If the flag exists, update it based on the new state and description
$data = [
'flag_datetime' => $currentDateTime,
'updated_by_open' => $userId
];
// Append the new description to the appropriate field based on flag state
if ($flagState === 'Closed') {
$data['flag_state'] = 'Closed';
$data['close_description'] = ($existingFlag['close_description'] ?? '') . PHP_EOL . $stateDescription;
} elseif ($flagState === 'Canceled') {
$data['flag_state'] = 'Canceled';
$data['cancel_description'] = ($existingFlag['cancel_description'] ?? '') . PHP_EOL . $stateDescription;
} else {
$data['open_description'] = $existingFlag['open_description'] . PHP_EOL . $description;
}
// Update the existing flag
$currentFlagModel->update($existingFlag['id'], $data);
session()->setFlashdata('success', 'Flag updated successfully!');
} else {
// If no existing flag is found, prepare the data for insertion
$data = [
'student_id' => $student['id'],
'student_name' => $student['firstname'] . ' ' . $student['lastname'],
'grade' => $this->request->getPost('grade'),
'flag' => $flagType,
'flag_datetime' => $currentDateTime,
'flag_state' => 'Open', // Set initial state to 'Open'
'updated_by_open' => $userId,
'open_description' => $description,
'semester' => $semester,
'school_year' => $schoolYear
];
// Insert the new flag
if ($currentFlagModel->insert($data)) {
session()->setFlashdata('success', 'New incident added successfully!');
} else {
session()->setFlashdata('error', 'Failed to add new incident.');
}
}
// Redirect to the list view
return $this->index();
}
public function updateState($id)
{
log_message('debug', 'updateState method called for ID: ' . $id);
log_message('debug', 'Flag state: ' . $this->request->getPost('flag_state'));
$currentFlagModel = new CurrentFlagModel();
// Get the new flag state from the form
$newState = $this->request->getPost('flag_state');
if (!$newState) {
session()->setFlashdata('error', 'incident state not provided.');
return $this->index();
}
// Update the flag state in the database
if ($currentFlagModel->update($id, ['flag_state' => $newState])) {
session()->setFlashdata('success', 'Incident state updated successfully!');
} else {
$errors = $currentFlagModel->errors();
log_message('error', 'Failed to update incident state: ' . print_r($errors, true));
session()->setFlashdata('error', 'Failed to update incident state.');
}
// Redirect back to the flags list
return $this->index();
}
public function closeFlag($flagId)
{
// Log the whole session array
log_message('debug', json_encode(session()->get()));
$currentFlagModel = new CurrentFlagModel();
$userId = session()->get('user_id');
// Get the current flag data
$flagData = $currentFlagModel->find($flagId);
// Log and check if flag data is found
if (!$flagData) {
log_message('error', "incident with ID {$flagId} not found in database.");
session()->setFlashdata('error', 'Incident not found.');
return redirect()->back();
}
// Proceed only if flag is not closed
if ($flagData['flag_state'] !== 'Closed') {
// Retrieve 'close_description' from POST request
$closeDescription = $this->request->getPost('state_description');
$actionTaken = $this->request->getPost('action_taken');
// Debugging: Check if the close description is received
if (empty($closeDescription)) {
session()->setFlashdata('error', 'Close description is missing.');
return redirect()->back();
}
// Update the flag state to Closed
$currentFlagModel->update($flagId, [
'flag_state' => 'Closed',
'updated_by_closed' => $userId,
'close_description' => $closeDescription, // Use dynamic description from form
'action_taken' => $actionTaken
]);
$flagData = $currentFlagModel->find($flagId);
return $this->moveToHistory($flagData);
} else {
session()->setFlashdata('error', 'Incident is already closed.');
}
return $this->index();
}
public function cancelFlag($flagId)
{
$currentFlagModel = new CurrentFlagModel();
$userId = session()->get('user_id');
// Retrieve 'cancel_description' from POST request
$cancelDescription = $this->request->getPost('state_description');
$actionTaken = $this->request->getPost('action_taken');
// Get the current flag data
$flagData = $currentFlagModel->find($flagId);
// Check if flag data is found
if (!$flagData) {
log_message('error', "Incident with ID {$flagId} not found in database.");
session()->setFlashdata('error', 'Incident not found.');
return redirect()->back();
}
// Check if the flag is not already canceled
if ($flagData['flag_state'] !== 'Canceled') {
// Update the flag state to Canceled
$currentFlagModel->update($flagId, [
'flag_state' => 'Canceled',
'updated_by_canceled' => $userId,
'cancel_description' => $cancelDescription,
'action_taken' => $actionTaken
]);
// Retrieve updated flag data to ensure latest state
$flagData = $currentFlagModel->find($flagId);
return $this->moveToHistory($flagData);
} else {
session()->setFlashdata('error', 'Incident is already canceled.');
}
return $this->index();
}
private function moveToHistory($flagData)
{
$flagModel = new FlagModel();
// Prepare data for the flag table
$dataToInsert = [
'student_id' => $flagData['student_id'],
'student_name' => $flagData['student_name'],
'grade' => $flagData['grade'],
'flag' => $flagData['flag'],
'flag_datetime' => $flagData['flag_datetime'],
'flag_state' => $flagData['flag_state'],
'updated_by_open' => $flagData['updated_by_open'],
'open_description' => $flagData['open_description'],
'updated_by_closed' => $flagData['updated_by_closed'],
'close_description' => $flagData['close_description'],
'action_taken' => $flagData['action_taken'],
'updated_by_canceled' => $flagData['updated_by_canceled'],
'cancel_description' => $flagData['cancel_description'],
'semester' => $flagData['semester'],
'school_year' => $flagData['school_year'],
'created_at' => $flagData['created_at'],
'updated_at' => $flagData['updated_at']
];
// Insert data into the flag table
if ($flagModel->insert($dataToInsert)) {
// Delete the entry from the current_flag table
$currentFlagModel = new CurrentFlagModel();
$currentFlagModel->delete($flagData['id']);
session()->setFlashdata('success', 'Incident has been moved to history.');
} else {
session()->setFlashdata('error', 'Failed to move incident to history.');
}
return $this->index();
}
}