'date', 'dt_login' => 'datetime', 'dt_reg' => 'datetime', 'dt_mod' => 'datetime', 'dt_vact' => 'datetime', 'dt_dor' => 'datetime', 'dt_ret_dor' => 'datetime', 'dt_out' => 'datetime', 'dt_rcv_email' => 'datetime', 'dt_rcv_sms' => 'datetime', 'dt_rcv_push' => 'datetime', 'dt_stat_1' => 'datetime', 'dt_stat_2' => 'datetime', 'dt_stat_3' => 'datetime', 'dt_stat_4' => 'datetime', 'dt_stat_5' => 'datetime', // JSON 컬럼 (DB CHECK(json_valid()) 걸려있으니 array cast 쓰면 편함) 'admin_memo' => 'array', 'modify_log' => 'array', ]; /* * ========== Scopes ========== */ public function scopeActive(Builder $q): Builder { // CI에서 stat_3 == 3 접근금지 / 4 탈퇴신청 / 5 탈퇴완료 return $q->whereNotIn('stat_3', ['3','4','5']); } public function scopeByEmail(Builder $q, string $email): Builder { return $q->where('email', strtolower($email)); } /** * ⚠️ cell_phone이 "암호화 저장"이라면 * 이 scope는 "정규화 컬럼(cell_phone_hash / cell_phone_norm 등)" 생긴 뒤에 완성하는 게 맞음. * 지금은 자리만 만들어 둠. */ public function scopeByPhoneLookup(Builder $q, string $phoneNormalized): Builder { // TODO: cell_phone이 암호화라면 단순 where 비교 불가 // 예시(추천): cell_phone_hash 컬럼을 만들고 SHA256 같은 값으로 매칭 // return $q->where('cell_phone_hash', hash('sha256', $phoneNormalized . config('app.key'))); return $q; } /* * ========== Helpers ========== */ public function isBlocked(): bool { return $this->stat_3 === '3'; } public function isWithdrawnOrRequested(): bool { return in_array($this->stat_3, ['4','5'], true); } public function isFirstLogin(): bool { if (!$this->dt_login || !$this->dt_reg) return false; return Carbon::parse($this->dt_login)->equalTo(Carbon::parse($this->dt_reg)); } }