Concevoir un système d'automatisation flexible du flux de travail avec le modèle de constructeur dans PHP Laravel

L'automatisation des flux de travail est au cœur de l'efficacité logicielle moderne, permettant aux équipes d'orchestrer des processus d'affaires complexes avec clarté et contrôle. Dans l'écosystème de Laravel, une approche éprouvée qui équilibre élégamment flexibilité et maintenabilité est le modèle de Builder. Cet article fournit un guide pratique et profond pour concevoir un système d'automatisation des flux de travail utilisant le modèle Builder à Laravel, passant des principes de base aux implémentations avancées et prêtes à la production.

Comprendre le modèle du constructeur dans un contexte larave

Le modèle Builder est un modèle de conception qui sépare la construction d'un objet complexe de sa représentation finale. Au lieu de forcer un seul constructeur avec de nombreux paramètres, le modèle Builder vous permet de construire un objet étape par étape, rendant le processus de création à la fois lisible et flexible.

Dans le contexte de l'automatisation des workflows, l'objet --complexe est une séquence d'étapes (un workflow). En utilisant un Builder, vous pouvez définir des workflows de compositions variées – adding, remove, or reordering steps – sans modifier les classes d'étapes sous-jacentes. Ce découplage facilite l'extension et le test du système.

Les principaux avantages sont les suivants :

Composantes essentielles du système de flux de travail

Une conception propre nécessite trois abstractions principales : le Workflow lui-même, une interface Step et un Builder qui sait assembler les étapes dans un Workflow.

Définition de la classe de flux de travail

La classe Workflow possède une collection ordonnée d'étapes et fournit une méthode pour les exécuter en séquence. Elle ne devrait pas se soucier des spécificités de chaque étape – seulement qu'ils mettent en œuvre un contrat défini.

<?php

namespace App\Workflow;

class Workflow
{
 protected array $steps = [];

 public function addStep(Step $step): self
 {
 $this->steps[] = $step;
 return $this;
 }

 public function run(): void
 {
 foreach ($this->steps as $step) {
 $step->execute();
 }
 }

 public function getSteps(): array
 {
 return $this->steps;
 }
}

Cette implémentation minimale suffit à démontrer le concept. Dans une application Laravel, vous pouvez injecter un ou un dans le flux de travail, mais même sans ces derniers, le modèle reste solide.

Création de l'interface étape

Chaque étape qui participe à un workflow doit mettre en place une interface commune. Cela garantit que le Workflow peut appeler à n'importe quelle étape sans connaître sa logique interne.

<?php

namespace App\Workflow;

interface Step
{
 public function execute(): void;
}

Vous pouvez étendre cette interface au fil du temps. Par exemple, ajouter ou permet l'exécution conditionnelle et des retours de transaction – tous deux utiles dans les flux de production.

Mise en œuvre de mesures concrètes

Voici des exemples de deux étapes communes : l'envoi d'un courriel et le traitement des données.

<?php

namespace App\Workflow\Steps;

use App\Workflow\Step;
use Illuminate\Support\Facades\Mail;

class EmailStep implements Step
{
 public function __construct(
 private readonly string $recipient,
 private readonly string $subject = 'Workflow Notification',
 private readonly string $body = ''
 ) {}

 public function execute(): void
 {
 Mail::raw($this->body, function ($message) {
 $message->to($this->recipient)
 ->subject($this->subject);
 });
 }
}

class DataProcessingStep implements Step
{
 public function __construct(
 private readonly array $data
 ) {}

 public function execute(): void
 {
 // Transform, validate, or persist $this->data
 // For demo: log the data
 \Log::info('Processing data', $this->data);
 }
}

En gardant les étapes petites et ciblées, vous encouragez la réutilisation sur différents workflows.

Mise en œuvre du constructeur

La classe Builder fournit une interface fluide pour la construction d'un objet Workflow. Chaque méthode du constructeur ajoute une étape configurée à l'instance interne du workflow, puis se retourne pour la chaîne.

<?php

namespace App\Workflow;

class WorkflowBuilder
{
 protected Workflow $workflow;

 public function __construct()
 {
 $this->workflow = new Workflow();
 }

 public function addEmailStep(string $recipient, string $subject = 'Notification', string $body = ''): self
 {
 $this->workflow->addStep(
 new Steps\EmailStep($recipient, $subject, $body)
 );
 return $this;
 }

 public function addDataProcessingStep(array $data): self
 {
 $this->workflow->addStep(
 new Steps\DataProcessingStep($data)
 );
 return $this;
 }

 public function build(): Workflow
 {
 return $this->workflow;
 }
}

Interface fluide et chaîne

L'interface fluide est ce qui fait briller le modèle Builder dans Laravel. Les développeurs peuvent composer un workflow en une seule expression:

$workflow = (new WorkflowBuilder())
 ->addEmailStep('[email protected]', 'Welcome', 'Your account is ready.')
 ->addDataProcessingStep(['user_id' => 42, 'action' => 'register'])
 ->build();

$workflow->run();

Cette lisibilité réduit la charge cognitive et facilite la réorganisation des étapes lorsque les règles d'affaires changent. Pour des scénarios plus complexes, une classe Director peut encapsuler plusieurs constructeurs prédéfinis, par exemple qui retourne un workflow entièrement construit pour l'enregistrement des nouveaux utilisateurs.

