clqms-be/app/Services/AuditLogService.php

180 lines
5.4 KiB
PHP
Raw Normal View History

<?php
namespace App\Services;
use CodeIgniter\Database\BaseConnection;
use DateTime;
use DateTimeZone;
use InvalidArgumentException;
use Throwable;
class AuditLogService
{
private const TABLE_MAP = [
'logpatient' => 'logpatient',
'patient' => 'logpatient',
'visit' => 'logpatient',
'logorder' => 'logorder',
'order' => 'logorder',
'specimen' => 'logorder',
'result' => 'logorder',
'logmaster' => 'logmaster',
'master' => 'logmaster',
'config' => 'logmaster',
'valueset' => 'logmaster',
'logsystem' => 'logsystem',
'system' => 'logsystem',
'auth' => 'logsystem',
'job' => 'logsystem',
];
private const PRIMARY_KEYS = [
'logpatient' => 'LogPatientID',
'logorder' => 'LogOrderID',
'logmaster' => 'LogMasterID',
'logsystem' => 'LogSystemID',
];
private const DEFAULT_PAGE = 1;
private const DEFAULT_PER_PAGE = 20;
private const MAX_PER_PAGE = 100;
private static ?BaseConnection $db = null;
public function fetchLogs(array $filters): array
{
$tableKey = $filters['table'] ?? null;
if (empty($tableKey)) {
throw new InvalidArgumentException('table parameter is required');
}
$logTable = $this->resolveLogTable($tableKey);
if ($logTable === null) {
throw new InvalidArgumentException("Unknown audit table: {$tableKey}");
}
$builder = $this->getDb()->table($logTable);
$this->applyFilters($builder, $filters);
$total = (int) $builder->countAllResults(false);
$page = $this->normalizePage($filters['page'] ?? null);
$perPage = $this->normalizePerPage($filters['perPage'] ?? $filters['per_page'] ?? null);
$offset = ($page - 1) * $perPage;
$builder->orderBy('LogDate', 'DESC');
$builder->orderBy($this->getPrimaryKey($logTable), 'DESC');
$rows = $builder
->limit($perPage, $offset)
->get()
->getResultArray();
return [
'data' => $rows,
'pagination' => [
'page' => $page,
'perPage' => $perPage,
'total' => $total,
],
];
}
private function applyFilters($builder, array $filters): void
{
if (!empty($filters['rec_id'])) {
$builder->where('RecID', (string) $filters['rec_id']);
}
if (!empty($filters['event_id'])) {
$builder->where('EventID', $this->normalizeCode($filters['event_id']));
}
if (!empty($filters['activity_id'])) {
$builder->where('ActivityID', $this->normalizeCode($filters['activity_id']));
}
$this->applyDateRange($builder, $filters['from'] ?? null, $filters['to'] ?? null);
if (!empty($filters['search'])) {
$search = trim($filters['search']);
if ($search !== '') {
$builder->groupStart();
$builder->like('UserID', $search);
$builder->orLike('Reason', $search);
$builder->orLike('FldName', $search);
$builder->orLike('FldValuePrev', $search);
$builder->orLike('FldValueNew', $search);
$builder->orLike('EventID', $search);
$builder->orLike('ActivityID', $search);
$builder->groupEnd();
}
}
}
private function applyDateRange($builder, ?string $from, ?string $to): void
{
if ($from !== null && trim($from) !== '') {
$builder->where('LogDate >=', $this->normalizeDate($from));
}
if ($to !== null && trim($to) !== '') {
$builder->where('LogDate <=', $this->normalizeDate($to));
}
}
private function normalizeDate(string $value): string
{
try {
$dt = new DateTime($value, new DateTimeZone('UTC'));
} catch (Throwable $e) {
throw new InvalidArgumentException('Invalid date: ' . $value);
}
return $dt->format('Y-m-d H:i:s');
}
private function normalizeCode(string $value): string
{
return strtoupper(trim($value));
}
private function normalizePage($value): int
{
$page = (int) ($value ?? self::DEFAULT_PAGE);
return $page < 1 ? self::DEFAULT_PAGE : $page;
}
private function normalizePerPage($value): int
{
$perPage = (int) ($value ?? self::DEFAULT_PER_PAGE);
if ($perPage < 1) {
return self::DEFAULT_PER_PAGE;
}
if ($perPage > self::MAX_PER_PAGE) {
throw new InvalidArgumentException('perPage cannot be greater than ' . self::MAX_PER_PAGE);
}
return $perPage;
}
private function resolveLogTable(?string $key): ?string
{
if ($key === null) {
return null;
}
$lookup = strtolower(trim($key));
return self::TABLE_MAP[$lookup] ?? null;
}
private function getPrimaryKey(string $table): string
{
return self::PRIMARY_KEYS[$table] ?? 'LogID';
}
private function getDb(): BaseConnection
{
return self::$db ??= \Config\Database::connect();
}
}