597 lines
22 KiB
PHP
597 lines
22 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();
|
|
$userId = session()->get('user_id');
|
|
|
|
// Get the new flag state from the form
|
|
$newState = $this->request->getPost('flag_state');
|
|
$stateDescription = (string) ($this->request->getPost('state_description') ?? '');
|
|
$actionTaken = (string) ($this->request->getPost('action_taken') ?? '');
|
|
|
|
if (!$newState) {
|
|
session()->setFlashdata('error', 'incident state not provided.');
|
|
return $this->index();
|
|
}
|
|
|
|
$update = ['flag_state' => $newState];
|
|
if ($newState === 'Closed') {
|
|
$update['updated_by_closed'] = $userId;
|
|
if ($stateDescription !== '') {
|
|
$update['close_description'] = $stateDescription;
|
|
}
|
|
if ($actionTaken !== '') {
|
|
$update['action_taken'] = $actionTaken;
|
|
}
|
|
} elseif ($newState === 'Canceled') {
|
|
$update['updated_by_canceled'] = $userId;
|
|
if ($stateDescription !== '') {
|
|
$update['cancel_description'] = $stateDescription;
|
|
}
|
|
if ($actionTaken !== '') {
|
|
$update['action_taken'] = $actionTaken;
|
|
}
|
|
}
|
|
|
|
// Update the flag state in the database
|
|
if ($currentFlagModel->update($id, $update)) {
|
|
if ($newState === 'Closed' || $newState === 'Canceled') {
|
|
$flagData = $currentFlagModel->find($id);
|
|
if ($flagData) {
|
|
return $this->moveToHistory($flagData);
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
}
|