refactor: rename lib/ to core/ for clearer core-module separation
Rename the top-level lib/ directory to core/ so the project root immediately communicates which code is core platform and which lives in modules/. PHP namespaces (MintyPHP\*) are unchanged — only the Composer PSR-4 path mapping moves from lib/ to core/. Module-internal lib/ directories (modules/*/lib/) are untouched. Updated across the full stack: - composer.json PSR-4 mapping - bootstrap entry points (web/index.php, bin/*, tests/bootstrap.php) - tooling configs (phpstan.neon, phpunit.xml, php-cs-fixer) - 26 architecture contract tests - enforcement-policy, guard-catalog, quality-gates - all documentation (CLAUDE.md, README, 25 docs/, .agents/skills/) - bin/qa-extended.sh search paths - .claude/settings.local.json permission paths Workflow: .agents/runs/CORE-LIB-RENAME-001/ (Analyst → Planner → Executor → Code Review (4 findings fixed) → Security Review → Acceptance Test → Finalizer) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
140
core/Repository/Scheduler/ScheduledJobRunRepository.php
Normal file
140
core/Repository/Scheduler/ScheduledJobRunRepository.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Repository\Scheduler;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobTriggerType;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
/** Records individual job run results with duration, output, and retention-based purging. */
|
||||
class ScheduledJobRunRepository implements ScheduledJobRunRepositoryInterface
|
||||
{
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into scheduled_job_runs (
|
||||
run_uuid, job_id, job_key, trigger_type, status, actor_user_id,
|
||||
started_at, finished_at, duration_ms, error_code, error_message, result_json
|
||||
) values (?,?,?,?,?,?,?,?,?,?,?,?)',
|
||||
(string) ($data['run_uuid'] ?? ''),
|
||||
(string) ((int) ($data['job_id'] ?? 0)),
|
||||
(string) ($data['job_key'] ?? ''),
|
||||
(string) ($data['trigger_type'] ?? ScheduledJobTriggerType::Scheduler->value),
|
||||
(string) ($data['status'] ?? ScheduledJobRunStatus::Failed->value),
|
||||
($data['actor_user_id'] ?? null) !== null ? (string) ((int) $data['actor_user_id']) : null,
|
||||
(string) ($data['started_at'] ?? ''),
|
||||
$data['finished_at'] ?? null,
|
||||
($data['duration_ms'] ?? null) !== null ? (string) ((int) $data['duration_ms']) : null,
|
||||
$data['error_code'] ?? null,
|
||||
$data['error_message'] ?? null,
|
||||
$data['result_json'] ?? null
|
||||
);
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public function listPagedByJobId(int $jobId, array $filters): array
|
||||
{
|
||||
if ($jobId <= 0) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
}
|
||||
|
||||
$search = trim((string) ($filters['search'] ?? ''));
|
||||
$status = strtolower(trim((string) ($filters['status'] ?? '')));
|
||||
$triggerType = strtolower(trim((string) ($filters['trigger_type'] ?? '')));
|
||||
|
||||
[$limit, $offset] = RepoQuery::sanitizeLimitOffset($filters, 20, 1, 200, 0);
|
||||
[$order, $dir] = RepoQuery::sanitizeOrder(
|
||||
$filters,
|
||||
['id', 'started_at', 'finished_at', 'duration_ms', 'status', 'trigger_type'],
|
||||
'started_at',
|
||||
'desc'
|
||||
);
|
||||
|
||||
$where = ['scheduled_job_runs.job_id = ?'];
|
||||
$params = [(string) $jobId];
|
||||
RepoQuery::addLikeFilter(
|
||||
$where,
|
||||
$params,
|
||||
['scheduled_job_runs.run_uuid', 'scheduled_job_runs.error_code', 'scheduled_job_runs.error_message'],
|
||||
$search
|
||||
);
|
||||
if (ScheduledJobRunStatus::tryNormalize($status) !== null) {
|
||||
$where[] = 'scheduled_job_runs.status = ?';
|
||||
$params[] = $status;
|
||||
}
|
||||
if (ScheduledJobTriggerType::tryNormalize($triggerType) !== null) {
|
||||
$where[] = 'scheduled_job_runs.trigger_type = ?';
|
||||
$params[] = $triggerType;
|
||||
}
|
||||
|
||||
$whereSql = ' where ' . implode(' and ', $where);
|
||||
$fromSql = ' from scheduled_job_runs left join users on users.id = scheduled_job_runs.actor_user_id ';
|
||||
|
||||
$total = (int) (DB::selectValue('select count(*)' . $fromSql . $whereSql, ...$params) ?? 0);
|
||||
$rows = DB::select(
|
||||
'select
|
||||
scheduled_job_runs.id,
|
||||
scheduled_job_runs.run_uuid,
|
||||
scheduled_job_runs.job_id,
|
||||
scheduled_job_runs.job_key,
|
||||
scheduled_job_runs.trigger_type,
|
||||
scheduled_job_runs.status,
|
||||
scheduled_job_runs.actor_user_id,
|
||||
scheduled_job_runs.started_at,
|
||||
scheduled_job_runs.finished_at,
|
||||
scheduled_job_runs.duration_ms,
|
||||
scheduled_job_runs.error_code,
|
||||
scheduled_job_runs.error_message,
|
||||
scheduled_job_runs.result_json,
|
||||
scheduled_job_runs.created_at,
|
||||
users.id,
|
||||
users.uuid,
|
||||
users.display_name,
|
||||
users.email
|
||||
' . $fromSql . $whereSql .
|
||||
sprintf(' order by scheduled_job_runs.`%s` %s limit ? offset ?', $order, $dir),
|
||||
...array_merge($params, [(string) $limit, (string) $offset])
|
||||
);
|
||||
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['total' => $total, 'rows' => $normalized];
|
||||
}
|
||||
|
||||
public function purgeOlderThanDays(int $days): int
|
||||
{
|
||||
if ($days <= 0) {
|
||||
return 0;
|
||||
}
|
||||
$cutoff = (new \DateTimeImmutable('now', new \DateTimeZone('UTC')))
|
||||
->modify('-' . $days . ' days')
|
||||
->format('Y-m-d H:i:s');
|
||||
$deleted = DB::delete('delete from scheduled_job_runs where created_at < ?', $cutoff);
|
||||
return is_int($deleted) ? $deleted : 0;
|
||||
}
|
||||
|
||||
private function normalizeRow(mixed $row): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
}
|
||||
$item = $row['scheduled_job_runs'] ?? [];
|
||||
if (!is_array($item) || !isset($item['id'])) {
|
||||
return null;
|
||||
}
|
||||
$user = is_array($row['users'] ?? null) ? $row['users'] : [];
|
||||
$item['actor_user_uuid'] = (string) ($user['uuid'] ?? '');
|
||||
$item['actor_user_display_name'] = (string) ($user['display_name'] ?? '');
|
||||
$item['actor_user_email'] = (string) ($user['email'] ?? '');
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user