Skip to content

Build an Artisan Command workflow

The reference app's orders:confirm Command accepts durable order, actor, tenant, and idempotency identifiers. It reconstructs and authorizes the Internal actor, calls one UseCase, prints operational output, and returns Laravel's success code.

The Command is an application boundary, not the Pulsar package generator CLI.

Before you begin

Run the reference app reset, then inspect Command. This is an application Command discovered by Laravel, not Pulsar's package generator CLI.

Keep command work at the boundary

examples/reference-app/app/Pulsar/Services/Internal/Modules/Orders/Commands/ConfirmOrderCommand.php — Context, authorization, one UseCase, output, and exit code.

php
<?php

namespace App\Pulsar\Services\Internal\Modules\Orders\Commands;

use App\Models\User;
use App\Pulsar\Domain\Orders\Models\Order;
use App\Pulsar\Services\Internal\Modules\Orders\UseCases\ConfirmPendingOrder;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Gate;

final class ConfirmOrderCommand extends Command
{
    protected $signature = 'orders:confirm {orderId} {actorId} {tenantId} {idempotencyKey}';

    protected $description = 'Confirm a pending order as an Internal actor.';

    // #region confirm-order-command
    public function handle(ConfirmPendingOrder $useCase): int
    {
        $order = Order::query()->findOrFail((int) $this->argument('orderId'));
        $actor = User::query()->findOrFail((int) $this->argument('actorId'));
        $tenantId = (string) $this->argument('tenantId');
        abort_unless($actor->tenant_id === $tenantId && $order->tenant_id === $tenantId, 403);
        Gate::forUser($actor)->authorize('confirm', $order);

        $useCase->execute($order->id, (string) $this->argument('idempotencyKey'));
        $this->components->info("Order {$order->id} confirmed.");

        return self::SUCCESS;
    }
    // #endregion
}

The Command owns delivery input and output, but no transaction or business branch. The shared ConfirmPendingOrder UseCase owns the transaction and application idempotency key.

Verify discovery and exit status

Run composer run reference:test:console. The test resolves the discovered signature, checks the success output, and confirms the pending Order changed state.

Troubleshoot

If the signature is absent, check bootstrap/app.php command discovery and the path under app/Pulsar/Services/Internal/Modules/Orders/Commands. Do not move the workflow into handle().

Continue with the scheduled workflow or the queue workflow.