'integer', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; /* ============================================================ * Relationships (optional) * ============================================================ */ public function user(): BelongsTo { return $this->belongsTo(User::class, 'user_id'); } /* ============================================================ * Scopes (nice for queries) * ============================================================ */ public function scopeActive(Builder $q): Builder { return $q->where('active_role', '!=', 'inactive'); } public function scopeInactive(Builder $q): Builder { return $q->where('active_role', '=', 'inactive'); } public function scopeForSchoolYear(Builder $q, string $schoolYear): Builder { return $q->where('school_year', $schoolYear); } /* ============================================================ * CI-compatible methods * ============================================================ */ public static function getActiveStaff(): array { return static::query() ->active() ->orderByDesc('created_at') ->get() ->all(); } public static function getInactiveStaff(): array { return static::query() ->inactive() ->orderByDesc('updated_at') ->get() ->all(); } /** * Insert or update a staff row keyed by (user_id, school_year). * - If school_year missing: reuse latest existing school_year for that user if available. * - created_at is preserved on update (unless explicitly provided). * - updated_at can be provided by caller; otherwise we set it. * * Returns the saved model or null if invalid. */ public static function upsertStaff(array $data): ?self { if (empty($data['user_id'])) { return null; } $userId = (int) $data['user_id']; // Resolve school_year fallback like your CI logic $schoolYear = $data['school_year'] ?? null; if ($schoolYear === null) { $existingAny = static::query() ->where('user_id', $userId) ->orderByDesc('id') ->first(); if ($existingAny && $existingAny->school_year) { $schoolYear = (string) $existingAny->school_year; $data['school_year'] = $schoolYear; } } // Find existing by key $existing = null; if ($schoolYear !== null) { $existing = static::query() ->where('user_id', $userId) ->where('school_year', (string) $schoolYear) ->first(); } else { // If no school_year, treat (user_id) as key $existing = static::query() ->where('user_id', $userId) ->first(); } $now = now(); // use UTC if app.timezone=UTC (recommended) // Only allow fillable keys $payload = array_intersect_key($data, array_flip((new static)->getFillable())); if ($existing) { // Preserve original created_at unless explicitly provided if (!array_key_exists('created_at', $payload) && $existing->created_at) { $payload['created_at'] = $existing->created_at; } // Ensure updated_at exists if (!array_key_exists('updated_at', $payload)) { $payload['updated_at'] = $now; } $existing->fill($payload); $existing->save(); return $existing; } // Insert new row — set created_at/updated_at if not provided if (!array_key_exists('created_at', $payload)) { $payload['created_at'] = $now; } if (!array_key_exists('updated_at', $payload)) { $payload['updated_at'] = $now; } return static::query()->create($payload); } /** * CI-compatible boolean wrapper if you want the same signature. */ public static function upsertBool(array $data): bool { return (bool) static::upsertStaff($data); } /* ============================================================ * Optional validation helper (FormRequest/controller) * ============================================================ */ public static function rules(bool $updating = false): array { $req = $updating ? 'sometimes' : 'required'; return [ 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], 'firstname' => ['nullable', 'string', 'max:120'], 'lastname' => ['nullable', 'string', 'max:120'], 'email' => ['nullable', 'email', 'max:255'], 'phone' => ['nullable', 'string', 'max:40'], 'role_name' => ['nullable', 'string', 'max:80'], 'active_role' => ['nullable', 'string', 'max:80'], // includes 'inactive' 'status' => ['nullable', 'string', 'max:40'], 'school_year' => ['nullable', 'string', 'max:20'], 'created_at' => ['nullable', 'date'], 'updated_at' => ['nullable', 'date'], ]; } }