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.