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 it’s 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(); } */ }