Table des matières
Si l'on se réfère à la définition de Wikipédia, il s'agit de la modélisation et la gestion informatique de l'ensemble des tâches à accomplir et des différents acteurs impliqués dans la réalisation d'un processus métier .
Pour un processus de suivi d'appel (Helpdesk), il s'agit de la modélisation des tâches lié à la vie du ticket. Le workflow étant représenté par des états et des transitions entre les états.
Justement, voyons plus précisement le cas d'un suivi d'un bug simpliste:
Etats :
-
'New' : Etat initial du bug
-
'Accepted' : Lorsque le bug a été accepté
-
'Refused' : Lorsque le bug a été réfusé
-
'Open' : Lorsque le bug est pris en compte
-
'Closed': Lorsque le bug est fermé
-
'Unresolved' : Lorsque le bug ne peut être résolu
Transitions :
-
'Accept' : De New vers 'Accepted'
-
'Refuse': De New vers Refused
-
'Take': De Accepted vers Open
-
'Close': De Open vers Closed
-
'CantResolve': De Open vers Unresolved
En passant à la moulinette ' GraphViz ' ça nous donne:
Les états sont représentés par les noeuds rouges et les transitions par les liens entre ces noeuds.
Ajoutons à cela que chaque bug aura une instance dans le workflow dont le rôle sera d'enregistrer l'état de ce dernier.
Nous allons voir comment mettre en oeuvre un workflow de type 'suivi d'appel' avec le module Class:Workflow
En tout premier lieu pour utiliser notre workflow nous devrons l'enrichir d'états et de transitions ... mais nous verrons ça plus tard.
Pour faire référence à une instance du workflow, notre bug pourrait être défini ainsi:
package MyBug; use Moose; has workflow_instance => ( does => "Class::Workflow::Instance", is => "rw", ); has description => ( ....
Imaginons maintenant que nous avons une action 'accept' dont le rôle est d'accepter le bug. Pour changer l'état de l'instance nous pourrions faire quelque chose comme :
sub accept { my $bug = shift; my $wi = $bug->workflow_instance; my $current_state = $wi->state; # if your state supports named transitions my $accept = $current_state->get_transition( "accept" ) or die "There's no 'accept' transition in the current state"; my $wi_accepted = $accept->apply( $wi ); $bug->workflow_instance( $wi_accepted ); }
Attention nous devons toujours "recharger" l'instance après avoir appliquer une transition. ($bug->workflow_instance( $wi_accepted );)
Avant de continuer dans l'exploration de ce module, nous devons nous arrêter un instant sur le concept de context.
Il s'agit d'un argument qui décrit le contexte appliqué à toutes les transitions. Il pourra fournir des informations sur qui fait la transition, dans quelle condition ... Il sera très utile lors de la mise en oeuvre de restrictions.
Imaginons que nous ayons une classe MyUser :
package MyUser; has id => ( isa => "Num", is => "ro", default => sub { next_unique_id() }; ); has name => ( ... );
Nous pouvons alors créer une classe 'context' héritant de Class::Workflow::Context
package MyWorkflowContext; use Moose; extends "Class::Workflow::Context"; has user => ( isa => "MyUser", is => "rw", );
On peut alors appliquer la transition en fournissant le contexte:
sub accept { my ( $bug, $current_user ) = @_; my $wi = $bug->workflow_instance; my $current_state = $wi->state; # if your state supports named transitions my $accept = $current_state->get_transition( "accept" ) or croak "There's no 'accept' transition in the current state"; my $c = MyWorkflowContext->new( user => $current_user ); my $wi_accepted = $accept->apply( $wi, $c ); $bug->workflow_instance( $wi_accepted ); }
La transition a donc accès au contexte $c qui contient notament l'utilisateur courant.
Pour mettre en place les restrictions lors de l'application d'une transition nous allons créer notre propre classe d'instance qui stockera notamment un ' owner ' et un ' submitter ' hériant de la classe MyUser:
package MyWorkflowInstance; use Moose; extends "Class::Workflow::Instance::Simple"; has owner => ( isa => MyUser", is => "ro", # all instance fields should be read only ); has submitter => ( isa => MyUser", is => "ro", );
Lorsque la première instance est créée l'utilisateur courant est enregistré comme étant ' submitter '.
Nous pouvons enfin définir notre transition en y ajoutant une restriction avec un 'validator' fournit par Class::Workflow::Transition::Validate::Simple :
$accept->add_validators( sub {
my ( $self, $instance, $c ) = @_;
die "Not owner" unless $self->instance->owner->id == $c->user->id;
} );
Jusqu'à maintenant nous ne nous sommes pas soucier du mode de
sauvegarde de l'état des bugs. On aurait pû le faire dans un fichier YAML
ou XML ou encore en base
KiokuDB
(base
d'objet). Mais ma préférence va vers une sauvegarde en base de donnée, une
petite base SQLite faisant très bien l'affaire. Pour cela je me suis
inspiré de l'exemple fournit avec les source du module
'
example/dbic/t/example_dbic.t
'.
J'ai ensuite ajouté quelques champs aux tables du schema Workflow de manière à pouvoir nommé et décrire les workflows, états et transitions. En y aapliquant une couche de Catalyst j'obtiens une interface de gestion de Workflow.
... Affaire à suivre ...


