123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- <?php
- /**
- * Define a workflow.
- * @author Administrateur
- * @category Plugin
- * @license MIT
- */
- class Workflow extends Entity{
- public $id;
- public $label = 'Workflow Sans titre'; //libellé (Texte)
- public $icon = 'fas fa-network-wired'; //Icone (Icône)
- public $color = '#222222'; //Couleur (Couleur)
- //Types de workflows
- const TYPE_GLOBAL = 'global';
- const TYPE_ENTITY = 'entity';
- const TYPE_LIST = 'list';
- const TYPE_ALL = 'all';
- public $type = self::TYPE_GLOBAL; //Couleur (Couleur)
- public $entity = ''; //Entité lié au workflow si de type entité ou liste (slug)
- public $cause = '{}'; // Causes (json)
- protected $TABLE_NAME = 'workflow_workflow';
- public $fields = array(
- 'id' => 'key',
- 'label' => 'string',
- 'icon' => 'string',
- 'type' => 'string',
- 'entity' => 'string',
- 'cause' => 'longstring',
- 'color' => 'string'
- );
- //Colonnes indexées
- public $indexes = array();
- //Retourn les types de workflow (général, liste, entité) uou un seul type si le slug est spécifié
- public static function types($slug = null){
- $types = array(
- self::TYPE_GLOBAL => array('label' => 'Général' ),
- self::TYPE_LIST => array('label' => 'Lié à une liste' ),
- self::TYPE_ENTITY => array('label' => 'Lié à une entité' ),
- self::TYPE_ALL => array('label' => 'Tous' ),
- );
- if(!isset($slug)) return $types;
- return isset($types[$slug]) ? $types[$slug] : $types[self::TYPE_GLOBAL];
- }
- //Regroupe les causes de possibles en fonction du slug et/ou du type de workflow fournis
- public static function causes($slug = null,$type = null ){
- $types = array();
- //Récupere les causes de bases dans le dossier cause
- foreach (glob(__DIR__.SLASH.'cause'.SLASH.'*.class.php') as $file) {
- require_once($file);
- $class = str_replace('.class.php','',basename($file));
- $infos = $class::manifest();
- if(isset($type) && !in_array($type, $class::manifest('type')) && !in_array(Workflow::TYPE_ALL, $class::manifest('type')) ) continue;
- $types[$infos['slug']] = $class;
- }
- //Récupere les causes en provenances d'autres plugins si existantes
- Plugin::callHook('workflow_cause',array(&$types));
- if(!isset($slug)) return $types;
- return isset($types[$slug]) ? $types[$slug] : $types['date'];
- }
- //Lance le workflow (vérifie les causes et lance les effets si les causes sont validées)
- public function run($causes = null,$parameters = array()){
- $logs = array('Verification des conditions');
- //Récuperation des causes du workflow (stockées en bdd en json)
- $this->cause = json_decode($this->cause,true);
- //Récuperation de tous les types de causes possibles (si non spécifié en premier parametre)
- if(!isset($causes)) $causes = self::causes();
- //Ajout des infos du forwlof courant au tableau de parametres utilisé par les causes et effets
- $parameters['workflow'] = $this->toArray();
- //On enleve le json des causes non utilisé pour gagner en lisibilité/place
- unset($parameters['workflow']['cause']);
- //Si le workflow est de type liste d'entité, on l'applique sur une boucle de cette liste
- if($this->type == self::TYPE_LIST){
- //On vérifie que la liste d'entité sur laquelle boucler est définie (pas le cas dans une execution manuelle)
- if(!isset($parameters['list'])) throw new Exception("Liste non fournie");
- //Pour chaque entité de la boucle
- foreach ($parameters['list'] as $i=>$current) {
- //On ajoute l'objet courant au tableau de parametres utilisé par les causes et effets
- $parameters['current'] = $current;
- //si pas de condition on valide, sinon on les vérifie
- if(!empty($this->cause)){
- if(!self::cause_recursive_check($this->cause,$causes,0,$logs,$parameters)){
- $logs[] = 'Item #'.$i.'Conditions non valables';
- continue;
- }
- }
- $logs[] = 'Item #'.$i.'Conditions valables';
- $logs[] = 'Lancement des effets';
- //On execute les effets
- $logs = array_merge($logs,$this->run_effects($parameters));
- }
- }else{
- //si pas de condition on valide, sinon on les vérifie
- if(!empty($this->cause)){
- if(!self::cause_recursive_check($this->cause,$causes,0,$logs,$parameters)){
- $logs[] = 'Conditions non valables';
- $logs[] = 'Terminé';
- return $logs;
- }
- }
- $logs[] = 'Conditions valables';
- $logs[] = 'Lancement des effets';
- //On execute les effets
- $logs = array_merge($logs,$this->run_effects($parameters));
- }
- $logs[] = 'Terminé';
- return $logs;
- }
- /*
- Vérification récursive d'un tableau de causes pour le workflow courant
- - $filters = le tableau de causes du workflow
- - $causes = le tableau de stype de causes possibles
- - iteration = le niveau de récursivité sur lequel on se trouve
- - logs = tableau de logs retourné en fin de workflow (pour l'historique)
- - parameters = tabeau de données contextuel utilisé par les causes/effets et pour le templating mustache des causes/effets
- */
- function cause_recursive_check($filters,$causes,$iteration = 0,&$logs = array(),$parameters = array()){
- $filterResults = array();
- foreach ($filters as $i=>$filter) {
- //Si on est sur un sous groupe de causes, on execute une recursivité
- if(isset($filter['group'])){
- $filterResults['group'.$iteration] = self::cause_recursive_check($filter['group'],$causes,$iteration+1,$logs,$parameters) ? 'true' : 'false';
- continue;
- }else{
- //Si on est sur une cause
- $filter['operator'] = html_entity_decode($filter['operator']);
- //On récuepre la classe du type de la cause courante
- $cause = $causes[$filter['column']];
- //On execute la méthode de veritication (check) de la cause
- //définie dans la classe de type de cause qui retourne vrai ou faux
- // en fonction des données en parametres (filter : données de la cause, parameters : données du workflow/entité courant)
- $check = $cause::check($filter,$parameters);
- //On stocke la vérification bolééene sous forme de string dans un tableau des résultats de check ($filterResults)
- $filterResults[$cause::manifest('label').$i] = $check ? 'true' : 'false';
- if(isset($filter['join'])) $filterResults[] = $filter['join'];
- }
- }
- // Chaining des booléens de résultats
- // On récupere toutes les valeurs vrai / faux stockées dans $filterResults et on les concatene aux jointures (et/ou)
- //dans une seule chaine
- $evalChain = '$result = ';
- foreach($filterResults as $filterResult){
- if($filterResult==='true') $evalChain .= ' true ';
- if($filterResult==='false') $evalChain .= ' false ';
- if($filterResult=='and') $evalChain .= ' && ';
- if($filterResult=='or') $evalChain .= '|| ';
- }
- $evalChain .= ';';
- //Evaluation des booléens de la chaine pour determiner la réponse finale et stockage dans la variable $result
- eval($evalChain);
- $logs[] = '> Niveau '.$iteration.' : '. ($result ? 'VRAI': 'FAUX').' <small class="text-muted">'.json_encode($filterResults,JSON_PRETTY_PRINT).'</small>';
- return $result;
- }
- //Lancement des effets du workflow
- public function run_effects($parameters = array()){
- require_once(__DIR__.SLASH.'WorkflowEffect.class.php');
- //Récuperation des effets a executer dans l'ordre
- $effects = WorkflowEffect::loadAll(array('workflow'=>$this->id),array('sort'));
- $logs = array();
- foreach($effects as $effect){
- //Récuperation du tableau des champs de formulaire pré-setté lors de la creation de l'effet
- $effect->values = json_decode($effect->values,true);
- //execution de l'effet via la méthode run définie dans la classe de type effect ciblée
- try{
- $logs = array_merge($logs,$effect->run($parameters));
- }catch(Exception $e){
- $logs[] = 'Erreur: '.$e->getMessage();
- }
- }
- return $logs;
- }
- }
- ?>
|