123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- <?php
- require_once(__DIR__.DIRECTORY_SEPARATOR.'DynamicField.class.php');
- /**
- * Define a dynamicform.
- * @author Charles DUBOIS
- * @category Plugin
- * @license MIT
- */
- class DynamicForm extends Entity{
- public $id;
- public $slug; //Slug (Texte)
- public $color; //Couleur (Couleur)
- public $icon; //Icônes (Icône)
- public $label; //Libellé (Texte)
- public $state; //State (Texte)
- public $firm; //Etablissement (Number)
- protected $TABLE_NAME = 'dynamicform_form';
- public $entityLabel = 'Formulaire';
- public $fields = array(
- 'id' => 'key',
- 'slug' => array('type'=>'string', 'label' => 'Slug'),
- 'color' => array('type'=>'string', 'label' => 'Couleur'),
- 'icon' => array('type'=>'string', 'label' => 'Icônes'),
- 'state' => array('type'=>'string', 'label' => 'Etat'),
- 'firm' => array('type'=>'int', 'label' => 'Etablissement','link'=>'class/Firm.class.php'),
- 'label' => array('type'=>'string', 'label' => 'Libellé')
- );
- //Colonnes indexées
- public $indexes = array('slug','firm');
- public static function remove($slug,$options = array()){
- Plugin::need('dynamicform/DynamicField,dynamicform/DynamicValue');
- $form = self::load(array('slug'=>$slug));
- if(!$form) return;
- $query = 'DELETE FROM {{table}} WHERE field IN(SELECT id FROM '.DynamicField::tableName().' fi WHERE fi.form=?) ';
- $data = array($form->id);
- if(empty($options['scope'])){
- $query .= ' AND scope=? ';
- $data[] = $options['scope'];
- }
- if(empty($options['uid'])){
- $query .= ' AND uid=? ';
- $data[] = $options['uid'];
- }
- DynamicValue::staticQuery($query,$data);
- }
- public static function check_required($slug,$options = array(),$newValues){
- Plugin::need('dynamicform/DynamicField');
- $types = FieldType::available();
- $query = "SELECT fi.id,fi.type,fi.label,fi.meta,fi.slug,fi.mandatory,fi.readonly
- FROM {{table}} fi
- LEFT JOIN ".self::tableName()." fo ON fi.form = fo.id
- WHERE fo.slug = ? ";
- $data = array($slug);
- $fields = DynamicField::staticQuery($query,$data,true,1);
- foreach($fields as $field)
- if(empty($newValues[$field->slug]) && $field->mandatory) throw new Exception('Le champ '.$field->label.' est obligatoire');
- //pour réutilisation de performance par la méthode record, souvant appellée juste après
- return $fields;
- }
- public static function record($slug,$options = array(),$newValues){
- Plugin::need('dynamicform/DynamicField');
- $types = FieldType::available();
- //si on a pas récupéré les fields dans un opération précédente (ex check_required), on les récupere ici
- if(!isset($options['fields'])){
- $query = "SELECT fi.id,fi.type,fi.label,fi.meta,fi.slug,fi.mandatory,fi.readonly
- FROM {{table}} fi
- LEFT JOIN ".self::tableName()." fo ON fi.form = fo.id
- WHERE fo.slug = ? ";
- $data = array($slug);
- $fields = DynamicField::staticQuery($query,$data,true,1);
- }else{
- $fields = $options['fields'];
- //gain de perf
- unset($options['fields']);
- }
- //on affiche chaque champ dynamique du formulaire
- foreach($fields as $field){
- if(empty($newValues[$field->slug]) && $field->mandatory) throw new Exception('Le champ '.$field->label.' est obligatoire');
- //on verifie qu'une valeur a été donnée
- if(!isset($newValues[$field->slug])) continue;
- //si le champ est en lecture seule on n'enregistre pas de valeur
- if($field->readonly) continue;
- DynamicField::record(array('field'=>$field,'value'=>$newValues[$field->slug],'options'=>$options,'types'=>$types));
- }
- }
- /**
- * Affiche un formulaire en fonction de son slug et de ses options de contexte
- * @param <String> slug du formulaire ciblé
- * @param <Array> options des filtres de sélection des champs
- * @return <Array> tableau des options de ciblage des champs à récupérer
- */
- public static function show($slug,$options = array()){
- global $myFirm;
- Plugin::need('dynamicform/DynamicField,dynamicform/DynamicValue');
- $options = array_merge(array(
- 'label' => 'block', // inline (input group) / block (label classique) / none (pas de label)
- 'legend' => 'block', // block (span text muted) / none (pas de label)
- 'input-class' => '', // classes additionnelles a placer sur les inputs
- 'input-group-class' => '', // classes additionnelles a placer sur les groupes d'inputs
- 'scope' => '', // ex : client
- 'uid' => '', // ex : 12
- 'firm' => $myFirm->id // ex : 1
- ),$options);
- $options['format'] = 'table';
- $types = FieldType::available();
- //Initialisation des options de sélection des champs scope / firm etc
- $listOptions = self::list_options($slug, $options);
- //Si pas de slug on affiche rien
- if(empty($listOptions))return;
- //Récupération du tableau d'objets champs
- $fieldsObjects = self::get_fields($listOptions);
- //Mise au format table (mise en page ligne colonne) de la liste des champs
- $fieldsTable = self::fields_layout($fieldsObjects, $types, $options);
- //Mise au format liste (à plat) de la liste des champs
- $options['format'] = 'list';
- $fieldsList = self::fields_layout($fieldsObjects, $types, $options);
- $stream = '';
- $values = self::get_values($fieldsList,$options);
- if(isset($options['arrayOutput']) && $options['arrayOutput']){
- return self::get_values_as_array($fieldsList,$values);
- }
- //mise en page
- foreach($fieldsTable as $i => $columns) {
- $stream .= '<div class="row">';
- foreach ($columns as $u => $fields) {
- $stream .= '<div class="col-md column">';
- foreach($fields as $field){
- $value = isset($values[$field['id']]) ? $values[$field['id']] : '';
- $stream .= DynamicField::show(array('field'=>$field,'value'=>$value,'types'=>$types,'options'=>$options));
- }
- $stream .= '</div>';
- }
- $stream .= '</div>';
- }
- return $stream;
- }
- /**
- * Retourne un tableau de champs disponibles pour ce slug et cette firm
- * @param <String> slug du formulaire ciblé
- * @param <Array> options des filtres de sélection des champs
- * @return <Array> tableau des options de ciblage des champs à récupérer
- */
- public static function list($slug,$options = array()){
- $types = FieldType::available();
- $options = self::list_options($slug,$options);
- if(empty($options)) return array();
- $fields = self::get_fields($options);
- $rows = self::fields_layout($fields,$types,$options);
- return $rows;
- }
- /**
- * Initialise les options de filtrage pour récupération des champs
- * @param <String> slug du formulaire ciblé
- * @param <Array> options des filtres de sélection des champs
- * @return <Array> tableau des options de ciblage des champs à récupérer
- */
- public static function list_options($slug,$options = array()){
- global $myFirm;
- $options = array_merge(array(
- 'firm' => $myFirm->id, // ex : 1
- 'format' => 'list' // table (mise en page ligne colonne) ou liste (a plat)
- ),$options);
- $forms = self::loadAll(array('slug'=>$slug,'firm:IN'=>array($options['firm'],'0')));
- if(!$forms || count($forms)==0) return array();
- $formIds = array();
- foreach ($forms as $form)
- $formIds[] = $form->id;
- $options['slug'] = $slug;
- $options['form'] = $formIds;
- $options['firm'] = array($options['firm'],'0');
- return $options;
- }
- /**
- * Retourne un tableau de champs (de type array) formaté en liste ou table selon l'option 'format'
- * @param <Array> tableau d'options/ filtres de sélection
- * @return <Array> tableau brut de champs (de type object) selon les options settées
- */
- public static function get_fields_layout($options = array()){
- $types = FieldType::available();
- $fields = self::get_fields($options);
- return self::fields_layout($fields,$types,$options);
- }
- /**
- * Retourne un tableau brut de champs (de type object) selon les options settées
- * @param <Array> tableau d'options/ filtres de sélection
- * @return <Array> tableau brut de champs (de type object) selon les options settées
- */
- public static function get_fields($options = array()){
- Plugin::need('dynamicform/DynamicField');
- $data = array();
- if(empty($options['format'])) $options['format'] = 'table';
- $query = 'SELECT fi.* FROM {{table}} fi LEFT JOIN '.self::tableName().' fo ON fi.form = fo.id WHERE 1 ';
- $query .= ' AND fo.state=? ';
- $data[] = self::ACTIVE;
- if(isset($options['slug'])){
- $query .= ' AND fo.slug=? ';
- $data[] = $options['slug'];
- }else if(isset($options['id'])){
- $query .= ' AND fo.id=? ';
- $data[] = $options['id'];
- }
- if(isset($options['form'])){
- $query .= ' AND fo.id IN ('.implode(',',array_fill(0,count($options['form']),'?')).')';
- foreach ($options['form'] as $form)
- $data[] = $form;
- }
- if(isset($options['firm'])){
- $query .= ' AND fo.firm IN ('.implode(',',array_fill(0,count($options['firm']),'?')).')';
- foreach ($options['firm'] as $firm)
- $data[] = $firm;
- }
- $query .= ' ORDER BY fi.row,fi.column,fi.sort';
- $dynamicfields = array();
- foreach(DynamicField::staticQuery($query,$data,true) as $dynamicField){
- if(!is_null($dynamicField->meta) && !empty($dynamicField->meta))
- $dynamicField->meta = base64_encode($dynamicField->meta);
- $dynamicfields[] = $dynamicField;
- }
- return $dynamicfields;
- }
- /**
- * Retourne un tableau de champs (de type array) formaté en liste ou table selon l'option 'format'
- * @param <Array> tableau brut d'objets champs dynamiques
- * @param <Array> tableau des fieldtypes disponibles
- * @param <Array> tableau des options de sélection et de format
- * @return <Array> tableau formaté (table ou liste) des champs dynamiques ciblés
- */
- public static function fields_layout($fields,$types,$options = array()){
- if(is_null($types)) $types = FieldType::available();
- if(empty($options['format'])) $options['format'] = 'table';
- $rows = array();
- foreach($fields as $field){
- $row = $field->toArray();
- $row['type'] = $types[$row['type']];
- if($options['format'] == 'table'){
- if(!isset($rows[$field->row])) $rows[$field->row] = array();
- if(!isset($rows[$field->row][$field->column])) $rows[$field->row][$field->column] = array();
- $rows[$field->row][$field->column][] = $row;
- }else{
- $rows[] = $row;
- }
- }
- return $rows;
- }
- /**
- * Retourne un tableau brut de valeurs pour un set de champs en fonction du scope / firm
- * @param <Array> tableau brut de champs dynamiques (sous forme d'arrays)
- * @param <Array> tableau des options de sélection et de format
- * @return <Array> tableau brut des valeurs des champs dynamiques ciblés avec comme clé l'identifiant du champ dynamique
- */
- public static function get_values($fields,$options){
- Plugin::need('dynamicform/DynamicValue');
- $values = array();
- $fieldIds = array();
- //Récuperation des id de fields
- foreach($fields as $field)
- $fieldIds[] = $field['id'];
- if(empty($fieldIds)) return $values;
- $valueFilters = array('field:IN'=>$fieldIds);
- if(!empty($options['firm'])) $valueFilters['firm:IN'] = array($options['firm'],0);
- if(!empty($options['scope'])) $valueFilters['scope'] = $options['scope'];
- $valueFilters['uid'] = $options['uid'];
- //récuperation des valeurs déja enregistrées pour ces fields
- foreach (DynamicValue::loadAll($valueFilters) as $key => $value)
- $values[$value->field] = $value->value;
- return $values;
- }
- /**
- * Retourne le tableau formaté des valeurs de champs pour export
- * @category manipulation de tableaux
- * @param <Array> tableau brut des valeurs des champs dynamiques
- * @return <Array> tableau des valeurs des champs dynamiques utilisables pour l'export
- */
- public static function get_values_as_array($fields,$values){
- $arrayOutput = array();
- foreach($fields as $field){
- $field['value']= isset($values[$field['id']]) ? $values[$field['id']] : '';
- $arrayOutput[] = $field;
- }
- return $arrayOutput;
- }
- /**
- * Ajoute à la requete originelle les valeurs des champs dynamiques aliasisés par le slug du champ dynamique
- * @category manipulation de chaine pour création dynamiqe de requête de sélection en base
- * @param <Array> tableau des champs dynamiques potentiellement affichables
- * @param <String> requête originelle de sélection en base à modifier
- * @param <String> alias de la table mère présente dans le FROM de la requête originelle de sélection
- * @return <String> requête de sélection modifiée avec les valeurs des champs dynamiques
- */
- public static function query_column_add($fields,&$query,$alias = ''){
- global $_;
- Plugin::need('dynamicform/DynamicValue');
- $columns = array();
- //Tableau des champs dynamiques disponibles
- foreach($fields as $field)
- $columns[$field['id']] = $field['slug'];
- //Tableau des champs dynamiques sélectionnés
- $selected = isset($_['columns']) && isset($_['columns']['added']) ? $_['columns']['added'] : array();
- //On ne garde que les champs sélectionés et présents dans les champs disponibles ET les champs requetés en filtres
- if(isset($_['filters']['advanced'])){
- foreach($_['filters']['advanced'] as $field){
- $parts = explode('dynamicField_',$field['column']);
- //on ne traite que les field dynamiques
- if(count($parts)<=1) continue;
- //pour retrouver le slug du custom field (slug-fitlre) depuis le slug du filtre (dynamicField_{{id}})
- $dynamicSlug = $columns[str_replace('.value','',$parts[1])];
- $selected[] = $dynamicSlug;
- }
- }
- $columns = array_intersect($columns,$selected);
- //On crée la chaine de sélection des valeurs
- $selectFields = array();
- foreach($columns as $id=>$slug)
- $selectFields[] = 'dynamicField_'.$id.'.value AS "'.$slug.'"';
- //On récupère ce qu'il y a entre select et from et on le concatène à la chaine de sélection des valeurs créé
- $selectFields = empty($selectFields) ? ' ' : ','.implode(',',$selectFields);
- $query = preg_replace("/(?<=SELECT)(.*)(?=FROM)/i","$0".$selectFields.' ',$query);
- //on récupère ce qu'il y a entre select et where et on le concat avec les left joins pour chaque champs dynamiques à afficher
- $joinFields = array();
- foreach($columns as $id=>$slug)
- $joinFields[] = ' LEFT JOIN '.DynamicValue::tableName().' dynamicField_'.$id.' ON dynamicField_'.$id.'.uid = '.(empty($alias) ? 'id' : '`'.$alias.'`.id').' AND dynamicField_'.$id.'.field = '.$id;
- $joinFields = implode(' ',$joinFields);
- $query = preg_replace("/(?<=SELECT)(.*)(?=WHERE)/is","$0".$joinFields.' ',$query);
- }
- //Retourne un set de filtres de colonnes dynamiques en fonction de la liste des
- //champs custom fournie
- public static function get_dynamic_columns($fields){
- $columns = array();
- foreach ($fields as $field) {
- $columns[$field['slug']] =
- array(
- 'head' => '<th data-sortable="dynamicField_'.$field['id'].'.value" data-available="'.$field['slug'].'">'.$field['label'].'</th>',
- 'body' => '<td class="align-middle text-center">{{{'.$field['slug'].'}}}</td>',
- );
- }
- return $columns;
- }
- //Convertion des valeurs retours d'une db pour des colonnes dynamiques en fonction de leurs types
- public static function search_values(&$row,$options){
- if(!isset($options['force-raw'])) $options['force-raw'] = false;
- //Récupération des champs afin d'avoir les metas pour affichaqge fieldtypes exotique list, dictionary...
- $meta = array();
- foreach(DynamicField::loadAll(array('slug:IN'=>array_keys($options['slugs']))) as $field)
- $meta[$field->slug] = $field->meta;
- //pour chaque champ, s'il fait partie des types qui possèdent une propriété onHtmlDisplay, on l'applique à la valeur du champ
- foreach($options['slugs'] as $slug=>$value){
- if(!isset($options['types'][$slug])) continue;
- $type = $options['types'][$slug];
- $displayOptions = array('meta'=>$meta[$slug],'type'=>$type);
- //tansmission des parametres de contexte
- foreach($options as $key=>$option){
- if(!is_string($option)) continue;
- $displayOptions[$key] = $option;
- }
- if(isset($row['id'])) $displayOptions['uid'] = $row['id'];
- if(property_exists($type,"onHtmlDisplay") && !$options['force-raw']){
- $method = $type->onHtmlDisplay;
- $displayOptions['decoration'] = 'true';
- $value = $method($value,$displayOptions);
- }elseif(property_exists($type,"onRawDisplay")){
- $method = $type->onRawDisplay;
- $value = $method($value,$displayOptions);
- }
- $row[$slug] = $value;
- }
- }
- //Récuperation des valeurs de champs dynamic pour un formulaire, un scope et un item donné sous la forme slug field => valeur
- public static function values($formSlug,$options){
- require_once(__DIR__.SLASH.'DynamicForm.class.php');
- require_once(__DIR__.SLASH.'DynamicField.class.php');
- require_once(__DIR__.SLASH.'DynamicValue.class.php');
- $query = 'SELECT dfi.slug,dva.value FROM {{table}} dva
- LEFT JOIN '.DynamicField::tableName().' dfi ON dfi.id = dva.field
- LEFT JOIN '.DynamicForm::tableName().' dfo ON dfo.id = dfi.form
- WHERE dfo.slug = ? AND dva.scope = ? AND dva.uid = ?';
- $data = array($formSlug,$options['scope'],$options['uid']);
- $values = array();
- foreach (DynamicValue::staticQuery($query,$data,true) as $key => $value)
- $values[$value->foreign('slug')] = $value->value;
- return $values;
- }
- //Retourne un set de filtres de recherche avancée en fonction de la liste des
- //champs custom fournie
- public static function get_filters($fields){
- $filters = array();
- foreach($fields as $field){
- $filterOptions = '';
- $filterType = $field['type']->slug;
- $meta = isset($field['meta']) ? json_decode(base64_decode($field['meta']),true) : (object) array();
- //le field doit comprendre le meta show-filter pour afficher le filtre (case a cocher dans la construction du formulaire)
- if(!is_array($meta) || empty($meta['show-filter'])) continue;
- $filterOptions = ' data-filter-type="'.$filterType.'" ';
- if(is_array($meta)){
- foreach($meta as $key=>$value)
- $filterOptions .= 'data-'.$key.'=\''.(is_string($value) ? $value : str_replace("'","\'",json_encode($value))).'\' ';
- }
- //si le type de champ ne propose pas de filtre on l'ignore
- if(!property_exists($field['type'],'filter')) continue;
- $filters[$field['slug']] = '<option value="dynamicField_'.$field['id'].'.value"'.$filterOptions.'>'.$field['label'].'</option>';
- }
- return $filters;
- }
- }
- ?>
|