Fonctions avancées du flux de travail

Un système de workflow de production a besoin de plus que l'exécution linéaire. Laissez-les améliorer l'architecture pour supporter les étapes conditionnelles, le traitement des erreurs et la persistance.

Étapes conditionnelles utilisant les prédicats

Toutes les étapes ne doivent pas être exécutées à chaque fois. En étendant l'interface Step avec une méthode , vous pouvez prendre des décisions d'exécution basées sur des données d'exécution.

interface Step
{
 public function shouldExecute(Context $context): bool;
 public function execute(): void;
}

class ConditionalEmailStep implements Step
{
 public function shouldExecute(Context $context): bool
 {
 return $context->get('send_email') === true;
 }

 public function execute(): void
 {
 // send email...
 }
}

La méthode Workflows vérifie ensuite chaque étape de la condition avant de l'exécuter.

Gestion des erreurs et des retours

Lorsqu'une étape échoue, vous pouvez vouloir annuler les étapes déjà terminées (un modèle de saga). Ajouter une méthode à l'interface Étape :

interface Step
{
 public function execute(): void;
 public function rollback(): void;
}

Le flux de travail devient alors un gestionnaire de transaction:

public function run(): void
{
 $completed = [];
 try {
 foreach ($this->steps as $step) {
 $step->execute();
 $completed[] = $step;
 }
 } catch (\Throwable $e) {
 // Rollback in reverse order
 foreach (array_reverse($completed) as $completedStep) {
 $completedStep->rollback();
 }
 throw $e;
 }
}

Cette tendance est particulièrement utile pour les opérations en plusieurs étapes qui doivent maintenir la cohérence des données, comme les opérations financières ou les ajustements des stocks.

État de la durée du travail

Les flux de travail à long terme (p. ex., chaînes d'approbation des utilisateurs) doivent persister entre les demandes. Laravel , Eloquent ORM rend cela simple.

Créez un modèle qui stocke la liste des étapes (sérialisées) et l'index d'exécution actuel. Utilisez une table dédiée:

Schema::create('workflows', function (Blueprint $table) {
 $table->id();
 $table->text('steps'); // serialized array of Step objects
 $table->unsignedSmallInteger('current_step')->default(0);
 $table->string('status'); // pending, running, completed, failed
 $table->timestamps();
});

Lors de la reprise, l'objet Workflow est reconstruit à partir des étapes sérielles stockées (ou des définitions d'étapes qui peuvent être ré-infirmées à l'aide du constructeur).Une étape peut être une classe de travail Laravel, rendant native l'exécution asynchrone.

Intégration avec l'écosystème Laravel

Utilisation des emplois pour les étapes asynchrones

Pour les étapes qui doivent se dérouler en arrière-plan (par exemple, l'envoi de gros rapports), convertissez chaque étape en un travail Laravel. Le flux de travail peut envoyer des tâches en séquence, ou le constructeur peut enrouler une étape dans une classe de travail.

class DispatchJobStep implements Step
{
 public function __construct(
 private readonly object $job
 ) {}

 public function execute(): void
 {
 dispatch($this->job);
 }
}

// Usage in builder
public function addReportGenerationJobStep(int $userId): self
{
 $this->workflow->addStep(
 new DispatchJobStep(new GenerateReportJob($userId))
 );
 return $this;
}

Évolution du flux de travail de la radiodiffusion

Les mises à jour de l'interface utilisateur en temps réel peuvent tirer parti de la diffusion d'événements Laravel. Chaque étape peut déclencher un événement avant et après l'exécution:

public function execute(): void
{
 StepStarted::dispatch($this);
 // perform work
 StepCompleted::dispatch($this);
}

Les auditeurs peuvent ensuite diffuser sur un tableau de bord en ligne via WebSockets (en utilisant Laravel Echo).

Cas d'utilisations réelles dans le monde

Dans chaque cas, le modèle Builder permet à différents départements de définir leur propre composition de workflow sans toucher le moteur d'exécution sous-jacent.

Essais de flux de travail

Chaque étape peut être testée indépendamment. Le constructeur peut être testé avec des étapes simulées pour vérifier que la séquence correcte des étapes est assemblée. Les tests d'intégration peuvent exécuter le flux complet en utilisant de fausses implémentations de services externes (p. ex. ].

public function test_email_step_is_added_to_workflow()
{
 $builder = new WorkflowBuilder();
 $workflow = $builder
 ->addEmailStep('[email protected]')
 ->build();

 $steps = $workflow->getSteps();
 $this->assertCount(1, $steps);
 $this->assertInstanceOf(EmailStep::class, $steps[0]);
}

Conclusion

Le modèle Builder est un ajustement naturel pour construire l'automatisation flexible du flux de travail à Laravel. Il favorise le code lisible, configurable et testable, tandis que l'interface fluide reflète l'élégance que les développeurs Laravel aiment déjà. En étendant le modèle avec exécution conditionnelle, retournements et persistance, vous pouvez construire un système qui s'échelle des actions linéaires simples aux orchestrations complexes et majestueuses.

Pour approfondir votre compréhension, explorez la documentation officielle de Laravel sur queues et events pour l'exécution asynchrone du workflow, et examinez le modèle Builder[ sur Refactoring Guru pour des considérations de conception supplémentaires.