
# Percabangan Bersyarat

Alur kerja dapat melompat ke langkah bernama berdasarkan keluaran langkah sebelumnya. Caranya dengan mengembalikan kunci khusus `_next_step` dalam nilai yang dikembalikan langkah.

Jika Anda secara khusus ingin melompat kembali ke langkah sebelumnya berdasarkan status alur kerja, lihat [Pengulangan](https://queuety.inline0.dev/id/docs/workflows/repeats). Cara ini menjaga lompatan balik tetap eksplisit dalam definisi alur kerja, alih-alih menyembunyikannya di dalam kelas langkah.

## Langkah bernama

Beri nama langkah menggunakan argumen kedua untuk `->then()`:

```php
use Queuety\Queuety;

Queuety::workflow( 'process_order' )
    ->then( ValidateOrderHandler::class, 'validate' )
    ->then( ChargePaymentHandler::class, 'charge' )
    ->then( FulfillOrderHandler::class, 'fulfill' )
    ->then( SendConfirmationHandler::class, 'confirm' )
    ->then( HandleFailureHandler::class, 'failure' )
    ->dispatch( [ 'order_id' => 123 ] );
```

Tanpa nama eksplisit, langkah diberi nama berdasarkan indeksnya (`'0'`, `'1'`, `'2'`, dan seterusnya).

## Kunci `_next_step`

Sebuah langkah dapat mengembalikan `_next_step` untuk melompat ke langkah bernama, melewati semua langkah di antaranya. Langkah setelah target lompatan tetap dijalankan secara berurutan: tanpa lompatan, alur kerja hanya melanjutkan ke langkah berikutnya dalam daftar, sehingga dalam contoh di atas langkah `confirm` yang berhasil akan berlanjut ke `failure` kecuali mengembalikan `_next_step` yang melewatinya atau `HandleFailureHandler` memeriksa kunci `error` terlebih dahulu:

```php
use Queuety\Step;

class ValidateOrderHandler implements Step {
    public function handle( array $state ): array {
        $order = wc_get_order( $state['order_id'] );

        if ( ! $order || $order->get_status() === 'cancelled' ) {
            return [
                'error'  => 'Order is invalid or cancelled',
                '_next_step'  => 'failure',
            ];
        }

        return [
            'order_total' => $order->get_total(),
            'customer_id' => $order->get_customer_id(),
        ];
    }

    public function config(): array {
        return [];
    }
}
```

Saat `ValidateOrderHandler` mengembalikan `_next_step => 'failure'`, alur kerja melewati `charge`, `fulfill`, dan `confirm`, lalu langsung melompat ke langkah `failure`. Kunci `_next_step` dikonsumsi oleh mesin alur kerja dan tidak disimpan dalam status.

## Pola percabangan

### Lewati berdasarkan kondisi

```php
class CheckInventoryHandler implements Step {
    public function handle( array $state ): array {
        $in_stock = check_inventory( $state['sku'] );

        if ( ! $in_stock ) {
            return [
                'reason' => 'Out of stock',
                '_next_step'  => 'notify_backorder',
            ];
        }

        return [ 'inventory_reserved' => true ];
    }

    public function config(): array {
        return [];
    }
}
```

### Penyelesaian dini

Lompat ke langkah terakhir untuk melewati pemrosesan yang tidak diperlukan:

```php
class CheckCacheHandler implements Step {
    public function handle( array $state ): array {
        $cached = get_transient( "report_{$state['user_id']}" );

        if ( $cached ) {
            return [
                'report_url' => $cached,
                '_next_step'      => 'done',
            ];
        }

        return [ 'cache_miss' => true ];
    }

    public function config(): array {
        return [];
    }
}
```

## Contoh lengkap

```php
Queuety::workflow( 'content_pipeline' )
    ->then( CheckCacheHandler::class, 'check_cache' )
    ->then( FetchDataHandler::class, 'fetch' )
    ->then( CallLLMHandler::class, 'generate' )
    ->then( SaveResultHandler::class, 'save' )
    ->then( ReturnCachedHandler::class, 'done' )
    ->dispatch( [ 'user_id' => 42 ] );
```

Jika pemeriksaan cache menemukan kecocokan, alur kerja melompat dari `check_cache` langsung ke `done`, melewati `fetch`, `generate`, dan `save`. Jika tidak ditemukan, langkah dijalankan berurutan dan `save` juga berlanjut ke `done`, sehingga `ReturnCachedHandler` harus menangani kedua alur tersebut.
