
# 条件分岐

前のステップの出力に基づいて、ワークフロー内の名前付きステップに移動できます。ステップの戻り値に特別な`_next_step`キーを含めて実現します。

ワークフローの状態に基づいて前のステップに戻りたい場合は、[繰り返し](https://queuety.inline0.dev/ja/docs/workflows/repeats)を参照してください。ステップクラス内に戻り先を隠すのではなく、ワークフロー定義内で明示できます。

## 名前付きステップ

`->then()`の2つ目の引数を使って、ステップに名前を付けます。

```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 ] );
```

明示的な名前を付けない場合、ステップにはインデックス（`'0'`、`'1'`、`'2'`など）が名前として付けられます。

## `_next_step`キー

ステップは`_next_step`を返して名前付きステップへジャンプし、その間のステップをスキップできます。ジャンプ先より後のステップは順番に実行されます。ジャンプしない場合、ワークフローはリストの次のステップへ進むだけなので、上の例では`confirm`ステップが成功すると`failure`へ進みます。これをスキップする`_next_step`を返すか、先に`error`キーを確認する`HandleFailureHandler`がない限り、処理は続きます。

```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 [];
    }
}
```

`ValidateOrderHandler`が`_next_step => 'failure'`を返すと、ワークフローは`charge`、`fulfill`、`confirm`をスキップし、`failure`ステップへ直接移動します。`_next_step`キーはワークフローエンジンによって消費され、状態には保存されません。

## 分岐パターン

### 条件に応じてスキップ

```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 [];
    }
}
```

### 早期完了

不要な処理を省くには、最後のステップに移動します。

```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 [];
    }
}
```

## 完全な例

```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 ] );
```

キャッシュチェックでヒットした場合、ワークフローは`check_cache`から`done`へ直接移動し、`fetch`、`generate`、`save`をスキップします。キャッシュにない場合は各ステップが順番に実行され、`save`から`done`へも進むため、`ReturnCachedHandler`は両方の経路に対応する必要があります。
