giftcon_dev/app/Services/Admin/Log/MemberLoginLogService.php

130 lines
4.2 KiB
PHP

<?php
namespace App\Services\Admin\Log;
use App\Repositories\Admin\Log\MemberLoginLogRepository;
use Illuminate\Support\Facades\Schema;
final class MemberLoginLogService
{
public function __construct(
private readonly MemberLoginLogRepository $repo,
) {}
public function indexData(array $query = []): array
{
$currentYear = (int)date('Y');
$years = $this->availableYears(2018, $currentYear);
$year = (int)($query['year'] ?? $currentYear);
if (!in_array($year, $years, true)) {
// 테이블 없거나 허용 범위 밖이면 최신년도 fallback
$year = !empty($years) ? max($years) : $currentYear;
}
$filters = [
'year' => $year,
'date_from' => $this->safeDate($query['date_from'] ?? ''),
'date_to' => $this->safeDate($query['date_to'] ?? ''),
'mem_no' => $this->safeInt($query['mem_no'] ?? null),
'sf' => $this->safeEnum($query['sf'] ?? '', ['s','f']), // 성공/실패
'conn' => $this->safeEnum($query['conn'] ?? '', ['1','2']), // pc/mobile
'ip4' => $this->safeIpPrefix($query['ip4'] ?? ''),
'ip4_c' => $this->safeIpPrefix($query['ip4_c'] ?? ''),
'error_code'=> $this->safeStr($query['error_code'] ?? '', 10),
'platform' => $this->safeStr($query['platform'] ?? '', 30),
'browser' => $this->safeStr($query['browser'] ?? '', 40),
];
// 기간 역전 방지
if ($filters['date_from'] && $filters['date_to']) {
if (strcmp($filters['date_from'], $filters['date_to']) > 0) {
[$filters['date_from'], $filters['date_to']] = [$filters['date_to'], $filters['date_from']];
}
}
$page = $this->repo->paginateByYear($year, $filters, 30);
// 화면 가공(라벨/링크 등)
$items = [];
foreach ($page->items() as $it) {
$r = is_array($it) ? $it : (array)$it;
$sf = (string)($r['sf'] ?? 's');
$conn = (string)($r['conn'] ?? '1');
$items[] = array_merge($r, [
'sf_label' => $sf === 'f' ? '실패' : '성공',
'sf_badge' => $sf === 'f' ? 'badge--bad' : 'badge--ok',
'conn_label' => $conn === '2' ? 'M' : 'PC',
'conn_badge' => $conn === '2' ? 'badge--mvno' : 'badge--muted',
'mem_no_int' => (int)($r['mem_no'] ?? 0),
'mem_link' => ((int)($r['mem_no'] ?? 0) > 0) ? ('/members/' . (int)$r['mem_no']) : null,
// 실패가 아니면 에러코드 화면에서 비워도 됨(뷰에서 처리)
]);
}
return [
'years' => $years,
'filters' => $filters,
'page' => $page,
'items' => $items,
];
}
private function availableYears(int $from, int $to): array
{
$out = [];
for ($y = $from; $y <= $to; $y++) {
$t = 'mem_login_' . $y;
if (Schema::hasTable($t)) $out[] = $y;
}
// 없으면 그냥 범위라도 반환(운영/개발에서 초기 셋업 대비)
return !empty($out) ? $out : [$to];
}
private function safeStr(mixed $v, int $max): string
{
$s = trim((string)$v);
if ($s === '') return '';
if (mb_strlen($s) > $max) $s = mb_substr($s, 0, $max);
return $s;
}
private function safeEnum(mixed $v, array $allowed): string
{
$s = trim((string)$v);
return in_array($s, $allowed, true) ? $s : '';
}
private function safeInt(mixed $v): ?int
{
if ($v === null || $v === '') return null;
if (!is_numeric($v)) return null;
$n = (int)$v;
return $n >= 0 ? $n : null;
}
private function safeDate(mixed $v): ?string
{
$s = trim((string)$v);
if ($s === '') return null;
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $s) ? $s : null;
}
private function safeIpPrefix(mixed $v): string
{
$s = trim((string)$v);
if ($s === '') return '';
return preg_match('/^[0-9.]+$/', $s) ? $s : '';
}
}