'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').' '.json_encode($filterResults,JSON_PRETTY_PRINT).''; 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; } } ?>