1. Go to this page and download the library: Download andydefer/laravel-task library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
andydefer / laravel-task example snippets
// config/task.php
return [
// Chemin de stockage des tâches
'storage_path' => env('TASK_STORAGE_PATH', storage_path('tasks')),
// Période de grâce
'grace_period' => [
'enabled' => env('TASK_GRACE_PERIOD_ENABLED', true),
'seconds' => env('TASK_GRACE_PERIOD_SECONDS', 86400), // 24 heures
],
// Traitement par lots
'batch' => [
'limit' => env('TASK_BATCH_LIMIT', 1000), // null ou 0 = illimité
'order' => env('TASK_BATCH_ORDER', 'oldest'), // 'oldest' ou 'newest'
],
];
// app/Tasks/ClearUnconfirmedOrdersTask.php
declare(strict_types=1);
namespace App\Tasks;
use AndyDefer\Task\AbstractTask;
use AndyDefer\Task\Records\TaskConfigRecord;
use AndyDefer\Task\ValueObjects\CounterVO;
use AndyDefer\Task\ValueObjects\TaskSignatureVO;
use App\Models\Order;
final class ClearUnconfirmedOrdersTask extends AbstractTask
{
public function getConfig(): TaskConfigRecord
{
return new TaskConfigRecord(
signature: new TaskSignatureVO('clear-unconfirmed-orders'),
description: 'Clear orders not confirmed after N minutes',
delay_seconds: new CounterVO(300), // Toutes les 5 minutes
max_attempts: new CounterVO(3),
start_at: null, // Maintenant
end_at: null, // Jamais (récurrente)
);
}
protected function process(): void
{
// Récupérer les paramètres du payload
$data = $this->context->getPayload()->data;
$minutes = $data->minutes ?? 30;
$force = $data->force ?? false;
// Logique métier
$query = Order::where('status', 'pending')
->where('created_at', '<', now()->subMinutes($minutes));
if ($force) {
$deleted = $query->forceDelete();
} else {
$deleted = $query->delete();
}
$this->info("Deleted {$deleted} unconfirmed orders");
}
}
namespace App\Console\Commands;
use AndyDefer\Task\Contracts\Services\TaskServiceInterface;
use AndyDefer\Task\Records\TaskPayloadRecord;
use AndyDefer\DomainStructures\Utils\StrictDataObject;
use App\Tasks\ClearUnconfirmedOrdersTask;
use Illuminate\Console\Command;
final class ScheduleTaskCommand extends Command
{
protected $signature = 'task:schedule';
protected $description = 'Schedule the clear unconfirmed orders task';
public function __construct(
private readonly TaskServiceInterface $task,
) {
parent::__construct();
}
public function handle(): int
{
// Créer le payload avec un objet StrictDataObject
$payload = new TaskPayloadRecord(
type: 'clear_orders',
data: StrictDataObject::from([
'minutes' => 30,
'force' => false,
]),
);
// Enregistrer comme tâche récurrente (delay_seconds > 0)
$signature = $this->task->register(ClearUnconfirmedOrdersTask::class, $payload);
$this->info("Task registered with signature: {$signature}");
return 0;
}
}
use AndyDefer\Task\Records\TaskPayloadRecord;
use AndyDefer\DomainStructures\Utils\StrictDataObject;
$payload = new TaskPayloadRecord(
type: 'clear_orders',
data: StrictDataObject::from([
'minutes' => 30,
'force' => true,
'notify' => '[email protected]',
]),
);
final class SendWelcomeEmailTask extends AbstractTask
{
public function getConfig(): TaskConfigRecord
{
return new TaskConfigRecord(
signature: new TaskSignatureVO('send-welcome-email'),
description: 'Send welcome email to new user',
delay_seconds: new CounterVO(0), // Pas de récurrence
max_attempts: new CounterVO(3),
end_at: new Iso8601DateTimeVO('2026-05-24T23:59:59+00:00'), // Expire
);
}
}
final class CleanLogsTask extends AbstractTask
{
public function getConfig(): TaskConfigRecord
{
return new TaskConfigRecord(
signature: new TaskSignatureVO('clean-logs'),
description: 'Clean old log files',
delay_seconds: new CounterVO(3600), // Toutes les heures
max_attempts: new CounterVO(3),
end_at: null, // Jamais (récurrente à vie)
);
}
}
// Tâche unique avec période de grâce (par défaut)
$taskId = $this->task->register(SendReportTask::class, $payload);
// Tâche qui exige une exécution stricte (pas de grâce)
$overrideConfig = new TaskConfigRecord(
signature: new TaskSignatureVO('critical-task'),
description: 'Critical task - no grace period',
delay_seconds: new CounterVO(0),
max_attempts: new CounterVO(1),
start_at: null,
end_at: new Iso8601DateTimeVO('2026-05-24T23:59:59+00:00'),
);
$taskId = $this->task->register(CriticalTask::class, $payload, $overrideConfig);
use AndyDefer\Task\Contracts\Services\TaskServiceInterface;
final class TaskController
{
public function __construct(
private readonly TaskServiceInterface $task,
) {}
public function process(): JsonResponse
{
// Traitement standard
$result = $this->task->process(50);
// Ou filtrage
$uniqueOnly = $this->task->processUniqueOnly(20);
$recurringOnly = $this->task->processRecurringOnly(10);
return response()->json([
'unique_success' => $result->unique_success->value,
'unique_failed' => $result->unique_failed->value,
'recurring_success' => $result->recurring_success->value,
'recurring_failed' => $result->recurring_failed->value,
'unique_errors' => $result->unique_errors->toArray(),
'recurring_errors' => $result->recurring_errors->toArray(),
]);
}
}
// config/task.php
'batch' => [
'order' => 'oldest', // FIFO : le plus ancien d'abord
// ou 'newest' // LIFO : le plus récent d'abord
],
public function getConfig(): TaskConfigRecord
{
return new TaskConfigRecord(
signature: new TaskSignatureVO('my-task'),
description: 'My task',
delay_seconds: new CounterVO(300),
max_attempts: new CounterVO(5), // 5 tentatives max
);
}
protected function process(): void
{
$this->info("Processing started");
$this->info("Step 1 complete");
if ($error) {
$this->error("Something went wrong: " . $error->getMessage());
}
}
namespace Tests\Unit\Tasks;
use AndyDefer\DomainStructures\Services\HydrationService;
use AndyDefer\DomainStructures\Utils\StrictDataObject;
use AndyDefer\Logger\Contracts\LoggerInterface;
use AndyDefer\Task\Contexts\TaskContext;
use AndyDefer\Task\Records\TaskPayloadRecord;
use AndyDefer\Task\ValueObjects\TaskIdVO;
use AndyDefer\Task\ValueObjects\TaskSignatureVO;
use App\Tasks\ClearUnconfirmedOrdersTask;
use Tests\TestCase;
use App\Models\Order;
final class ClearUnconfirmedOrdersTaskTest extends TestCase
{
private ClearUnconfirmedOrdersTask $task;
protected function setUp(): void
{
parent::setUp();
$logger = $this->createMock(LoggerInterface::class);
$hydration = new HydrationService();
$context = new TaskContext();
$context->setTaskId(new TaskIdVO('550e8400-e29b-41d4-a716-446655440000'));
$context->setSignature(new TaskSignatureVO('clear-unconfirmed-orders'));
$context->setLaravelApp(app());
$this->task = new ClearUnconfirmedOrdersTask($context, $logger, $hydration);
}
public function test_execute_deletes_unconfirmed_orders(): void
{
// Arrange
Order::create([
'status' => 'pending',
'created_at' => now()->subMinutes(40),
]);
$payload = new TaskPayloadRecord(
type: 'clear_orders',
data: StrictDataObject::from([
'minutes' => 30,
]),
);
// Act
$this->task->execute($payload);
// Assert
$this->assertDatabaseCount('orders', 0);
}
}
class MyController {
public function __construct(
private TaskRegistryService $registry,
private TaskRunnerService $runner,
private TaskValidatorService $validator,
private TaskBatchService $batch,
private TaskFinderService $finder,
) {}
}
class MyController {
public function __construct(
private TaskService $task,
) {}
}