'integer', 'age' => 'integer', 'photo_consent' => 'boolean', 'is_new' => 'boolean', 'parent_id' => 'integer', 'tuition_paid' => 'boolean', 'is_active' => 'boolean', 'dob' => 'date', 'registration_date' => 'date', 'year_of_registration' => 'integer', ]; /* ============================================================ * Relationships (optional but useful) * ============================================================ */ public function parent(): BelongsTo { // Change User model if your parent lives elsewhere return $this->belongsTo(User::class, 'parent_id'); } public function classAssignments(): HasMany { return $this->hasMany(StudentClass::class, 'student_id'); } public function allergies(): HasMany { return $this->hasMany(StudentAllergy::class, 'student_id'); } public function medicalConditions(): HasMany { return $this->hasMany(StudentMedicalCondition::class, 'student_id'); } /* ============================================================ * Scopes * ============================================================ */ public function scopeActive(Builder $q): Builder { return $q->where('is_active', 1); } public function scopeNew(Builder $q): Builder { return $q->where('is_new', 1); } public function scopeForSchoolYear(Builder $q, ?string $schoolYear): Builder { if ($schoolYear === null || strtolower(trim($schoolYear)) === 'all' || trim($schoolYear) === '') { return $q; } return $q->where('school_year', $schoolYear); } public function scopeOrderByName(Builder $q): Builder { return $q->orderBy('lastname', 'asc')->orderBy('firstname', 'asc'); } /* ============================================================ * CI-compatible methods (converted) * ============================================================ */ /** CI: getNewStudents() */ public static function getNewStudents(): array { return static::query() ->new() ->orderByName() ->get() ->all(); } /** CI: getNewStudentsWithParents() */ public static function getNewStudentsWithParents(): array { return DB::table('students') ->selectRaw(' 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 ') ->leftJoin('users as u', 'u.id', '=', 'students.parent_id') ->where('students.is_new', 1) ->orderBy('students.lastname', 'asc') ->orderBy('students.firstname', 'asc') ->get() ->map(fn ($r) => (array) $r) ->all(); } /** * CI: getNewStudentsWithParentsAndEmergency() * Picks one emergency contact via MIN(...) with groupBy student. */ public static function getNewStudentsWithParentsAndEmergency(): array { return DB::table('students') ->selectRaw(' 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 ') ->leftJoin('users as u', 'u.id', '=', 'students.parent_id') ->leftJoin('emergency_contacts as ec', 'ec.parent_id', '=', 'students.parent_id') ->where('students.is_new', 1) ->groupBy('students.id') ->orderBy('students.lastname', 'asc') ->orderBy('students.firstname', 'asc') ->get() ->map(fn ($r) => (array) $r) ->all(); } /** * CI: getStudentsWithParentsAndEmergency(?schoolYear, ?isNew) */ public static function getStudentsWithParentsAndEmergency(?string $schoolYear = null, ?int $isNew = null): array { $q = DB::table('students') ->selectRaw(' 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 ') ->leftJoin('users as u', 'u.id', '=', 'students.parent_id') ->leftJoin('emergency_contacts as ec', 'ec.parent_id', '=', 'students.parent_id'); // is_new filter if ($isNew === 0 || $isNew === 1) { $q->where('students.is_new', $isNew); } else { $q->whereIn('students.is_new', [0, 1]); } // school_year filter (skip if null or "all") if ($schoolYear !== null && strtolower($schoolYear) !== 'all') { $q->where('students.school_year', $schoolYear); } return $q->groupBy('students.id') ->orderByDesc('students.is_new') // new first ->orderBy('students.lastname', 'asc') ->orderBy('students.firstname', 'asc') ->get() ->map(fn ($r) => (array) $r) ->all(); } /** CI: getStudentSchoolIdByStudentId() */ public static function getStudentSchoolIdByStudentId(int $studentId): ?string { $v = static::query()->where('id', $studentId)->value('school_id'); return $v !== null ? (string) $v : null; } /** CI: getAllStudents() */ public static function getAllStudents() { return static::query()->get(); } /** CI: getTotalStudents() */ public static function getTotalStudents(): int { return (int) static::query()->count(); } /** CI: getFullNameById() => returns [firstname, lastname] or null */ public static function getFullNameById($studentId): ?array { $student = static::query()->find($studentId); if (!$student) return null; $first = (string) ($student->firstname ?? ''); $last = (string) ($student->lastname ?? ''); if ($first === '' && $last === '') return null; return ['firstname' => $first, 'lastname' => $last]; } /** CI: getFullName($student array) */ public static function getFullName(array $student): string { return trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')); } /** CI: getLastRegistrationDate($ParentId) */ public static function getLastRegistrationDate(int $parentId): ?array { $row = static::query() ->select('registration_date') ->where('parent_id', $parentId) ->orderByDesc('registration_date') ->first(); return $row ? ['registration_date' => $row->registration_date] : null; } /** * CI: getByClassAndYear($class_section_id, $school_year, ?semester ignored) */ public static function getByClassAndYear(int $classSectionId, string $schoolYear, ?string $semester = null): array { $studentIds = StudentClass::query() ->select('student_id') ->where('class_section_id', $classSectionId) ->where('school_year', $schoolYear) ->pluck('student_id') ->all(); if (empty($studentIds)) return []; return static::query() ->whereIn('id', $studentIds) ->where('is_active', 1) ->orderBy('firstname', 'asc') ->orderBy('lastname', 'asc') ->get() ->all(); } public static function getSchoolIdByStudentId($studentId) { return static::query()->where('id', $studentId)->value('school_id'); } public static function getSchoolIdsByParentId(int $parentId): array { return static::query() ->where('parent_id', $parentId) ->distinct() ->pluck('school_id') ->filter(fn ($v) => $v !== null && $v !== '') ->values() ->all(); } public static function getStudentIdsByParentId(int $parentId): array { return static::query() ->where('parent_id', $parentId) ->distinct() ->pluck('id') ->map(fn ($v) => (int) $v) ->values() ->all(); } /** * CI: getStudentsWithClassAndEnrollment() * Keeps your original grouping so behavior doesn’t change. */ public static function getStudentsWithClassAndEnrollment(): array { return DB::table('students') ->selectRaw(' students.*, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status, u.firstname AS parent_firstname, u.lastname AS parent_lastname ') ->leftJoin('student_class', 'student_class.student_id', '=', 'students.id') ->leftJoin('enrollments', 'enrollments.student_id', '=', 'students.id') ->leftJoin('users as u', 'u.id', '=', 'students.parent_id') ->groupByRaw('students.id, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status, u.firstname, u.lastname') ->get() ->map(fn ($r) => (array) $r) ->all(); } /** * CI: getStudentInfoByClassSectionId($classSectionId, $semester ignored, $schoolYear optional) * NOTE: In CI you appended updated_by from session; here we accept actor id. */ public static function getStudentInfoByClassSectionId(int $classSectionId, ?string $semester = null, ?string $schoolYear = null, ?int $actorId = null): array { if ($classSectionId <= 0) return []; $q = DB::table('students') ->selectRaw('students.id AS student_id, students.school_id, students.firstname, students.lastname, sc.class_section_id') ->join('student_class as sc', 'sc.student_id', '=', 'students.id') ->where('sc.class_section_id', $classSectionId) ->where('students.is_active', 1) ->distinct() ->orderBy('students.lastname', 'asc') ->orderBy('students.firstname', 'asc'); if ($schoolYear !== null) { $q->where('sc.school_year', $schoolYear); } $rows = $q->get()->map(fn ($r) => (array) $r)->all(); $actorId = $actorId ?? (auth()->id() ?? 0); foreach ($rows as &$row) { $row['updated_by'] = (int) $actorId; } unset($row); return $rows; } /* ============================================================ * Optional validation helper * ============================================================ */ public static function rules(bool $updating = false): array { $req = $updating ? 'sometimes' : 'required'; return [ 'school_id' => ['nullable', 'integer', 'min:1'], 'firstname' => [$req, 'string', 'max:120'], 'lastname' => [$req, 'string', 'max:120'], 'dob' => ['nullable', 'date'], 'age' => ['nullable', 'integer', 'min:0'], 'gender' => ['nullable', 'string', 'max:20'], 'registration_grade' => ['nullable', 'string', 'max:50'], 'photo_consent' => ['nullable', 'boolean'], 'is_new' => ['nullable', 'boolean'], 'parent_id' => ['nullable', 'integer'], 'school_year' => ['nullable', 'string', 'max:20'], 'registration_date' => ['nullable', 'date'], 'tuition_paid' => ['nullable', 'boolean'], 'year_of_registration'=> ['nullable', 'integer', 'min:0'], 'rfid_tag' => ['nullable', 'string', 'max:120'], 'is_active' => ['nullable', 'boolean'], ]; } }