feat: ajout de la gestion des jobs avec création, récupération, suppression et filtrage via l'API, incluant des entités, des composants Vue.js et des mises à jour de la documentation API

This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2025-03-30 16:14:17 +02:00
parent 4d1d5b9f21
commit fd2d3cd640
21 changed files with 1538 additions and 184 deletions

View File

@@ -9,8 +9,11 @@ use App\Domain\Shared\Domain\Model\JobStatus;
readonly class ListJobsQuery implements QueryInterface
{
/**
* @param JobStatus[] $statuses
*/
public function __construct(
public ?JobStatus $status = null,
public ?array $statuses = null,
public ?string $type = null,
public ?\DateTimeImmutable $createdAfter = null,
public ?\DateTimeImmutable $createdBefore = null,

View File

@@ -28,7 +28,7 @@ readonly class ListJobsQueryHandler implements QueryHandlerInterface
}
$criteria = [
'status' => $query->status,
'statuses' => $query->statuses,
'type' => $query->type,
'createdAfter' => $query->createdAfter,
'createdBefore' => $query->createdBefore,

View File

@@ -18,6 +18,7 @@ interface JobRepositoryInterface
/**
* @param array{
* status?: ?JobStatus,
* statuses?: ?array<JobStatus>,
* type?: ?string,
* createdAfter?: ?\DateTimeImmutable,
* createdBefore?: ?\DateTimeImmutable,
@@ -33,6 +34,7 @@ interface JobRepositoryInterface
/**
* @param array{
* status?: ?JobStatus,
* statuses?: ?array<JobStatus>,
* type?: ?string,
* createdAfter?: ?\DateTimeImmutable,
* createdBefore?: ?\DateTimeImmutable

View File

@@ -25,13 +25,26 @@ use Symfony\Component\Validator\Constraints as Assert;
[
'name' => 'status',
'in' => 'query',
'description' => 'Filtrer par status',
'description' => 'Filtrer par status (séparés par des virgules pour plusieurs statuts, ex: "pending,in_progress" ou sous forme de tableau avec "status[]=")',
'required' => false,
'schema' => [
'type' => 'string',
'enum' => ['pending', 'in_progress', 'completed', 'failed'],
'example' => 'pending'
]
'oneOf' => [
[
'type' => 'string',
'example' => 'pending,in_progress'
],
[
'type' => 'array',
'items' => [
'type' => 'string',
'enum' => ['pending', 'in_progress', 'completed', 'failed', 'cancelled']
],
'example' => ['pending', 'in_progress']
]
]
],
'style' => 'form',
'explode' => false
],
[
'name' => 'type',
@@ -108,10 +121,7 @@ class GetJobListResource
#[Assert\NotBlank]
public readonly string $type,
#[ApiProperty(
description: 'Status du job',
openapiContext: ['enum' => ['pending', 'in_progress', 'completed', 'failed', 'cancelled']]
)]
#[ApiProperty(description: 'Status du job')]
#[Assert\NotBlank]
public readonly string $status,

View File

@@ -21,8 +21,34 @@ readonly class GetJobListStateProvider implements ProviderInterface
{
$filters = $context['filters'] ?? [];
$statuses = null;
if (isset($filters['status'])) {
if (is_array($filters['status'])) {
// Cas où status est passé en format tableau: status[]=pending&status[]=in_progress
$statusValues = $filters['status'];
} else {
// Cas où status est passé comme une chaîne séparée par des virgules: status=pending,in_progress
$statusValues = explode(',', $filters['status']);
}
$statuses = [];
foreach ($statusValues as $statusValue) {
try {
$statuses[] = JobStatus::from($statusValue);
} catch (\ValueError $e) {
// Ignorer les valeurs invalides
continue;
}
}
// Si aucun statut valide n'est trouvé, on met $statuses à null
if (empty($statuses)) {
$statuses = null;
}
}
$query = new ListJobsQuery(
status: isset($filters['status']) ? JobStatus::from($filters['status']) : null,
statuses: $statuses,
type: $filters['type'] ?? null,
createdAfter: isset($filters['createdAfter']) ? new \DateTimeImmutable($filters['createdAfter']) : null,
createdBefore: isset($filters['createdBefore']) ? new \DateTimeImmutable($filters['createdBefore']) : null,

View File

@@ -112,7 +112,15 @@ readonly class DoctrineJobRepository implements JobRepositoryInterface
->select('j')
->from(JobEntity::class, 'j');
if (isset($criteria['status'])) {
if (isset($criteria['statuses']) && is_array($criteria['statuses']) && !empty($criteria['statuses'])) {
$expr = $qb->expr()->orX();
foreach ($criteria['statuses'] as $key => $status) {
$paramName = 'status' . $key;
$expr->add($qb->expr()->eq('j.status', ':' . $paramName));
$qb->setParameter($paramName, $status->value);
}
$qb->andWhere($expr);
} elseif (isset($criteria['status'])) {
$qb->andWhere('j.status = :status')
->setParameter('status', $criteria['status']->value);
}
@@ -155,7 +163,15 @@ readonly class DoctrineJobRepository implements JobRepositoryInterface
->select('COUNT(j.id)')
->from(JobEntity::class, 'j');
if (isset($criteria['status'])) {
if (isset($criteria['statuses']) && is_array($criteria['statuses']) && !empty($criteria['statuses'])) {
$expr = $qb->expr()->orX();
foreach ($criteria['statuses'] as $key => $status) {
$paramName = 'status' . $key;
$expr->add($qb->expr()->eq('j.status', ':' . $paramName));
$qb->setParameter($paramName, $status->value);
}
$qb->andWhere($expr);
} elseif (isset($criteria['status'])) {
$qb->andWhere('j.status = :status')
->setParameter('status', $criteria['status']->value);
}