
# 조건부 분기

워크플로는 이전 단계의 출력에 따라 이름이 지정된 단계로 건너뛸 수 있습니다. 단계의 반환값에 특수 키 `_next_step`을 반환하면 됩니다.

워크플로 상태에 따라 이전 단계로 돌아가려면 [반복](https://queuety.inline0.dev/ko/docs/workflows/repeats)을 참조하세요. 이렇게 하면 단계 클래스 안에 뒤로 가는 연결을 숨기는 대신 워크플로 정의에 명시할 수 있습니다.

## 이름이 지정된 단계

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

이름을 명시적으로 지정하지 않으면 단계의 인덱스가 이름으로 사용됩니다(`'0'`, `'1'`, `'2'` 등).

## `_next_step` 키

단계는 `_next_step`을 반환해 이름이 지정된 단계로 이동하고 그 사이의 모든 단계를 건너뛸 수 있습니다. 이동 대상 뒤의 단계는 순서대로 계속 실행됩니다. 이동하지 않으면 워크플로는 목록의 다음 단계로 계속 진행하므로, 위 예시에서는 성공한 `confirm` 단계가 건너뛰는 `_next_step`을 반환하거나, `HandleFailureHandler`가 먼저 `error` 키를 확인하지 않는 한 `failure`로 이어집니다:

```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`은 두 경로를 모두 처리해야 합니다.
