210 lines
6.3 KiB
PHP
210 lines
6.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Automation;
|
|
|
|
use PDO;
|
|
|
|
final class AutomationExecutionLogRepository
|
|
{
|
|
public function __construct(private readonly PDO $pdo)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $data
|
|
*/
|
|
public function create(array $data): void
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO automation_execution_logs (
|
|
event_type,
|
|
rule_id,
|
|
rule_name,
|
|
order_id,
|
|
execution_status,
|
|
result_message,
|
|
context_json,
|
|
executed_at,
|
|
created_at
|
|
) VALUES (
|
|
:event_type,
|
|
:rule_id,
|
|
:rule_name,
|
|
:order_id,
|
|
:execution_status,
|
|
:result_message,
|
|
:context_json,
|
|
:executed_at,
|
|
NOW()
|
|
)'
|
|
);
|
|
|
|
$statement->execute([
|
|
'event_type' => (string) ($data['event_type'] ?? ''),
|
|
'rule_id' => isset($data['rule_id']) ? (int) $data['rule_id'] : null,
|
|
'rule_name' => (string) ($data['rule_name'] ?? ''),
|
|
'order_id' => (int) ($data['order_id'] ?? 0),
|
|
'execution_status' => (string) ($data['execution_status'] ?? ''),
|
|
'result_message' => $this->trimNullable((string) ($data['result_message'] ?? '')),
|
|
'context_json' => $this->encodeJson($data['context'] ?? null),
|
|
'executed_at' => (string) ($data['executed_at'] ?? date('Y-m-d H:i:s')),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $filters
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function paginate(array $filters, int $page, int $perPage): array
|
|
{
|
|
$safePage = max(1, $page);
|
|
$safePerPage = max(1, min(100, $perPage));
|
|
$offset = ($safePage - 1) * $safePerPage;
|
|
|
|
['where' => $whereSql, 'params' => $params] = $this->buildFilters($filters);
|
|
|
|
$sql = 'SELECT id, event_type, rule_id, rule_name, order_id, execution_status, result_message, context_json, executed_at
|
|
FROM automation_execution_logs
|
|
' . $whereSql . '
|
|
ORDER BY executed_at DESC, id DESC
|
|
LIMIT :limit OFFSET :offset';
|
|
|
|
$statement = $this->pdo->prepare($sql);
|
|
foreach ($params as $key => $value) {
|
|
$statement->bindValue(':' . $key, $value);
|
|
}
|
|
$statement->bindValue(':limit', $safePerPage, PDO::PARAM_INT);
|
|
$statement->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$statement->execute();
|
|
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($rows as &$row) {
|
|
$decoded = json_decode((string) ($row['context_json'] ?? ''), true);
|
|
$row['context_json'] = is_array($decoded) ? $decoded : null;
|
|
}
|
|
unset($row);
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $filters
|
|
*/
|
|
public function count(array $filters): int
|
|
{
|
|
['where' => $whereSql, 'params' => $params] = $this->buildFilters($filters);
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT COUNT(*) FROM automation_execution_logs ' . $whereSql
|
|
);
|
|
$statement->execute($params);
|
|
$value = $statement->fetchColumn();
|
|
|
|
return max(0, (int) $value);
|
|
}
|
|
|
|
public function purgeOlderThanDays(int $days): int
|
|
{
|
|
$safeDays = max(1, min(3650, $days));
|
|
$statement = $this->pdo->prepare(
|
|
'DELETE FROM automation_execution_logs WHERE executed_at < DATE_SUB(NOW(), INTERVAL :days DAY)'
|
|
);
|
|
$statement->bindValue(':days', $safeDays, PDO::PARAM_INT);
|
|
$statement->execute();
|
|
|
|
return $statement->rowCount();
|
|
}
|
|
|
|
/**
|
|
* @return list<string>
|
|
*/
|
|
public function listEventTypes(): array
|
|
{
|
|
$statement = $this->pdo->query(
|
|
'SELECT DISTINCT event_type FROM automation_execution_logs ORDER BY event_type ASC'
|
|
);
|
|
$rows = $statement->fetchAll(PDO::FETCH_COLUMN);
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
return array_values(array_filter(array_map('strval', $rows), static fn (string $value): bool => $value !== ''));
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $filters
|
|
* @return array{where:string,params:array<string,mixed>}
|
|
*/
|
|
private function buildFilters(array $filters): array
|
|
{
|
|
$where = [];
|
|
$params = [];
|
|
|
|
$eventType = trim((string) ($filters['event_type'] ?? ''));
|
|
if ($eventType !== '') {
|
|
$where[] = 'event_type = :event_type';
|
|
$params['event_type'] = $eventType;
|
|
}
|
|
|
|
$executionStatus = trim((string) ($filters['execution_status'] ?? ''));
|
|
if ($executionStatus !== '') {
|
|
$where[] = 'execution_status = :execution_status';
|
|
$params['execution_status'] = $executionStatus;
|
|
}
|
|
|
|
$ruleId = (int) ($filters['rule_id'] ?? 0);
|
|
if ($ruleId > 0) {
|
|
$where[] = 'rule_id = :rule_id';
|
|
$params['rule_id'] = $ruleId;
|
|
}
|
|
|
|
$orderId = (int) ($filters['order_id'] ?? 0);
|
|
if ($orderId > 0) {
|
|
$where[] = 'order_id = :order_id';
|
|
$params['order_id'] = $orderId;
|
|
}
|
|
|
|
$dateFrom = trim((string) ($filters['date_from'] ?? ''));
|
|
if ($dateFrom !== '') {
|
|
$where[] = 'DATE(executed_at) >= :date_from';
|
|
$params['date_from'] = $dateFrom;
|
|
}
|
|
|
|
$dateTo = trim((string) ($filters['date_to'] ?? ''));
|
|
if ($dateTo !== '') {
|
|
$where[] = 'DATE(executed_at) <= :date_to';
|
|
$params['date_to'] = $dateTo;
|
|
}
|
|
|
|
if ($where === []) {
|
|
return ['where' => '', 'params' => []];
|
|
}
|
|
|
|
return ['where' => 'WHERE ' . implode(' AND ', $where), 'params' => $params];
|
|
}
|
|
|
|
private function trimNullable(string $value): ?string
|
|
{
|
|
$trimmed = trim($value);
|
|
if ($trimmed === '') {
|
|
return null;
|
|
}
|
|
|
|
return mb_substr($trimmed, 0, 500);
|
|
}
|
|
|
|
private function encodeJson(mixed $data): ?string
|
|
{
|
|
if (!is_array($data) || $data === []) {
|
|
return null;
|
|
}
|
|
|
|
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: null;
|
|
}
|
|
}
|