'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 slug du formulaire ciblé * @param options des filtres de sélection des champs * @return 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 .= '
'; foreach ($columns as $u => $fields) { $stream .= '
'; 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 .= '
'; } $stream .= '
'; } return $stream; } /** * Retourne un tableau de champs disponibles pour ce slug et cette firm * @param slug du formulaire ciblé * @param options des filtres de sélection des champs * @return 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 slug du formulaire ciblé * @param options des filtres de sélection des champs * @return 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 tableau d'options/ filtres de sélection * @return 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 tableau d'options/ filtres de sélection * @return 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 tableau brut d'objets champs dynamiques * @param tableau des fieldtypes disponibles * @param tableau des options de sélection et de format * @return 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 tableau brut de champs dynamiques (sous forme d'arrays) * @param tableau des options de sélection et de format * @return 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 tableau brut des valeurs des champs dynamiques * @return 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 tableau des champs dynamiques potentiellement affichables * @param requête originelle de sélection en base à modifier * @param alias de la table mère présente dans le FROM de la requête originelle de sélection * @return 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' => ''.$field['label'].'', 'body' => '{{{'.$field['slug'].'}}}', ); } 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']] = ''; } return $filters; } } ?>