# Déclaration d'un modèle de workflow
Le modèle d'un workflow référence le graphe et la définition des paramètres. Ce modèle est une Smart Structure qui
hérite de la Smart StructureWDOC
.
Exemple : vendor/My/SmartStructures/MyWorkflow/MyWorkflowArticleModel.xml
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_WFL_ARTICLE" label="Modèle suivi des articles">
<smart:extends ref="WDOC"/>
<smart:class>My\SmartStructures\MyWorkflow\MyWorkflowArticleBehavior</smart:class>
</smart:structure-configuration>
</smart:config>
# Attachement d'un graphe de workflow
L'attachement du modèle à un graphe donné se fait dans la classe de comportement du modèle. La méthode
SmartStructure\Wdoc::useWorkflowGraph()
permet d'indiquer quel graphe est utilisé par le modèle. Cette association
doit être faite dans le constructeur de la classe de comportement du modèle.
Exemple : vendor/My/SmartStructures/MyWorkflow/MyWorkflowArticleBehavior.php
namespace My\SmartStructures\MyWorkflow;
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public function __construct(...$args)
{
$this->useWorkflowGraph(__DIR__ . "/MyArticleGraph.xml");
parent::__construct(...$args);
}
}
Attention
Le constructeur parent construit les droits des transitions en fonction du graphe. Il doit donc être indiqué après
l'appel à la méthode useWorkflowGraph()
.
# Classe de comportement d'un modèle de workflow
La classe correspondante à un workflow doit définir la structure de ce workflow. Cette structure s'exprime sous la forme
d'un graphe, exprimé notamment au moyen des propriétés de classe $cycle
et $transitions
.
Si la méthode SmartStructure\Wdoc::useWorkflowGraph()
a été utilisée, alors les propriétés $cycle
, $transitions
et
$stepLabels
ont été initialisées avec le graphe indiqué.
Dans le cas contraire, il est nécessaire de renseigner ces propriétés afin de constituer le graphe du workflow.
Attention
La définition manuelle du workflow (sans passer par un XML) bien que possible est déconseillée.
# $cycle
La propriété $cycle
définit le graphe à proprement parler. C'est une liste d'éléments de la forme :
[
"e1" => "<état de départ>",
"e2" => "<état d'arrivée>",
"t" => "<transition à utiliser>"
];
où
e1
est l'identifiant de l'état de départ,e2
est l'identifiant de l'état d'arrivée,t
est l'identifiant de la transition à utiliser pour passer de l'état de départ à l'état d'arrivée.
Exemple :
public $cycle = [
[
"e1" => "<état de départ 1>",
"e2" => "<état d'arrivée 1>",
"t" => "<transition à utiliser 1>"
],
…,
[
"e1" => "<état de départ N>",
"e2" => "<état d'arrivée N>",
"t" => "<transition à utiliser N>"
]
];
# $transitions
La propriété $transitions
définit l'ensemble des types de transitions utilisables. C'est un tableau associatif dont la
clé est le nom de la transition, et la valeur est un élément de la forme :
[
"nr" => true,
"m0" => "myFirstCondition",
"m1" => function ($nextStep, $currentStep, $confirmationMessage) {},
"m2" => "myFirstProcess",
"m3" => "myLastProcess",
"ask" => ["askId1", …]
];
où
nr
est un booléen indiquant qu'il ne faut pas demander de raison au passage de transition (nr pour No Reason).
La valeur par défaut est àfalse
; dans ce cas, une popup demande à l'utilisateur de préciser la raison du passage de transition.m0
,m1
,m2
,m3
sont chacune le nom d'une méthode de la classe de workflow.ask
est un tableau d'identifiants de paramètres ou de Smart Fields du workflow ou de Smart Field de l'élément associé, qui sont utilisés pour générer la demande des informations de transition.
La configuration d'une transition est effectuée au travers de l'objet Anakeen\SmartStructure\Wdoc\Transition
fourni
par la méthode Wdoc::getTransition()
.
Préconisation
Il est déconseillé de modifier directement l'attribut $this->transition
de l'objet dans le cas où celui-ci est
initialisé par un graphe en utilisant la méthode Wdoc::useWorkflowGraph()
. Il est conseillé d'utilisé la méthode
Wdoc::getTransition()
Exemple :
<?php
namespace My\SmartStructures\MyWorkflow;
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public function __construct(...$args)
{
$this->useWorkflowGraph(__DIR__ . "/MyArticleGraph.xml");
parent::__construct(...$args);
$this->getTransition("transmission")->setM0(function () {
// ...
});
// ...
$this->getTransition("printing")
->setM2(function () {})
->setRequireComment(false);
$this->getTransition("rejecting")->setAsks(function () {
return [$this->getAttribute("wmy_reason"), $this->getSmartElement()->getAttribute("my_deadlinedate")];
});
}
}
# $firstState
La propriété $firstState
définit l'état initial des Smart Elements liés à ce cycle de vie. Elle désigne l'identifiant
d'un état.
Graphe XML
Indiqué par le Smart Field graph/steps/step/@initial
.
# $attrPrefix
Lors de la génération d'un cycle de vie, Anakeen Platform génère un grand nombre de Smart Fields pour paramétrer
finement chaque état et chaque transition. Ces Smart Fields sont préfixés par $attrPrefix
pour éviter les éventuelles
collisions en base de données.
Graphe XML
Indiqué par le Smart Field graph/@ns
.
# $stepLabels
La propriété $stepLabels
indique les libellés pour les états et les activités. C'est un tableau associatif ; la clé
est l'identifiant de l'étape.
Exemple :
[
"start" => ["state" => "Initialisé", "activity" => "Rédaction"],
"control" => ["state" => "Rédigé", "activity" => "Vérification"],...
];
Graphe XML
Indiqué par le Smart Field graph/steps/step/@state-labelet
graph/steps/step/@activity-label` .
# Les méthodes de transition
Les méthodes appelées lors des transitions en m0
, m1
, m2
, m3
sont des méthodes de la Smart Structure de
workflow.
Pour déclarer une méthode mi, il faut utiliser la méthode setMi()
de l'objet
transition en indiquant une fonction closure en paramètre.
# Définition méthode m0
La méthode appelée en m0
est de la forme suivante:
setM0($nextStep, $currentStep, $confirmationMessage);
où :
$nextStep
est l'identifiant de la prochaine étape, (étape d'arrivée)$currentStep
est l'identifiant de l'étape actuelle, (étape de départ)$confirmationMessage
est le message de confirmation (si la méthode est exécutée pour l'affichage des menus, le message est vide)
Si elle retourne une chaîne vide, alors la transition peut être effectuée. Dans le cas contraire, elle doit retourner un message localisé qui indiquera à l'utilisateur la raison pour laquelle la transition ne peut pas être effectuée.
Le message retourné par la méthode est présenté dans un "tooltip" lors du survol de l'entrée de l'étape dans le menu
Étapes
, ou dans un "popover" lors du clic sur l'entrée de l'étape.
Note : Cette méthode est aussi appelée lors de l'affichage de la liste des transitions accessibles. Cela permet notamment de signaler à l'utilisateur les transitions qu'il a le droit d'effectuer, mais pour lesquelles il doit faire des modifications sur le Smart Element. De fait, cette méthode ne doit pas modifier le Smart Element.
<?php
namespace My\SmartStructures\MyWorkflow;
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public function __construct(...$args)
{
$this->useWorkflowGraph(__DIR__ . "/MyArticleGraph.xml");
parent::__construct(...$args);
$this->getTransition("transmission")->setM0(function ($newState, $startState, $comment = '') {
// Ici le smart element à la structure de MY_ARTICLE
if (mb_strlen($this->getSmartElement()->getRawValue("my_content")) < 1000) {
return "Le contenu est doit avoir au moins 1000 caractères";
}
});
}
}
# Définition méthode m1
La méthode appelée en m1
est de la forme :
setM1($nextStep, $currentStep, $confirmationMessage);
où :
$nextStep
est l'identifiant de la prochaine étape, (étape d'arrivée)$currentStep
est l'identifiant de l'étape actuelle, (étape de départ)$confirmationMessage
est le message de confirmation
Si elle retourne une chaîne vide, alors la transition peut être effectuée. Dans le cas contraire, elle doit retourner un message localisé qui indiquera à l'utilisateur la raison pour laquelle la transition ne peut pas être effectuée.
# Définition méthode m2
La méthode appelée en m2
est de la forme :
setM2($currentStep, $previousStep, $confirmationMessage);
où :
$currentStep
est l'identifiant de l'étape actuelle, (étape d'arrivée)$previousStep
est l'identifiant de l'ancienne étape, (étape de départ)$confirmationMessage
est le message de confirmation
Si elle retourne une chaîne non vide, cette chaîne est considérée comme un message d'erreur qui sera affiché à l'utilisateur à l'issue de la transition (Cette méthode n'est pas bloquante).
# Définition méthode m3
La méthode appelée en m3
est de la forme :
setM3($currentStep, $previousStep, $confirmationMessage);
où :
$currentStep
est l'identifiant de l'étape actuelle, (étape d'arrivée)$previousStep
est l'identifiant de l'ancienne étape, (étape de départ)$confirmationMessage
est le message de confirmation
Si elle retourne une chaîne non vide, cette chaîne est considérée comme un message d'erreur qui sera affiché à l'utilisateur à l'issue de la transition (Cette méthode n'est pas bloquante).
# Information de transition du workflow ask
Les informations de transition, qui sont utilisables dans les ask
peuvent être :
- des paramètres du modèle de workflow.
- des Smart Fields du modèle de workflow.
- des Smart Fields du Smart Element associé.
- des paramètres du Smart Element associé.
Exemple de déclaration d'un paramètre de workflow utilisable pour une information de transition :
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_WFL_ARTICLE">
<smart:parameters>
<smart:field-set name="my_infos_transitions" type="frame" label="Informations de transition" access="ReadWrite">
<smart:field-longtext name="wmy_reason" label="Raison de refus" access="ReadWrite" needed="true"/>
</smart:field-set>
</smart:parameters>
</smart:structure-configuration>
</smart:config>
# Utilisation des informations de transition ask
Les informations de transition sont envoyées lors de la requête de transition effectuée par l'interface web.
Les valeurs présentées sur l'interface sont les valeurs des paramètres ou des Smart Fields référencés au moment de la demande de transition.
Les valeurs des informations de transition utilisées sont enregistrées dans l'historique du Smart Element.
Si le paramètre référencé est obligatoire, l'interface exigera que le paramètre soit complété. Cette contrainte n'est pas testée lorsqu'il s'agit de passer une transition par programmation. Elle n'est prise en compte que par l'interface web. De même, les valeurs des informations de transition ne sont remplies que lors d'une transition effectuée par l'interface.
Attention
Contrairement aux paramètres de Smart Structure ordinaires, les contraintes ne sont pas prises en compte dans les informations de transition.
Dans les méthodes m1
, m2
, m3
, la récupération des valeurs des informations de transition s'effectue au moyen de la
méthode WDoc::getAskValue($askFieldId)
. La méthode m0
n'a pas accès aux valeurs des ask, car elle est aussi utilisée
pour la constitution de menu des transition.
Lors de la recherche des transitions accessibles, la méthode m0
ne peut accéder aux informations de transition (elles
ne sont pas encore demandées).
Si le ask
référence des Smart Fields du Smart Element, la valeur du ask est enregistrée dans le Smart Element entre le
m0
et le m1
. Par contre, le Smart Element n'est pas encore enregistré sur le serveur. Il sera enregistré après le
m1
si cette méthode ne retourne pas d'erreur.
La déclaration des ask
est réalisée par la méthode Transition::setAsks()
. Elle prend en argument une fonction qui
doit retourner un tableau d'objets (Smart Field) de type Anakeen\Core\SmartStructure\BasicAttribute
.
<?php
namespace My\SmartStructures\MyWorkflow;
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public function __construct(...$args)
{
$this->useWorkflowGraph(__DIR__ . "/MyArticleGraph.xml");
parent::__construct(...$args);
$this->getTransition("transmission")
->setM1(function () {
$ctoComment = $this->getAskValue("my_content");
$c = mb_strlen($ctoComment);
if ($c < 1000) {
return sprintf("Seulement %d caractères.\nLe commentaire doit avoir plus de 1000 caractères", $c);
}
})
->setM2(function () {
$reason = $this->getAskValue("wmy_reason");
$this->getSmartElement()->addHistoryEntry("Raison du rejet : " . $reason);
})
->setAsks(function () {
return [
// Paramètre du workflow
$this->getAttribute("wmy_reason"),
// Smart Field du Smart Element courant
$this->getSmartElement()->getAttribute("my_content")
];
});
}
}
# Inhiber la demande de raison
Par défaut, une confirmation avec une demande de la raison pour effectuer la transition est demandée. La méthode
setRequiredComment
de l'objet Transition
permet de désactiver cette demande.
<?php
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public function __construct(...$args)
{
$this->useWorkflowGraph(__DIR__ . "/MyArticleGraph.xml");
parent::__construct(...$args);
$this->getTransition("transmission")->setRequiredComment(false);
}
}
Cette méthode modifie l'index nr
du tableau de transitions.
# Programmer un graphe sans XML
Considérons le workflow de l'introduction. Pour avoir un graphe identique, la classe le définissant contiendra :
<?php
namespace My\SmartStructures\MyWorkflow;
class MyWorkflowArticleBehavior extends \SmartStructure\Wdoc
{
public $attrPrefix = "MY";
public $firstState = "start";
public $cycle = [
[
'e1' => 'start',
'e2' => 'control',
't' => 'transmission'
],
[
'e1' => 'control',
'e2' => 'start',
't' => 'correcting'
],
[
'e1' => 'control',
'e2' => 'rejected',
't' => 'rejecting'
],
[
'e1' => 'control',
'e2' => 'published',
't' => 'publishing'
],
[
'e1' => 'published',
'e2' => 'rejected',
't' => 'rejecting'
],
[
'e1' => 'published',
'e2' => 'printed',
't' => 'printing'
]
];
public $transition = [
'transmission' => [
'label' => 'Transmettre'
],
'correcting' => [
'label' => 'Corriger'
],
'rejecting' => [
'label' => 'Abandonner'
],
'publishing' => [
'label' => 'Diffuser'
],
'printing' => [
'label' => 'Imprimer'
]
];
public $stepLabels = [
'start' => [
'state' => 'Initialisé',
'activity' => 'Rédaction'
],
'control' => [
'state' => 'Rédigé',
'activity' => 'Vérification'
],
'published' => [
'state' => 'Publié',
'activity' => 'Publication'
],
'printed' => [
'state' => 'Imprimé',
'activity' => ''
],
'rejected' => [
'state' => 'Rejeté',
'activity' => ''
]
];
}