Re-synced controllers, configs, libraries, seeds, and docs with the latest API expectations and response helpers.
180 lines
5.2 KiB
PHP
Executable File
180 lines
5.2 KiB
PHP
Executable File
<?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();
|
|
}
|
|
}
|