Files
oficial/app/src/Service/Job.php
2025-05-16 16:35:17 -04:00

149 lines
4.4 KiB
PHP

<?php
namespace Incoviba\Service;
use DateTimeImmutable;
use DateTimeZone;
use InvalidArgumentException;
use OutOfRangeException;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement\Exception\EmptyRedis;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Exception\ServiceAction\{Create, Read, Update};
use Incoviba\Repository;
use Incoviba\Model;
class Job extends Ideal\Service
{
public function __construct(LoggerInterface $logger, protected Redis $redisService,
protected Repository\Job $jobRepository)
{
parent::__construct($logger);
}
protected string $redisKey = 'jobs';
public function getPending(null|string|array $orderBy = null): array
{
try {
$jobs = $this->redisService->get($this->redisKey);
if ($jobs === null) {
return [];
}
$jobs = json_decode($jobs, true);
if ($orderBy !== null) {
uksort($jobs, function($a, $b) use ($orderBy) {
return $a[$orderBy] <=> $b[$orderBy];
});
}
return array_map([$this, 'load'], $jobs);
} catch (EmptyRedis) {
return [];
}
}
/**
* @param int $id
* @return Model\Job
* @throws Read
*/
public function getPendingById(int $id): Model\Job
{
$jobs = $this->getJobs();
try {
$idx = $this->findJob($jobs, $id);
} catch (EmptyResult $exception) {
$exception = new OutOfRangeException('Job not found', count($jobs), $exception);
throw new Read(__CLASS__, $exception);
}
return $this->load($jobs[$idx]);
}
/**
* @param array $configuration
* @return Model\Job
* @throws Read
*/
public function add(array $configuration): Model\Job
{
$now = (new DateTimeImmutable('now', new DateTimeZone($_ENV['TZ'] ?? 'America/Santiago')));
$data = [
'id' => $now->format('Uu'),
'configuration' => $configuration,
'executed' => false,
'created_at' => $now->format('Y-m-d H:i:s'),
'updated_at' => null
];
$jobs = [];
try {
$jobs = $this->redisService->get($this->redisKey);
if ($jobs !== null) {
$jobs = json_decode($jobs, true);
}
} catch (EmptyRedis) {}
$jobs []= $data;
$this->redisService->set($this->redisKey, json_encode($jobs), -1);
return $this->load($data);
}
/**
* @param Model\Job $job
* @return bool
* @throws Read
*/
public function execute(Model\Job $job): bool
{
$jobs = $this->getJobs();
try {
$idx = $this->findJob($jobs, $job->id);
} catch (EmptyResult $exception) {
$exception = new OutOfRangeException('Job not found', count($jobs), $exception);
throw new Read(__CLASS__, $exception);
}
unset($jobs[$idx]);
$this->redisService->set($this->redisKey, json_encode(array_values($jobs)), -1);
return true;
}
/**
* @return array
* @throws Read
*/
protected function getJobs(): array
{
try {
$jobs = $this->redisService->get($this->redisKey);
} catch (EmptyRedis $exception) {
throw new Read(__CLASS__, $exception);
}
if ($jobs === null) {
$exception = new InvalidArgumentException("Redis Key {$this->redisKey} not found");
throw new Read(__CLASS__, $exception);
}
return json_decode($jobs, true);
}
/**
* @param array $jobs
* @param int $id
* @return int
* @throws EmptyResult
*/
protected function findJob(array $jobs, int $id): int
{
$idx = array_find_key($jobs, function($job) use ($id) {
return (int) $job['id'] === $id;
});
if ($idx === null) {
throw new EmptyResult("SELECT * FROM jobs WHERE id = ?");
}
return $idx;
}
protected function load(array $data, ?int $id = null): Model\Job
{
$job = new Model\Job();
$job->id = $id ?? $data['id'] ?? null;
$job->configuration = $data['configuration'] ?? [];
$job->executed = $data['executed'] ?? false;
return $job;
}
}