Workflow.class.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. /**
  3. * Define a workflow.
  4. * @author Administrateur
  5. * @category Plugin
  6. * @license MIT
  7. */
  8. class Workflow extends Entity{
  9. public $id;
  10. public $label = 'Workflow Sans titre'; //libellé (Texte)
  11. public $icon = 'fas fa-network-wired'; //Icone (Icône)
  12. public $color = '#222222'; //Couleur (Couleur)
  13. //Types de workflows
  14. const TYPE_GLOBAL = 'global';
  15. const TYPE_ENTITY = 'entity';
  16. const TYPE_LIST = 'list';
  17. const TYPE_ALL = 'all';
  18. public $type = self::TYPE_GLOBAL; //Couleur (Couleur)
  19. public $entity = ''; //Entité lié au workflow si de type entité ou liste (slug)
  20. public $cause = '{}'; // Causes (json)
  21. protected $TABLE_NAME = 'workflow_workflow';
  22. public $fields = array(
  23. 'id' => 'key',
  24. 'label' => 'string',
  25. 'icon' => 'string',
  26. 'type' => 'string',
  27. 'entity' => 'string',
  28. 'cause' => 'longstring',
  29. 'color' => 'string'
  30. );
  31. //Colonnes indexées
  32. public $indexes = array();
  33. //Retourn les types de workflow (général, liste, entité) uou un seul type si le slug est spécifié
  34. public static function types($slug = null){
  35. $types = array(
  36. self::TYPE_GLOBAL => array('label' => 'Général' ),
  37. self::TYPE_LIST => array('label' => 'Lié à une liste' ),
  38. self::TYPE_ENTITY => array('label' => 'Lié à une entité' ),
  39. self::TYPE_ALL => array('label' => 'Tous' ),
  40. );
  41. if(!isset($slug)) return $types;
  42. return isset($types[$slug]) ? $types[$slug] : $types[self::TYPE_GLOBAL];
  43. }
  44. //Regroupe les causes de possibles en fonction du slug et/ou du type de workflow fournis
  45. public static function causes($slug = null,$type = null ){
  46. $types = array();
  47. //Récupere les causes de bases dans le dossier cause
  48. foreach (glob(__DIR__.SLASH.'cause'.SLASH.'*.class.php') as $file) {
  49. require_once($file);
  50. $class = str_replace('.class.php','',basename($file));
  51. $infos = $class::manifest();
  52. if(isset($type) && !in_array($type, $class::manifest('type')) && !in_array(Workflow::TYPE_ALL, $class::manifest('type')) ) continue;
  53. $types[$infos['slug']] = $class;
  54. }
  55. //Récupere les causes en provenances d'autres plugins si existantes
  56. Plugin::callHook('workflow_cause',array(&$types));
  57. if(!isset($slug)) return $types;
  58. return isset($types[$slug]) ? $types[$slug] : $types['date'];
  59. }
  60. //Lance le workflow (vérifie les causes et lance les effets si les causes sont validées)
  61. public function run($causes = null,$parameters = array()){
  62. $logs = array('Verification des conditions');
  63. //Récuperation des causes du workflow (stockées en bdd en json)
  64. $this->cause = json_decode($this->cause,true);
  65. //Récuperation de tous les types de causes possibles (si non spécifié en premier parametre)
  66. if(!isset($causes)) $causes = self::causes();
  67. //Ajout des infos du forwlof courant au tableau de parametres utilisé par les causes et effets
  68. $parameters['workflow'] = $this->toArray();
  69. //On enleve le json des causes non utilisé pour gagner en lisibilité/place
  70. unset($parameters['workflow']['cause']);
  71. //Si le workflow est de type liste d'entité, on l'applique sur une boucle de cette liste
  72. if($this->type == self::TYPE_LIST){
  73. //On vérifie que la liste d'entité sur laquelle boucler est définie (pas le cas dans une execution manuelle)
  74. if(!isset($parameters['list'])) throw new Exception("Liste non fournie");
  75. //Pour chaque entité de la boucle
  76. foreach ($parameters['list'] as $i=>$current) {
  77. //On ajoute l'objet courant au tableau de parametres utilisé par les causes et effets
  78. $parameters['current'] = $current;
  79. //si pas de condition on valide, sinon on les vérifie
  80. if(!empty($this->cause)){
  81. if(!self::cause_recursive_check($this->cause,$causes,0,$logs,$parameters)){
  82. $logs[] = 'Item #'.$i.'Conditions non valables';
  83. continue;
  84. }
  85. }
  86. $logs[] = 'Item #'.$i.'Conditions valables';
  87. $logs[] = 'Lancement des effets';
  88. //On execute les effets
  89. $logs = array_merge($logs,$this->run_effects($parameters));
  90. }
  91. }else{
  92. //si pas de condition on valide, sinon on les vérifie
  93. if(!empty($this->cause)){
  94. if(!self::cause_recursive_check($this->cause,$causes,0,$logs,$parameters)){
  95. $logs[] = 'Conditions non valables';
  96. $logs[] = 'Terminé';
  97. return $logs;
  98. }
  99. }
  100. $logs[] = 'Conditions valables';
  101. $logs[] = 'Lancement des effets';
  102. //On execute les effets
  103. $logs = array_merge($logs,$this->run_effects($parameters));
  104. }
  105. $logs[] = 'Terminé';
  106. return $logs;
  107. }
  108. /*
  109. Vérification récursive d'un tableau de causes pour le workflow courant
  110. - $filters = le tableau de causes du workflow
  111. - $causes = le tableau de stype de causes possibles
  112. - iteration = le niveau de récursivité sur lequel on se trouve
  113. - logs = tableau de logs retourné en fin de workflow (pour l'historique)
  114. - parameters = tabeau de données contextuel utilisé par les causes/effets et pour le templating mustache des causes/effets
  115. */
  116. function cause_recursive_check($filters,$causes,$iteration = 0,&$logs = array(),$parameters = array()){
  117. $filterResults = array();
  118. foreach ($filters as $i=>$filter) {
  119. //Si on est sur un sous groupe de causes, on execute une recursivité
  120. if(isset($filter['group'])){
  121. $filterResults['group'.$iteration] = self::cause_recursive_check($filter['group'],$causes,$iteration+1,$logs,$parameters) ? 'true' : 'false';
  122. continue;
  123. }else{
  124. //Si on est sur une cause
  125. $filter['operator'] = html_entity_decode($filter['operator']);
  126. //On récuepre la classe du type de la cause courante
  127. $cause = $causes[$filter['column']];
  128. //On execute la méthode de veritication (check) de la cause
  129. //définie dans la classe de type de cause qui retourne vrai ou faux
  130. // en fonction des données en parametres (filter : données de la cause, parameters : données du workflow/entité courant)
  131. $check = $cause::check($filter,$parameters);
  132. //On stocke la vérification bolééene sous forme de string dans un tableau des résultats de check ($filterResults)
  133. $filterResults[$cause::manifest('label').$i] = $check ? 'true' : 'false';
  134. if(isset($filter['join'])) $filterResults[] = $filter['join'];
  135. }
  136. }
  137. // Chaining des booléens de résultats
  138. // On récupere toutes les valeurs vrai / faux stockées dans $filterResults et on les concatene aux jointures (et/ou)
  139. //dans une seule chaine
  140. $evalChain = '$result = ';
  141. foreach($filterResults as $filterResult){
  142. if($filterResult==='true') $evalChain .= ' true ';
  143. if($filterResult==='false') $evalChain .= ' false ';
  144. if($filterResult=='and') $evalChain .= ' && ';
  145. if($filterResult=='or') $evalChain .= '|| ';
  146. }
  147. $evalChain .= ';';
  148. //Evaluation des booléens de la chaine pour determiner la réponse finale et stockage dans la variable $result
  149. eval($evalChain);
  150. $logs[] = '> Niveau '.$iteration.' : '. ($result ? 'VRAI': 'FAUX').' <small class="text-muted">'.json_encode($filterResults,JSON_PRETTY_PRINT).'</small>';
  151. return $result;
  152. }
  153. //Lancement des effets du workflow
  154. public function run_effects($parameters = array()){
  155. require_once(__DIR__.SLASH.'WorkflowEffect.class.php');
  156. //Récuperation des effets a executer dans l'ordre
  157. $effects = WorkflowEffect::loadAll(array('workflow'=>$this->id),array('sort'));
  158. $logs = array();
  159. foreach($effects as $effect){
  160. //Récuperation du tableau des champs de formulaire pré-setté lors de la creation de l'effet
  161. $effect->values = json_decode($effect->values,true);
  162. //execution de l'effet via la méthode run définie dans la classe de type effect ciblée
  163. try{
  164. $logs = array_merge($logs,$effect->run($parameters));
  165. }catch(Exception $e){
  166. $logs[] = 'Erreur: '.$e->getMessage();
  167. }
  168. }
  169. return $logs;
  170. }
  171. }
  172. ?>