Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Le composant workflow de Symfony, c'est graphem...

Le composant workflow de Symfony, c'est graphement bien !

Gérer les étapes de validation d’une application peut vite devenir un casse tête. Le composant Workflow de Symfony a été introduit en 3.2 pour simplifier la vie de tous les développeurs qui avaient besoin de gérer des graphs, processus de validation et/ou machines à états. J’ai eu l’occasion de m’y frotter sur le projet d’un grand compte et j’aimerais vous faire part de cette expérience. Vous décrire cette mise en place sera également l’occasion de dévoiler deux petites révolutions qui seront bientôt livrées à la communauté.

#Symfony_Live

Hamza Amrouche

March 30, 2018
Tweet

Other Decks in Programming

Transcript

  1. Les-Tilleuls.coop Lead Dev Symfony chez Les-Tilleuls.coop Core Team Api-Platform Contributeur

    Symfony @cDaed Simperfit Bureau étendu AFUP Hamza Amrouche
  2. Les-Tilleuls.coop Les-Tilleuls.coop SCOP fondée en 2011 Détenue à 100% par

    ses salariés 25 coopérateurs, 97% de croissance On recrute à Amiens, Lille, Paris et Londres [email protected]
  3. Les-Tilleuls.coop L’accompagnement des particuliers et des professionnels du bâtiment Groupe

    Adeo (Leroy Merlin) Équipe technique de 20 personnes (St Cloud) Quotatis est présent aujourd’hui au Symfony Live Quotatis
  4. Les-Tilleuls.coop A B 3 6 2 3 4 2 1

    5 2 La théorie des graphes
  5. Les-Tilleuls.coop A 3 6 2 3 4 2 1 5

    2 B La théorie des graphes
  6. Les-Tilleuls.coop 3 6 2 3 4 2 1 5 2

    A B La théorie des graphes
  7. Les-Tilleuls.coop $definition = new Definition([‘in_progress',‘to_validate'], [ new Transition( ‘to_validate', //

    transition name [‘in_progress’], // from place [‘to_validate'] // to place ) ], ‘in_progress' ); } Définition du workflow
  8. Les-Tilleuls.coop Le composant nous permet de garantir que les projets

    qui sont dans certains états (places) ont bien passé toutes les règles de validation. Merci au Workflow !
  9. Les-Tilleuls.coop Les events public static function getSubscribedEvents() { return [

    'workflow.project.enter.to_validate'=> ['assignUser'], 'workflow.project.entered.validated' => ['sendToLegacy'], ]; }
  10. Les-Tilleuls.coop class BlogPostReviewListener implements EventSubscriberInterface { public function guardReview(GuardEvent $event)

    { $post = $event->getSubject(); $title = $post->title; if (!$title) { // Posts with no title should not be allowed $event->setBlocked(true); } } public static function getSubscribedEvents() { return ['workflow.blogpost.guard.to_review' => ['guardReview']]; } } Le guard event
  11. Les-Tilleuls.coop {# Or loop through the enabled transitions #} {%

    for transition in workflow_transitions(post) %} <a href="...">{{ transition.name }}</a> {% endfor %} La vue
  12. Les-Tilleuls.coop {# Check if the object is in some specific

    place #} {% if workflow_has_marked_place(post, 'to_review') %} <p>This post is ready for review.</p> {% endif %} La vue
  13. Les-Tilleuls.coop {# Check if some place has been marked on

    the object #} {% if 'waiting_some_approval' in workflow_marked_places(post) %} <span class="label">PENDING</span> {% endif %} La vue
  14. Les-Tilleuls.coop Contexte Quotatis Quotatis permet aux personnes qui souhaitent faire

    des travaux de créer des projets, ceux-ci ont plusieurs états. Pour atteindre ces états il y a des conditions, qui ne sont remplies que si le projet est prêt.
  15. Les-Tilleuls.coop En mode API Scenario: As authenticated user, I can

    set the project's status to "to_validate" Given I am authenticated as user And there is a newly created project When I set the project's status to "to_validate" Then I should get a project And the status should be "to_validate" And I should be assigned to the project L’utilisateur à travers l’application :
  16. Les-Tilleuls.coop L’API elle-même qui transforme le projet en « pending_search

    » lorsque qu’un appel à l’api « Legacy » est fait. // […] $project->setLeadReference((string) $xml->newid); if ($this->projectWorkflow->can($project, ‘pending_search’)) { $this->projectWorkflow->apply($project, ‘pending_search’); } // […] En mode API
  17. Les-Tilleuls.coop La « Legacy » qui transforme le projet en

    « found » lorsque le projet a trouvé son artisan.
 
 Via un simple PUT. En mode API
  18. Les-Tilleuls.coop private function checkStatusWorkflow(Project $data) { $content = json_decode($request->getContent(), true);

    if (isset($content[‘status’])) { return; } if ($this->projectWorkflow->can($data, $status)) { $this->projectWorkflow->apply($data, $status); return; } throw new BadRequestHttpException('status.not_in_workflow'); } En mode API
  19. Les-Tilleuls.coop framework: workflows: issue: marking_store: type: single_state arguments: - state

    supports: AppBundle\Entity\Project places: - created - to_valdate transitions: affect: guard: "is_valid(subject, [‘toValidate’]) » from: created to: to_validate
  20. Les-Tilleuls.coop Ajout des transitions blockers $event->addTransitionBlocker( new TransitionBlocker('You can not

    validate the project. Try again tomorrow morning.') ); Exemple par Javier Eguiluz.
  21. Les-Tilleuls.coop Ajout des transitions blockers {# […] get the transition.name

    #} <ul> {% for blocker in workflow_build_transition_blocker_list(project, transition.name) %} <li> {{ blocker.message }} {% if blocker.parameters.expression is defined %} <code>{{ blocker.parameters.expression }}</code> {% endif %} </li> {% endfor %} </ul> Exemple par Javier Eguiluz.
  22. Les-Tilleuls.coop Plus de contraintes sur le nom des places 4.1:

    https://github.com/symfony/symfony/pull/26079
  23. Les-Tilleuls.coop Before weird: places: - a' - é! - b\"(\"

    supports: AppBundle\Entity\Project transitions: - from: a' name: "{}" to: é! type: workflow Exemple par Grégoire Pineau. The place "é!" contains invalid characters.
  24. Les-Tilleuls.coop After weird: places: - a' - é! - b\"(\"

    supports: AppBundle\Entity\Project transitions: - from: a' name: "{}" to: é! type: workflow Exemple par Grégoire Pineau.
  25. Les-Tilleuls.coop Un store de metadata framework: workflows: project: supports: -

    App\Entity\Project metadata: description: 'This is a project' # ... places: created: metadata: some_key: 'some_value' # ... transitions: to_validate: metadata: some_key: 'some_value' Exemple par Javiere Eguiluz.
  26. Les-Tilleuls.coop Un store de metadata public function onReview(Event $event) {

    $metadataStore = $event->getWorkflow()->getMetadataStore(); foreach ($event->getTransition()->getTos() as $place) { $this->flashbag->add('info', $metadataStore->getPlaceMetadata($place)->get(‘description')); } } Exemple par Javier Eguiluz.
  27. Les-Tilleuls.coop Un store de metadata <strong>Current place(s)</strong> <ul> {% for

    place in workflow_marked_places(article) %} <li> {{ place }}: <code>{{ workflow_metadata(article, 'title', place) ?: 'n-a'}}</code> </li> {% endfor %} </ul> Exemple par Javier Eguiluz.
  28. Les-Tilleuls.coop Un store de metadata <strong>Enabled transition(s)</strong> <ul> {% for

    transition in workflow_transitions(article) %} <li> {{ transition.name }}: <code>{{ workflow_metadata(article, 'title', transition) ?: 'n-a'}}</code> </li> {% endfor %} </ul> Exemple par Javier Eguiluz.
  29. Les-Tilleuls.coop interface WorkflowInterface { public function getMarking($subject); public function can($subject,

    $transitionName); public function buildTransitionBlockerList($subject, string $transitionName): TransitionBlockerList; public function apply($subject, $transitionName); public function getEnabledTransitions($subject); public function getName(); public function getDefinition(); public function getMarkingStore(); public function getMetadataStore(): MetadataStoreInterface; } 4.1: https://github.com/symfony/symfony/pull/24751