
# Exécuter des workflows

Un workflow peut lancer un workflow enfant comme l’une de ses étapes. Le parent se met en pause jusqu’à la fin de l’exécution du workflow enfant, puis fusionne l’état final de l’enfant dans le sien.

## La méthode `->run_workflow()`

```php
use Queuety\Queuety;

$enrichment = Queuety::workflow( 'enrich_user' )
    ->then( FetchSocialHandler::class )
    ->then( FetchCreditScoreHandler::class );

Queuety::workflow( 'onboarding' )
    ->then( CreateAccountHandler::class )
    ->run_workflow( 'enrich_user', $enrichment )
    ->then( SendWelcomeEmailHandler::class )
    ->dispatch( [ 'email' => 'user@example.com' ] );
```

La méthode `run_workflow()` prend deux arguments :
1. Un nom pour l’exécution du workflow
2. Une instance `WorkflowBuilder` qui définit les étapes de l’exécution

## Fonctionnement

Lorsque le workflow parent atteint une étape `run_workflow` :

1. L’exécution du workflow est lancée comme workflow indépendant avec son propre identifiant
2. Le workflow parent se met en pause
3. Le workflow enfant exécute ses étapes normalement
4. À la fin de son exécution, son état final est fusionné dans celui du parent
5. Le workflow parent reprend à l’étape suivante

## État parent/enfant

Le workflow enfant reçoit l’état cumulé actuel du parent comme charge utile initiale. Ses étapes peuvent donc accéder à toutes les données produites par les étapes précédentes du parent :

```php
class CreateAccountHandler implements Step {
    public function handle( array $state ): array {
        $user_id = wp_create_user( $state['email'], wp_generate_password() );
        return [ 'user_id' => $user_id ];
    }

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

// This run-workflow step can access 'user_id' from the parent
class FetchSocialHandler implements Step {
    public function handle( array $state ): array {
        $profile = fetch_social_profile( $state['user_id'] );
        return [ 'social_data' => $profile ];
    }

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

## Fusion de l’état

À la fin de l’exécution du workflow enfant, son état final (à l’exception des clés internes telles que `_steps`, `_queue`, `_priority`, `_max_attempts`) est fusionné dans l’état du parent. L’étape suivante du parent voit toutes les données des étapes précédentes du parent et du workflow enfant :

```php
class SendWelcomeEmailHandler implements Step {
    public function handle( array $state ): array {
        // Has access to:
        // - $state['email'] (from initial dispatch)
        // - $state['user_id'] (from CreateAccountHandler)
        // - $state['social_data'] (from run-workflow's FetchSocialHandler)
        // - $state['credit_score'] (from run-workflow's FetchCreditScoreHandler)

        send_welcome_email( $state['email'], $state['social_data'] );
        return [ 'welcome_sent' => true ];
    }

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

## Options d’exécution du workflow enfant

Les options `on_queue()`, `with_priority()` et `max_attempts()` du générateur d’exécution du workflow s’appliquent au workflow enfant. Les autres options au niveau du workflow sur le générateur enfant, comme `on_cancel()`, `prune_state_after()`, `must_complete_within()`, `version()`, `idempotency_key()`, les budgets `max_*()` et `compensate_on_failure()`, ne sont pas reprises :

```php
$sub = Queuety::workflow( 'heavy_processing' )
    ->on_queue( 'background' )
    ->with_priority( Priority::Normal )
    ->max_attempts( 5 )
    ->then( StepA::class )
    ->then( StepB::class );

Queuety::workflow( 'parent' )
    ->run_workflow( 'heavy', $sub )
    ->then( FinalStep::class )
    ->dispatch( $payload );
```

## Exécutions de workflows imbriquées

Les workflows enfants peuvent eux-mêmes contenir des workflows enfants, ce qui permet une imbrication arbitraire :

```php
$inner = Queuety::workflow( 'inner' )
    ->then( InnerStepA::class )
    ->then( InnerStepB::class );

$middle = Queuety::workflow( 'middle' )
    ->then( MiddleStepA::class )
    ->run_workflow( 'inner', $inner )
    ->then( MiddleStepB::class );

Queuety::workflow( 'outer' )
    ->then( OuterStepA::class )
    ->run_workflow( 'middle', $middle )
    ->then( OuterStepB::class )
    ->dispatch( $payload );
```
