Le composant workflow de Symfony
Le talk « composant workflow » a été présenté par Hamza Amrouche.
Le composant workflow, est sorti avec Symfony 3.2. Il fournit des outils permettant de modéliser des processus ou des cycles de vie. Il permet de simplifier la gestion des graphs, les processus de validation et/ou machines à états, grâce à la programmation orientée objet. Un workflow est un processus ou un cycle de vie que vos objets traversent. Chaque étape du processus est appelée « place ». Vous définissez également des transitions qui décrivent l'action à effectuer d'une place à une autre. En pratique, pour créer un workflow, vous définissez des "états" et des "transitions" (qui sont les événements qui peuvent se produire entre deux états).
Pour rendre vos workflows plus flexibles, vous pouvez créer l'objet Workflow avec un EventDispatcher. Vous pouvez désormais créer des écouteurs d'événement pour bloquer les transitions (c'est-à-dire en fonction des données de l'object) et effectuer des actions supplémentaires lorsqu'une opération se produit.
1. Les nouveautés
1.1 L'exception TransitionException
// ...
use Symfony\Component\Workflow\Registry;
use App\Entity\BlogPost;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Workflow\Exception\TransitionException;
class BlogController extends Controller
{
public function edit(Registry $workflows)
{
$post = new BlogPost();
$workflow = $workflows->get($post);
// if there are multiple workflows for the same class,
// pass the workflow name as the second argument
// $workflow = $workflows->get($post, 'blog_publishing');
$workflow->can($post, 'publish'); // False
$workflow->can($post, 'to_review'); // True
// Update the currentState on the post
try {
$workflow->apply($post, 'to_review');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
// See all the available transitions for the post in the current state
$transitions = $workflow->getEnabledTransitions($post);
}
}
L'exception TransitionException a été introduite dans Symfony 4.1
1.2 La méthode addWorkflow()
Lorsque vous définissez plusieurs wokflow, vous devez envisager d'utiliser un registre, qui est un objet qui stocke et donne accès à différents workflow. Un registre aide également à décider si un workflow prend en charge l'objet utilisé:
// ...
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\WorkflowInterface\InstanceOfSupportStrategy;
use Acme\Entity\BlogPost;
use Acme\Entity\Newsletter;
$blogWorkflow = ...
$newsletterWorkflow = ...
$registry = new Registry();
$registry->addWorkflow($blogWorkflow, new InstanceOfSupportStrategy(BlogPost::class));
$registry->addWorkflow($newsletterWorkflow, new InstanceOfSupportStrategy(Newsletter::class));
La méthode addWorkflow() a été introduite dans Symfony 4.1. Dans les versions précédentes de Symfony, il s'appelait add ().
2. Les améliorations
2.1 Injecter des metadata : cas d'utilisation
2.1.1 Cas d'utilisation
J'ai besoin d'injecter une route pour y avoir accès dans :
- un workflow
- une place
- une transition
2.1.1.a Injecter des metadata : la configuration de mon workflow
# app/config/config.yml
workflows:
article_publishing:
type: 'workflow' # or 'state_machine'
marking_store:
type: 'multiple_state' # or 'single_state'
arguments:
- 'currentPlace'
supports:
- AppBundle\Entity\Article
places:
- draft
- review
- rejected
- published
transitions:
to_review:
from: draft
to: review
publish:
from: review
to: published
reject:
from: review
to: rejected
class Article
{
//la propriété qui stockera l'état
public $currentPlace;
public $title;
public $content;
}
Notre exemple se base sur un article. Un article peut avoir l'un des statuts prédéfinis dans la config :
- draft => status brouillon
- review => status révisé
- rejected => status rejeté
- published => status publié
2.1.1.b Injecter des metadata : Récupérer les metadata (php)
$metadataStore = $workflow->getMetadataStore();
//framework.workflows.my_workflows.metadata.route
$metadataStore->getWorkflowMetadata()->get('route');
//framework.workflows.my_workflows.places.some_place.metadata.route
$metadataStore->getPlaceMetadata($place)->get('route');
//framework.workflows.my_workflows.places.some_transitions.metadata.route
$metadataStore->getTransitionMetadata($transition)->get('route');
2.1.1.c Injecter des metadata : Récupérer les metadata (twig)
$metadataStore = $workflow->getMetadataStore();
//framework.workflows.my_workflows.metadata.route
{{ workflow_metadata(article, 'route') }}
//framework.workflows.my_workflows.places.some_place.metadata.route
{{ workflow_metadata(article, 'route', place) }}
//framework.workflows.my_workflows.places.some_transitions.metadata.route
{{ workflow_metadata(article, 'route', transition) }}
2.1.2 Transition blocker ou expliquer pourquoi une transition est bloquée
use Symfony\Component\Workflow\Event\GuardEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class BlogPostReviewListener implements EventSubscriberInterface
{
public function guardReview(GuardEvent $event)
{
/** @var \App\Entity\BlogPost $post */
$post = $event->getSubject();
$title = $post->title;
if (empty($title)) {
$event->addTransitionBlocker(
new TransitionBlocker(
"Impossible de publier cet article, il n'a pas de titre."
));
}
}
public static function getSubscribedEvents()
{
return array(
'workflow.blogpost.guard.to_review' => array('guardReview'),
);
}
}
2.1.2.a Pourquoi vous ne pouvez pas publier cet article?
<ul>
{% for transition in workflow_all_transitions(article) %}
{% if not workflow_can(article, transition.name) %}
<ul>
{% for blocker in framework.workflows_build_transition_blocker_list(article, transition.name) %}
<li>
{{ blocker.message }}
</li>
{% endfor %}
</ul>
{% endif %
{% endfor %}
</ul>
Source:
Découvrez les derniers articles d'alter way
- kubevpn
- Kubernetes 1.32
- re:Invent 2024 : AWS mise tout sur l'IA pour son Cloud
- OVHcloud Summit 2024 : L’innovation au cœur d’un cloud souverain et performant
- Big Data & AI Paris 2024 : L'IA au cœur de toutes les transformations.
- Un retour vers l'open-source ? Vos outils DevOps préférés et leurs equivalents open-source.