PHP code example of andydefer / laravel-task

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]',
    ]),
);

protected function process(): void
{
    $data = $this->context->getPayload()->data;
    
    $minutes = $data->minutes ?? 30;
    $force = $data->force ?? false;
    $notify = $data->notify ?? null;
    
    $this->info("Clearing orders older than {$minutes} minutes");
    
    if ($force) {
        $this->info("Force delete enabled");
    }
    
    if ($notify) {
        $this->info("Will notify: {$notify}");
    }
}

$payload = new TaskPayloadRecord(
    type: 'advanced',
    data: StrictDataObject::from([
        'user' => [
            'id' => 123,
            'name' => 'John Doe',
        ],
        'settings' => [
            'timeout' => 30,
            'retries' => 3,
        ],
    ]),
);

// Accès
$userId = $payload->data->user->id;
$timeout = $payload->data->settings->timeout;

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)
        );
    }
}

// config/task.php
'grace_period' => [
    'enabled' => env('TASK_GRACE_PERIOD_ENABLED', true),
    'seconds' => env('TASK_GRACE_PERIOD_SECONDS', 86400),
],

// 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,
    ) {}
}
bash
php artisan vendor:publish --tag=task-config
json
{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "signature": "clear-unconfirmed-orders",
    "class": "App\\Tasks\\ClearUnconfirmedOrdersTask",
    "payload": {
        "type": "clear_orders",
        "data": {
            "minutes": 30,
            "force": false
        }
    },
    "status": "pending",
    "created_at": "2026-05-24T10:00:00+00:00",
    "start_at": "2026-05-24T10:00:00+00:00",
    "end_at": null,
    "delay_seconds": 0,
    "attempts": 0,
    "max_attempts": 3,
    "last_error": null,
    "enforce_exact_schedule": false
}
json
{
    "signature": "clean-logs",
    "class": "App\\Tasks\\CleanLogsTask",
    "payload": {
        "type": "clean",
        "data": {
            "days": 30,
            "backup": true
        }
    },
    "start_at": "2026-05-24T10:00:00+00:00",
    "end_at": null,
    "delay_seconds": 3600,
    "last_run_at": "2026-05-24T11:00:00+00:00",
    "next_run_at": "2026-05-24T12:00:00+00:00",
    "success_count": 42,
    "failure_count": 3,
    "last_error": null
}