Files
alrahma_sunday_school_api/app/Models/Student.php
T
2026-04-23 00:04:35 -04:00

397 lines
13 KiB
PHP
Raw 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 Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\DB;
class Student extends BaseModel
{
use HasFactory;
protected $table = 'students';
/**
* CI: timestamps disabled
*/
public $timestamps = false;
protected $fillable = [
'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 $casts = [
'school_id' => 'string',
'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 doesnt 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'],
];
}
}