feat: debut du domain Shared avec Contracts et Jobs + rules pour cursor

This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2025-03-24 14:56:18 +01:00
parent 19a697c712
commit ca9a74fe69
15 changed files with 748 additions and 110 deletions

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Domain\Shared\Contract;
namespace App\Domain\Shared\Domain\Contract;
interface CommandHandlerInterface
{

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Domain\Shared\Contract;
namespace App\Domain\Shared\Domain\Contract;
interface CommandInterface
{

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Domain\Shared\Domain\Contract;
use App\Domain\Shared\Domain\Model\FailedJob;
interface FailedJobRepositoryInterface
{
public function save(FailedJob $failedJob): void;
public function get(string $id): ?FailedJob;
public function delete(string $id): void;
public function findAll(): array;
public function findByJobType(string $jobType): array;
public function findByJobId(string $jobId): array;
public function findRetryableJobs(): array;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Domain\Shared\Domain\Contract;
use App\Domain\Shared\Domain\Model\Job;
use App\Domain\Shared\Domain\Model\JobStatus;
interface JobRepositoryInterface
{
public function save(Job $job): void;
public function get(string $id): ?Job;
public function findByStatus(JobStatus $status): array;
public function findByType(string $type): array;
public function findPendingJobs(): array;
public function findInProgressJobs(): array;
public function findFailedJobs(): array;
}

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Domain\Shared\Contract;
namespace App\Domain\Shared\Domain\Contract;
interface QueryHandlerInterface
{

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Domain\Shared\Contract;
namespace App\Domain\Shared\Domain\Contract;
interface QueryInterface
{

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Domain\Shared\Contract;
namespace App\Domain\Shared\Domain\Contract;
interface ResponseInterface
{

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Domain\Shared\Domain\Exception;
class JobNotFoundException extends \DomainException
{
public static function withId(string $id): self
{
return new self(sprintf('Job with id "%s" not found', $id));
}
public static function withJobId(string $jobId): self
{
return new self(sprintf('Failed job with job id "%s" not found', $jobId));
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Domain\Shared\Domain\Exception;
class JobNotRetryableException extends \DomainException
{
public static function maxAttemptsReached(string $jobId, int $maxAttempts): self
{
return new self(sprintf('Job "%s" has reached its maximum number of attempts (%d)', $jobId, $maxAttempts));
}
public static function notFailed(string $jobId): self
{
return new self(sprintf('Cannot retry job "%s" because it is not in failed status', $jobId));
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Domain\Shared\Domain\Model;
class FailedJob
{
public function __construct(
public readonly string $id,
public readonly string $jobId,
public readonly string $jobType,
public readonly string $failureReason,
public readonly array $context,
public readonly \DateTimeImmutable $failedAt,
public readonly int $attempt
) {}
public static function fromJob(Job $job): self
{
return new self(
id: uniqid('failed_', true),
jobId: $job->id,
jobType: $job->type,
failureReason: $job->failureReason ?? 'Unknown error',
context: $job->context,
failedAt: new \DateTimeImmutable(),
attempt: $job->attempts
);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Domain\Shared\Domain\Model;
abstract class Job
{
public JobStatus $status;
public \DateTimeImmutable $createdAt;
public ?\DateTimeImmutable $startedAt = null;
public ?\DateTimeImmutable $completedAt = null;
public ?string $failureReason = null;
public int $attempts = 0;
public int $maxAttempts = 3;
public array $context = [];
public function __construct(
public readonly string $id,
public readonly string $type
) {
$this->status = JobStatus::PENDING;
$this->createdAt = new \DateTimeImmutable();
}
public function start(): void
{
$this->status = JobStatus::IN_PROGRESS;
$this->startedAt = new \DateTimeImmutable();
$this->attempts++;
}
public function complete(): void
{
$this->status = JobStatus::COMPLETED;
$this->completedAt = new \DateTimeImmutable();
}
public function fail(string $reason): void
{
$this->failureReason = $reason;
$this->status = $this->attempts >= $this->maxAttempts
? JobStatus::FAILED
: JobStatus::PENDING;
$this->completedAt = new \DateTimeImmutable();
}
public function cancel(): void
{
$this->status = JobStatus::CANCELLED;
$this->completedAt = new \DateTimeImmutable();
}
public function canBeRetried(): bool
{
return $this->status === JobStatus::FAILED && $this->attempts < $this->maxAttempts;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Domain\Shared\Domain\Model;
enum JobStatus: string
{
case PENDING = 'pending';
case IN_PROGRESS = 'in_progress';
case COMPLETED = 'completed';
case FAILED = 'failed';
case CANCELLED = 'cancelled';
}