select(['p.seq', 'p.state', 'p.info', 'p.rgdate']); // 기간 if (!empty($filters['date_from'])) { $q->where('p.rgdate', '>=', $filters['date_from'] . ' 00:00:00'); } if (!empty($filters['date_to'])) { $q->where('p.rgdate', '<=', $filters['date_to'] . ' 23:59:59'); } // state if (!empty($filters['state'])) { $q->where('p.state', $filters['state']); } // mem_no (JSON) if (($filters['mem_no'] ?? null) !== null) { $q->whereRaw( "JSON_UNQUOTE(JSON_EXTRACT(p.info, '$.mem_no')) = ?", [(string)((int)$filters['mem_no'])] ); } // type (신포맷) $type = trim((string)($filters['type'] ?? '')); if ($type !== '') { $q->whereRaw( "JSON_UNQUOTE(JSON_EXTRACT(p.info, '$.type')) = ?", [$type] ); } // email (구포맷) $email = trim((string)($filters['email'] ?? '')); if ($email !== '') { $like = '%' . $this->escapeLike($email) . '%'; $q->where(function ($qq) use ($like) { $qq->whereRaw("JSON_UNQUOTE(JSON_EXTRACT(p.info, '$.user_email')) LIKE ?", [$like]) ->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(p.info, '$.email')) LIKE ?", [$like]); }); } // ip: 신포맷 remote_addr prefix OR 구포맷 auth_key/info contains $ip = trim((string)($filters['ip'] ?? '')); if ($ip !== '') { $like = $this->escapeLike($ip) . '%'; $like2 = '%' . $this->escapeLike($ip) . '%'; $q->where(function ($qq) use ($like, $like2) { $qq->whereRaw("JSON_UNQUOTE(JSON_EXTRACT(p.info, '$.remote_addr')) LIKE ?", [$like]) ->orWhere('p.info', 'like', $like2); }); } // q: info 전체 검색(필요할 때만) $kw = trim((string)($filters['q'] ?? '')); if ($kw !== '') { $q->where('p.info', 'like', '%' . $this->escapeLike($kw) . '%'); } $q->orderByDesc('p.rgdate')->orderByDesc('p.seq'); return $q->paginate($perPage)->withQueryString(); } private function escapeLike(string $s): string { return str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], $s); } }