
# Branchement conditionnel

Les workflows peuvent passer à une étape nommée en fonction du résultat d’une étape précédente. Pour cela, l’étape renvoie une clé spéciale `_next_step`.

Si vous souhaitez précisément revenir à une étape précédente en fonction de l’état du workflow, consultez [Répétitions](https://queuety.inline0.dev/fr/docs/workflows/repeats). La boucle arrière reste ainsi explicite dans la définition du workflow au lieu d’être dissimulée dans une classe d’étape.

## Étapes nommées

Nommez les étapes à l’aide du deuxième argument de `->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 ] );
```

Sans nom explicite, les étapes sont nommées selon leur index (`'0'`, `'1'`, `'2'`, etc.).

## La clé `_next_step`

Une étape peut renvoyer `_next_step` pour passer à une étape nommée et ignorer toutes celles qui la séparent de la cible. Les étapes situées après la cible s’exécutent toujours dans l’ordre : en l’absence de saut, le workflow passe simplement à l’étape suivante de la liste. Ainsi, dans l’exemple ci-dessus, une étape `confirm` réussie passe à `failure`, sauf si elle renvoie un `_next_step` qui l’ignore ou si `HandleFailureHandler` vérifie d’abord la présence d’une clé `error` :

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

Lorsque `ValidateOrderHandler` renvoie `_next_step => 'failure'`, le workflow ignore `charge`, `fulfill` et `confirm`, puis passe directement à l’étape `failure`. La clé `_next_step` est consommée par le moteur de workflow et n’est pas conservée dans l’état.

## Modèles de branchement

### Ignorer sous condition

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

### Terminaison anticipée

Passez à la dernière étape pour ignorer le traitement inutile :

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

## Exemple complet

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

Si la vérification du cache trouve une entrée, le flux de travail passe directement de `check_cache` à `done`, en ignorant `fetch`, `generate` et `save`. En cas d’absence, les étapes s’exécutent dans l’ordre et `save` se poursuit également jusqu’à `done` ; `ReturnCachedHandler` doit donc gérer les deux parcours.
