Le composant Workflow de symfony

Voir la vidéo

Dans ce tutoriel je vous propose de découvrir le principe du composant Workflow qui va permette de mettre en place une logique de machine à états finis dans votre application Symfony (mais on peut aussi l'utiliser en mode standalone).

Cette approche permet de représenter la logique de votre application comme un ensemble d'états prédéfinis qui vont être liés ensembles par des transitions. C'est une approche très pertinente si vous avez à créer une logique métier complexe.

Survolons le fonctionnement

On commencera par installer le module

composer require symfony/workflow

Ensuite on peut décrire notre machine de différentes manière (on utilisera ici du YAML mais vous pouvez le faire aussi en PHP et XML)

framework:
  workflows:
    blog_publishing:
      type: 'state_machine'
      marking_store:
        type: 'method'
        property: 'currentState'
      supports:
        - App\Entity\Post
      initial_marking: draft
      places:
        - draft
        - reviewed
        - published
        - rejected
      transitions:
        to_review:
          from: draft
          to: reviewed
        publish:
          from: reviewed
          to: published
          metadata:
            hours: [9, 20]
        reject:
          from: [reviewed, draft]
          to: rejected

On utilise ici un type state_machine mais on peut aussi utiliser un type workflow qui permet à un élément d'être dans plusieurs états à la fois (l'état sera alors représenté par un tableau de chaîne). Dans le cas des workflow une transition ne pourra être prise que lorsque l'élément est dans tous les états demandés dans le from.

Dans notre entité on peut créer le champs qui permettra de sauvegarder l'état de notre élément.

<?php
namespace App\Entity;

use App\Repository\PostRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: PostRepository::class)]
class Post
{
    // ...

    private array $currentState = [];

    // ...

    public function getCurrentState(): string
    {
        return $this->currentState;
    }

    public function setCurrentState(string $currentState): Post
    {
        $this->currentState = $currentState;
        return $this;
    }
}

Enfin, vous pourrez utiliser votre Workflow pour mettre à jour l'état de votre entité depuis n'import quel service.

<?php

namespace App\Controller;

use App\Entity\Post;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Workflow\WorkflowInterface;

class PostController extends AbstractController
{

    public function __construct(private WorkflowInterface $blogPublishingWorkflow){ }

    #[Route('/', name: 'post')]
    public function index(): Response
    {
        $post = new Post();
        $this->blogPublishingWorkflow->apply($post, 'to_review');
        $post->getCurrentState(); // 'reviewed'
        $this->blogPublishingWorkflow->apply($post, 'publish');
        $post->getCurrentState(); // 'published'
        // ...
    }
}

Il sera aussi possible d'utiliser une série d’événements qui permettront d'ajouter des comportements particuliers ou de bloquer certaines transitions.

Pour aller plus loin

Si la théorie vous a donné envie et que vous souhaitez voir un cas d'utilisation des Workflow je vous renvoie sur la vidéo "# Un Workflow de pro avec Symfony 5 !" de yoan dev.

Publié
Technologies utilisées
Auteur :
Grafikart
Partager