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

525 lines
18 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Models;
use CodeIgniter\Model;
class StudentModel extends Model
{
protected $table = 'students';
protected $primaryKey = 'id'; // Primary key of the students table
protected $allowedFields = [
'school_id',
'firstname',
'lastname',
'dob',
'age',
'gender',
'registration_grade',
'photo_consent',
'is_new',
'parent_id',
'school_year',
'registration_date',
'tuition_paid',
'year_of_registration',
'rfid_tag',
'is_active'
];
protected $useTimestamps = false;
// File: app/Models/StudentModel.php
/**
* Get all students marked as new (is_new = 1).
*
* @return array
*/
public function getNewStudents(): array
{
return $this->where('is_new', 1)
->orderBy('lastname', 'ASC')
->orderBy('firstname', 'ASC')
->findAll();
}
public function getNewStudentsWithParents(): array
{
return $this->select([
'students.*',
'u.id AS parent_id',
'u.firstname AS parent_firstname',
'u.lastname AS parent_lastname',
'u.email AS parent_email',
'u.cellphone AS parent_phone',
])
->join('users u', 'u.id = students.parent_id', 'left')
->where('students.is_new', 1)
->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC')
->findAll();
}
/**
* Fetch only new students (is_new=1) with parent info and a single emergency contact.
* - Parent fields: parent_firstname, parent_lastname, parent_email, parent_phone
* - Emergency fields: emergency_name, emergency_relationship, emergency_phone
*/
public function getNewStudentsWithParentsAndEmergency(): array
{
return $this->select([
'students.*',
'u.firstname AS parent_firstname',
'u.lastname AS parent_lastname',
'u.email AS parent_email',
'u.cellphone AS parent_phone',
// Pick one emergency contact (MIN() works fine if you group by student)
'MIN(ec.emergency_contact_name) AS emergency_name',
'MIN(ec.relation) AS emergency_relationship',
'MIN(ec.cellphone) AS emergency_phone',
])
->join('users u', 'u.id = students.parent_id', 'left')
->join('emergency_contacts ec', 'ec.parent_id = students.parent_id', 'left')
->where('students.is_new', 1) // strictly 1; change to 'Yes' if your data uses Yes/No
->groupBy('students.id')
->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC')
->findAll();
}
/**
* Fetch students with parent + one emergency contact.
* @param null|int $isNew Pass 1 for only new, 0 for only not-new, null for both.
*/
/**
* Fetch students with parent + one emergency contact.
*
* @param null|int $isNew 1 = only new, 0 = only not-new, null = both
* @param null|string $schoolYear e.g. "2025-2026"; pass null or "all" for no filter
* @return array
*/
public function getStudentsWithParentsAndEmergency(?string $schoolYear = null, ?int $isNew = null): array
{
$builder = $this->select([
'students.*',
'u.firstname AS parent_firstname',
'u.lastname AS parent_lastname',
'u.email AS parent_email',
'u.cellphone AS parent_phone',
'MIN(ec.emergency_contact_name) AS emergency_name',
'MIN(ec.relation) AS emergency_relationship',
'MIN(ec.cellphone) AS emergency_phone',
])
->join('users u', 'u.id = students.parent_id', 'left')
->join('emergency_contacts ec', 'ec.parent_id = students.parent_id', 'left');
// is_new filter
if ($isNew === 0 || $isNew === 1) {
$builder->where('students.is_new', $isNew);
} else {
$builder->whereIn('students.is_new', [0, 1]); // both
}
// school_year filter (skip if null or "all")
if ($schoolYear !== null && strtolower($schoolYear) !== 'all') {
$builder->where('students.school_year', $schoolYear);
}
return $builder
->groupBy('students.id')
->orderBy('students.is_new', 'DESC') // new first
->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC')
->findAll();
}
public function getStudentSchoolIdByStudentId(int $studentId): ?string
{
$result = $this->select('school_id')
->where('id', $studentId)
->first();
return $result['school_id'] ?? null;
}
/**
* Get all students with assignments, current semester, and school year.
*/
public function getStudentsWithAssignments()
{
// Retrieve school year and semester from the configuration table
$configTable = $this->db->table('configuration');
$schoolYear = $configTable->select('config_value')
->where('config_key', 'school_year')
->get()
->getRowArray()['config_value'];
$semester = $configTable->select('config_value')
->where('config_key', 'semester')
->get()
->getRowArray()['config_value'];
return $this->db->table('students')
->select('
students.id,
students.firstname,
students.lastname,
students.age,
users.email,
users.cellphone as phone,
students.registration_grade,
classSection.class_section_name as current_class,
"' . $schoolYear . '" as school_year,
"' . $semester . '" as semester
')
->join('users', 'users.id = students.parent_id', 'left')
->join('student_class', 'student_class.student_id = students.id', 'left')
->join('class_section', 'student_class.class_section_id = classSection.id', 'left')
->get()
->getResultArray();
}
/**
* Get students assigned to a specific teacher.
*
* @param int $teacherId
* @return array
*/
public function getStudentsByTeacher($teacherId)
{
return $this->db->table('students')
->select('
students.firstname,
students.lastname,
students.age,
classSection.class_section_name,
student_class.school_year
')
->join('student_class', 'students.id = student_class.student_id', 'left')
->join('teacher_class', 'student_class.class_section_id = teacher_class.class_section_id', 'left')
->join('class_section', 'student_class.class_section_id = classSection.id', 'left')
->where('teacher_class.teacher_id', $teacherId)
->get()
->getResultArray();
}
/**
* Get all students in a specific class section.
*
* @param int $classSectionId
* @return array
*/
public function getStudentsByClass($classSectionId)
{
return $this->db->table('students')
->join('student_class', 'students.id = student_class.student_id', 'left')
->where('student_class.class_section_id', $classSectionId)
->select('students.*, student_class.class_section_id')
->get()
->getResultArray();
}
/**
* Get all students.
*
* @return array
*/
public function getAllStudents()
{
return $this->findAll();
}
/**
* Get the total number of students.
*
* @return int
*/
public function getTotalStudents()
{
return $this->countAllResults();
}
public function getFullNameById($studentId)
{
// Fetch student record by ID
$student = $this->find($studentId);
// Return null if student not found
if (empty($student)) {
return null;
}
// Extract first and last name (support common variations)
$firstName = $student['firstname'] ?? $student['first_name'] ?? $student['first'] ?? '';
$lastName = $student['lastname'] ?? $student['last_name'] ?? $student['last'] ?? '';
// Return null if both names are empty
if ($firstName === '' && $lastName === '') {
return null;
}
// Return names separately
return [
'firstname' => $firstName,
'lastname' => $lastName,
];
}
/**
* Get the full name of a student.
*
* @param array $student
* @return string
*/
public function getFullName($student)
{
return ($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '');
}
// In the StudentModel
public function getLastRegistrationDate($ParentId)
{
return $this->select('registration_date')
->where('parent_id', $ParentId)
->orderBy('registration_date', 'DESC') // Order by most recent registration date
->limit(1) // Get only the most recent registration
->first(); // Return the first record
}
public function getByClassAndYear($class_section_id, $school_year, ?string $semester = null): array
{
$studentClassModel = new \App\Models\StudentClassModel();
$builder = $studentClassModel
->select('student_id')
->where('class_section_id', $class_section_id)
->where('school_year', $school_year);
$studentIds = $builder->findAll();
$studentIds = array_column($studentIds, 'student_id');
if (empty($studentIds)) {
return [];
}
return $this->whereIn('id', $studentIds)
->where('is_active', 1)
->orderBy('firstname', 'ASC')
->orderBy('lastname', 'ASC')
->findAll();
}
public function getSchoolIdByStudentId($studentId)
{
return $this->select('school_id')
->where('id', $studentId)
->first()['school_id'] ?? null;
}
public function getSchoolIdsByParentId($parentId)
{
$results = $this->select('school_id')
->where('parent_id', $parentId)
->distinct()
->findAll();
return array_column($results, 'school_id');
}
public function getStudentIdsByParentId($parentId)
{
$results = $this->select('id')
->where('parent_id', $parentId)
->distinct()
->findAll();
return array_column($results, 'id');
}
public function getStudentsWithClassAndEnrollment()
{
return $this->select('
students.*,
student_class.class_section_id,
enrollments.enrollment_status,
enrollments.admission_status,
u.firstname AS parent_firstname,
u.lastname AS parent_lastname
')
->join('student_class', 'student_class.student_id = students.id', 'left')
->join('enrollments', 'enrollments.student_id = students.id', 'left')
->join('users u', 'u.id = students.parent_id', 'left')
// keep your original grouping as-is so behavior doesn't change
->groupBy('students.id, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status')
->findAll();
}
/*
public function getStudentsWithClassAndEnrollment()
{
return $this->select('students.*, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status')
->join('student_class', 'student_class.student_id = students.id', 'left')
->join('enrollments', 'enrollments.student_id = students.id', 'left')
->groupBy('students.id, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status')
->findAll();
}
*/
/**
* Get student and teacher information based on class_section_id.
*
* @param int $classSectionId
* @param string|null $semester Deprecated/ignored (assignments now tracked per school year only).
* @param string|null $schoolYear
* @return array
*/
public function getStudentInfoByClassSectionId($classSectionId, ?string $semester = null, ?string $schoolYear = null): array
{
$classSectionId = (int) $classSectionId;
if ($classSectionId <= 0) {
return [];
}
// Start from this model's table (likely 'students')
$builder = $this->builder();
$builder
->select('students.id AS student_id, students.school_id, students.firstname, students.lastname, sc.class_section_id')
->join('student_class sc', 'sc.student_id = students.id', 'inner')
->where('sc.class_section_id', $classSectionId)
->where('students.is_active', 1);
// Optional term scoping (safe no-ops if null)
if ($schoolYear !== null) {
$builder->where('sc.school_year', $schoolYear);
}
// Prevent accidental dupes if student_class has multiple rows
$builder->distinct();
$builder->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC');
$results = $builder->get()->getResultArray();
// 🔹 Instead of saving, just add `updated_by` to each result row
$userId = (int) (session()->get('user_id') ?? 0);
if (!empty($results)) {
foreach ($results as &$row) {
$row['updated_by'] = $userId; // add actor id for use downstream
}
unset($row); // good practice to break ref
}
return $results ?: [];
}
// In your existing StudentModel
public function getStudentBasic(int $studentId): ?array
{
return $this->select('id, firstname, lastname, grade')->find($studentId);
}
/**
* Returns students with:
* - class/enrollment/admission info
* - primary parent (guardian) info as aliases the view expects:
* parent_firstname, parent_lastname, parent_phone, parent_email
* - emergency contact info as: emergency_name, emergency_relationship, emergency_phone
*
* Adjust table/column names to your schema where noted.
*/
/*
public function getStudentsWithClassAndEnrollment(): array
{
$db = $this->db;
// ---- Notes: adjust these names if your schema differs ----
// users table fields:
// users.first_name, users.last_name, users.email, users.phone
// students table may already have emergency_* columns; if not, enable the alt join below.
// class/enrollment sources: adjust joins to your real tables/fields.
// ----------------------------------------------------------
$builder = $db->table('students s');
// Base student fields used by the view/controller
$builder->select([
's.id',
's.firstname',
's.lastname',
's.is_new',
's.dob',
's.registration_date',
's.photo_consent',
// If your students table stores class_section_id directly; otherwise replace with a subquery/join
's.class_section_id',
// Optional emergency columns ON students table (comment out if you use separate table)
's.emergency_name',
's.emergency_relationship',
's.emergency_phone',
]);
// ---------- Enrollment / Admission status ----------
// Replace these with your real sources:
// Example 1: statuses live on students (already selected) then alias directly:
// $builder->select('s.enrollment_status, s.admission_status');
// Example 2: join enrollment/admission tables:
// $builder->join('enrollments e', 'e.student_id = s.id AND e.is_current = 1', 'left');
// $builder->select('e.status AS enrollment_status');
// $builder->join('admissions a', 'a.student_id = s.id', 'left');
// $builder->select('a.status AS admission_status');
// If you actually store on students, uncomment this line and remove the example joins above:
$builder->select('s.enrollment_status, s.admission_status');
// ---------- Class Section readable name ----------
// If you already have a helper to resolve the name, the controller uses it.
// But its faster to produce a label here:
// Example: class_sections (id, name), classes (name) etc. Adjust join/concat as needed.
$builder->join('class_sections cs', 'cs.id = s.class_section_id', 'left');
$builder->select("COALESCE(cs.name, 'Class not Assigned') AS class_section");
// ---------- Family/Guardian (primary parent) ----------
// Link student -> family via family_students
$builder->join('family_students fs', 'fs.student_id = s.id', 'left');
// Join to primary guardian for that family
$builder->join('family_guardians fg', 'fg.family_id = fs.family_id AND fg.is_primary = 1', 'left');
// Join to users for the guardian details (ADJUST field names!)
$builder->join('users pu', 'pu.id = fg.user_id', 'left');
// Produce the aliases your view expects
$builder->select([
'pu.first_name AS parent_firstname',
'pu.last_name AS parent_lastname',
'pu.email AS parent_email',
'pu.phone AS parent_phone',
]);
// ---------- OPTIONAL: If emergency contact lives in a separate table ----------
// Comment OUT the s.emergency_* selections above and use this instead:
// $builder->join('student_emergency_contacts sec', 'sec.student_id = s.id AND sec.is_primary = 1', 'left');
// $builder->select([
// 'sec.name AS emergency_name',
// 'sec.relationship AS emergency_relationship',
// 'sec.phone AS emergency_phone',
// ]);
// If you need only currently active / current semester, apply where here:
// $builder->where('s.is_active', 1);
// Avoid duplicate rows (e.g., if multiple guardians slipped in)
$builder->groupBy('s.id');
// Optional: order
$builder->orderBy('s.lastname', 'ASC')->orderBy('s.firstname', 'ASC');
return $builder->get()->getResultArray();
}
*/
}