From 9815fb147faf7bd16d545f117468e3e5a5b36ef0 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Wed, 3 May 2017 01:12:35 +0200 Subject: [PATCH 1/3] LSattr_html :: jsonCompositeAttribute : first version --- .../LSformElement_jsonCompositeAttribute.css | 34 +++ ...ass.LSattr_html_jsonCompositeAttribute.php | 32 +++ ...s.LSformElement_jsonCompositeAttribute.php | 254 ++++++++++++++++++ .../LSformElement_jsonCompositeAttribute.tpl | 7 + ...rmElement_jsonCompositeAttribute_field.tpl | 36 +++ 5 files changed, 363 insertions(+) create mode 100644 public_html/css/default/LSformElement_jsonCompositeAttribute.css create mode 100644 public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php create mode 100644 public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php create mode 100644 public_html/templates/default/LSformElement_jsonCompositeAttribute.tpl create mode 100644 public_html/templates/default/LSformElement_jsonCompositeAttribute_field.tpl diff --git a/public_html/css/default/LSformElement_jsonCompositeAttribute.css b/public_html/css/default/LSformElement_jsonCompositeAttribute.css new file mode 100644 index 00000000..28b641f3 --- /dev/null +++ b/public_html/css/default/LSformElement_jsonCompositeAttribute.css @@ -0,0 +1,34 @@ +ul.LSformElement_jsonCompositeAttribute li { + border: 1px dotted #CCC; + padding: 2px; +} + +ul.LSformElement_jsonCompositeAttribute li.noValue { + border: none; +} + +ul.LSformElement_jsonCompositeAttribute p { + margin: 0; +} + +ul.LSformElement_jsonCompositeAttribute p label { + font-weight: bold; +} + +div.jsonCompositeAttribute_possibleValues ul { + list-style-type: none; + padding: 0; + margin: 0; + border: 1px solid #CCC; + border-collapse: collapse; +} + +div.jsonCompositeAttribute_possibleValues li { + border-bottom: 1px solid #CCC; + margin-bottom: 2px; +} + +div.jsonCompositeAttribute_possibleValues li:hover { + background-color: #CCC; + cursor: pointer; +} diff --git a/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php b/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php new file mode 100644 index 00000000..ce8bddcf --- /dev/null +++ b/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php @@ -0,0 +1,32 @@ + + */ +class LSattr_html_jsonCompositeAttribute extends LSattr_html { + + var $LSformElement_type = 'jsonCompositeAttribute'; + +} diff --git a/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php b/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php new file mode 100644 index 00000000..ee0f47d0 --- /dev/null +++ b/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php @@ -0,0 +1,254 @@ + + */ + +class LSformElement_jsonCompositeAttribute extends LSformElement { + + var $template = 'LSformElement_jsonCompositeAttribute.tpl'; + var $fieldTemplate = 'LSformElement_jsonCompositeAttribute_field.tpl'; + + function LSformElement_jsonCompositeAttribute (&$form, $name, $label, $params,&$attr_html){ + parent :: LSformElement($form, $name, $label, $params,$attr_html); + if (is_array($this -> params['html_options']['components'])) { + $this -> components = $this -> params['html_options']['components']; + } + } + + /* + * Composants des valeurs composites : + * + * Format : + * array ( + * '[clé composant1]' => array ( + * 'label' => '[label composant]', + * 'type' => '[type de composant]', + * 'required' => '[booléen obligatoire]' + * ), + * '[clé composant 2]' => array ( + * 'label' => 'label2', + * 'type' => 'select_list', + * 'options' => array([config as LSattr_html_select_list html_options]), + * ), + * [...] + * ) + * Types : + * - 'select_list' => Composant alimenté à partir d'une liste de valeur configurable + * de la même manière qu'un LSattr_html :: select_list. + * - 'text' => saisie manuelle + * + */ + var $components = array(); + + /** + * Retourne les infos d'affichage de l'élément + * + * Cette méthode retourne les informations d'affichage de l'élement + * + * @retval array + */ + function getDisplay(){ + $return = $this -> getLabelInfos(); + + $parseValues=array(); + $invalidValues=array(); + foreach($this -> values as $val) { + $decodedValue=json_decode($val, true); + if (is_array($decodedValue)) { + $parseValue=array('value' => $val); + foreach($decodedValue as $c => $cvalue) { + $parseValue[$c]=$this -> translateComponentValue($c,$cvalue); + } + $parseValues[]=$parseValue; + } + else { + $invalidValues[]=$val; + } + } + + $components = $this -> components; + foreach($components as $c => $cconf) { + if ($cconf['type']=='select_list') { + $components[$c]['possible_values']=$this -> getSelectListComponentPossibleValues($c); + } + } + + $return['html'] = $this -> fetchTemplate(NULL, + array( + 'parseValues' => $parseValues, + 'components' => $components + ) + ); + LSsession :: addCssFile('LSformElement_jsonCompositeAttribute.css'); + return $return; + } + + + /** + * Retourne le code HTML d'un champ vide + * + * @retval string Code HTML d'un champ vide. + */ + function getEmptyField() { + return $this -> fetchTemplate($this -> fieldTemplate,array('components' => $this -> components)); + } + + /** + * Traduit la valeur d'un composant + * + * Retourne un array contenant : + * - label : l'étiquette de la valeur ou 'no' sinon + * - value : la valeur brute + * - translated : la valeur traduite ou la valeur elle même + * + * @param[in] $c string Le nom du composant + * @param[in] $val string La valeur + * + * @retval array + **/ + function translateComponentValue($c,$val) { + $retval = array ( + 'translated' => $val, + 'value' => $val, + ); + if (isset($this -> components[$c])) { + if ($this -> components[$c]['type']=='select_list') { + $retval['translated'] = $this -> getSelectListComponentValueLabel($c,$val); + } + //elseif type == 'text' => aucune transformation + } + return $retval; + } + + protected $_cache_getSelectListComponentPossibleValues=array(); + protected function getSelectListComponentPossibleValues($c) { + if (!isset($this -> _cache_getSelectListComponentPossibleValues[$c])) { + if (!LSsession :: loadLSclass('LSattr_html_select_list')) return; + $this -> _cache_getSelectListComponentPossibleValues[$c]=LSattr_html_select_list :: getPossibleValues($this -> components[$c]['options'], $this -> name, $this->attr_html->attribute->ldapObject); + } + return $this -> _cache_getSelectListComponentPossibleValues[$c]; + } + + protected function getSelectListComponentValueLabel($c,$value) { + if ($this -> getSelectListComponentPossibleValues($c)) { + foreach ($this -> _cache_getSelectListComponentPossibleValues[$c] as $v => $label) { + if (is_array($label)) { + if (!isset($label['possible_values'])) continue; + foreach ($label['possible_values'] as $vk => $vl) + if ($vk == $$value) return $vl; + } + if ($v == $value) return $label; + } + } + return; + } + + /** + * Recupère la valeur de l'élement passée en POST + * + * Cette méthode vérifie la présence en POST de la valeur de l'élément et la récupère + * pour la mettre dans le tableau passer en paramètre avec en clef le nom de l'élément + * + * @param[] array Pointeur sur le tableau qui recupèrera la valeur. + * + * @retval boolean true si la valeur est présente en POST, false sinon + */ + function getPostData(&$return) { + if($this -> isFreeze()) { + return true; + } + + $count=0; + $end=false; + $return[$this -> name]=array(); + while ($end==false) { + $value=array(); + $parseValue=array(); + $errors=array(); + $unemptyComponents=array(); + foreach ($this -> components as $c => $cconf) { + if (isset($_POST[$this -> name.'__'.$c][$count])) { + $parseValue[$c]=$_POST[$this -> name.'__'.$c][$count]; + if ($cconf['required'] && empty($parseValue[$c])) { + $errors[]=getFData(__('Component %{c} must be defined'),__($cconf['label'])); + continue; + } + if (empty($parseValue[$c])) { + continue; + } + $unemptyComponents[]=$c; + if ($cconf['type']=='select_list') { + if (!$this -> getSelectListComponentValueLabel($c, $parseValue[$c])) { + $errors[]=getFData(__('Invalid value for component %{c}.'),__($cconf['label'])); + } + } + if (is_array($cconf['check_data'])) { + foreach($cconf['check_data'] as $ruleType => $rconf) { + $className='LSformRule_'.$ruleType; + if (LSsession::loadLSclass($className)) { + $r=new $className(); + if (!$r -> validate($parseValue[$c],$rconf,$this)) { + if (isset($rconf['msg'])) { + $errors[]=getFData(__($rconf['msg']),__($cconf['label'])); + } + else { + $errors[]=getFData(__('Invalid value for component %{c}.'),__($cconf['label'])); + } + } + } + else { + $errors[]=getFData(__("Can't validate value of component %{c}."),__($cconf['label'])); + } + } + } + $value[$c]=$parseValue[$c]; + } + else { + // end of value break + $end=true; + break; + } + + } + if (!$end) { + if (!empty($unemptyComponents)) { + foreach($errors as $e) { + $this -> form -> setElementError($this -> attr_html,$e); + } + $return[$this -> name][]=json_encode($value); + } + $count++; + } + } + return true; + } + +} diff --git a/public_html/templates/default/LSformElement_jsonCompositeAttribute.tpl b/public_html/templates/default/LSformElement_jsonCompositeAttribute.tpl new file mode 100644 index 00000000..7c1cccd9 --- /dev/null +++ b/public_html/templates/default/LSformElement_jsonCompositeAttribute.tpl @@ -0,0 +1,7 @@ + diff --git a/public_html/templates/default/LSformElement_jsonCompositeAttribute_field.tpl b/public_html/templates/default/LSformElement_jsonCompositeAttribute_field.tpl new file mode 100644 index 00000000..31030e13 --- /dev/null +++ b/public_html/templates/default/LSformElement_jsonCompositeAttribute_field.tpl @@ -0,0 +1,36 @@ +{if $freeze} + {if isset($parseValue)} + {foreach $components as $c => $cconf} + {if !isset($parseValue[$c])}{continue}{/if} +

+ + {$parseValue[$c].translated} +

+ {/foreach} + {else} + {$noValueTxt} + {/if} +{else} + {foreach $components as $c => $cconf} +

+ + {if $cconf.type=='select_list'} + + {else} + + {/if} +

+ {/foreach} +{/if} From 8fa9221a6eb24732ced0eac48b47ceb7a872ff53 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Thu, 4 May 2017 17:27:52 +0200 Subject: [PATCH 2/3] Improve and translate code comments --- ...ass.LSattr_html_jsonCompositeAttribute.php | 2 +- ...s.LSformElement_jsonCompositeAttribute.php | 106 ++++++++++-------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php b/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php index ce8bddcf..82e26ebb 100644 --- a/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php +++ b/public_html/includes/class/class.LSattr_html_jsonCompositeAttribute.php @@ -28,5 +28,5 @@ class LSattr_html_jsonCompositeAttribute extends LSattr_html { var $LSformElement_type = 'jsonCompositeAttribute'; - + } diff --git a/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php b/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php index ee0f47d0..ee061617 100644 --- a/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php +++ b/public_html/includes/class/class.LSformElement_jsonCompositeAttribute.php @@ -23,10 +23,9 @@ LSsession :: loadLSclass('LSformElement'); /** - * Element jsonCompositeAttribute d'un formulaire pour LdapSaisie + * Element jsonCompositeAttribute for LSform * - * Cette classe permet de gérer les attributs composite encodé en JSON. - * Elle étant la classe basic LSformElement. + * This classe permit to handle compostie attributes encoded with JSON. * * @author Benjamin Renard */ @@ -42,18 +41,19 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { $this -> components = $this -> params['html_options']['components']; } } - + /* - * Composants des valeurs composites : - * + * Value components : + * * Format : * array ( - * '[clé composant1]' => array ( - * 'label' => '[label composant]', - * 'type' => '[type de composant]', - * 'required' => '[booléen obligatoire]' + * '[component1_key]' => array ( + * 'label' => '[component label]', + * 'type' => '[component type]', + * 'required' => '[booléen]', + * 'check_data' => array([config LSform_rule]) * ), - * '[clé composant 2]' => array ( + * '[component2_key]' => array ( * 'label' => 'label2', * 'type' => 'select_list', * 'options' => array([config as LSattr_html_select_list html_options]), @@ -61,16 +61,16 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { * [...] * ) * Types : - * - 'select_list' => Composant alimenté à partir d'une liste de valeur configurable - * de la même manière qu'un LSattr_html :: select_list. - * - 'text' => saisie manuelle - * + * - 'select_list' => Component feed by a list of valeur configured like an + * atribute LSattr_html :: select_list. + * - 'text' => manual entry + * */ var $components = array(); - + /** * Retourne les infos d'affichage de l'élément - * + * * Cette méthode retourne les informations d'affichage de l'élement * * @retval array @@ -110,44 +110,50 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { LSsession :: addCssFile('LSformElement_jsonCompositeAttribute.css'); return $return; } - - + + /** - * Retourne le code HTML d'un champ vide + * Return HTML code of an empty field * - * @retval string Code HTML d'un champ vide. + * @retval string HTML code of an empty field. */ function getEmptyField() { return $this -> fetchTemplate($this -> fieldTemplate,array('components' => $this -> components)); } - + /** - * Traduit la valeur d'un composant - * - * Retourne un array contenant : - * - label : l'étiquette de la valeur ou 'no' sinon - * - value : la valeur brute - * - translated : la valeur traduite ou la valeur elle même - * - * @param[in] $c string Le nom du composant - * @param[in] $val string La valeur - * + * Translate componant value + * + * Return an array containing : + * - value : untranslated value + * - translated : translated value + * + * @param[in] $c string The component name + * @param[in] $value string The value + * * @retval array **/ - function translateComponentValue($c,$val) { + function translateComponentValue($c,$value) { $retval = array ( - 'translated' => $val, - 'value' => $val, + 'translated' => $value, + 'value' => $value, ); if (isset($this -> components[$c])) { if ($this -> components[$c]['type']=='select_list') { - $retval['translated'] = $this -> getSelectListComponentValueLabel($c,$val); + $retval['translated'] = $this -> getSelectListComponentValueLabel($c,$value); } - //elseif type == 'text' => aucune transformation + //elseif type == 'text' => no transformation } return $retval; } + /** + * Retreive possible values of an select_list component + * + * @param[in] $c string The component name + * + * @retval array + **/ protected $_cache_getSelectListComponentPossibleValues=array(); protected function getSelectListComponentPossibleValues($c) { if (!isset($this -> _cache_getSelectListComponentPossibleValues[$c])) { @@ -157,6 +163,14 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { return $this -> _cache_getSelectListComponentPossibleValues[$c]; } + /** + * Retreive value's label of an select_list component + * + * @param[in] $c string The component name + * @param[in] $value string The value + * + * @retval array + **/ protected function getSelectListComponentValueLabel($c,$value) { if ($this -> getSelectListComponentPossibleValues($c)) { foreach ($this -> _cache_getSelectListComponentPossibleValues[$c] as $v => $label) { @@ -170,22 +184,22 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { } return; } - + /** - * Recupère la valeur de l'élement passée en POST + * Retreive LSformElement value from POST data * - * Cette méthode vérifie la présence en POST de la valeur de l'élément et la récupère - * pour la mettre dans le tableau passer en paramètre avec en clef le nom de l'élément + * This method check present of this element's value in POST data and retreive + * it to feed the array passed in paramater. * - * @param[] array Pointeur sur le tableau qui recupèrera la valeur. + * @param[] array Reference of the array for retreived values * - * @retval boolean true si la valeur est présente en POST, false sinon + * @retval boolean true if value is in POST data, false instead */ function getPostData(&$return) { if($this -> isFreeze()) { return true; } - + $count=0; $end=false; $return[$this -> name]=array(); @@ -236,7 +250,7 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { $end=true; break; } - + } if (!$end) { if (!empty($unemptyComponents)) { @@ -250,5 +264,5 @@ class LSformElement_jsonCompositeAttribute extends LSformElement { } return true; } - + } From d8e0d40deee97fb5051615e545281684cbf67668 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Thu, 4 May 2017 17:28:13 +0200 Subject: [PATCH 3/3] Add documentation --- doc/conf/LSattribute/LSattr_html.docbook | 1 + .../LSattr_html/LSattr_html.entities.xml | 3 + ...LSattr_html_jsonCompositeAttribute.docbook | 96 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 doc/conf/LSattribute/LSattr_html/LSattr_html_jsonCompositeAttribute.docbook diff --git a/doc/conf/LSattribute/LSattr_html.docbook b/doc/conf/LSattribute/LSattr_html.docbook index 2c2bdd1b..59fdd074 100644 --- a/doc/conf/LSattribute/LSattr_html.docbook +++ b/doc/conf/LSattribute/LSattr_html.docbook @@ -6,6 +6,7 @@ &conf-LSattr_html_boolean; &conf-LSattr_html_date; &conf-LSattr_html_image; + &conf-LSattr_html_jsonCompositeAttribute; &conf-LSattr_html_mail; &conf-LSattr_html_maildir; &conf-LSattr_html_mailQuota; diff --git a/doc/conf/LSattribute/LSattr_html/LSattr_html.entities.xml b/doc/conf/LSattribute/LSattr_html/LSattr_html.entities.xml index 3be2d267..3e342b14 100644 --- a/doc/conf/LSattribute/LSattr_html/LSattr_html.entities.xml +++ b/doc/conf/LSattribute/LSattr_html/LSattr_html.entities.xml @@ -2,6 +2,7 @@ + @@ -17,3 +18,5 @@ + +LSattr_html_select_list"> diff --git a/doc/conf/LSattribute/LSattr_html/LSattr_html_jsonCompositeAttribute.docbook b/doc/conf/LSattribute/LSattr_html/LSattr_html_jsonCompositeAttribute.docbook new file mode 100644 index 00000000..09fe1097 --- /dev/null +++ b/doc/conf/LSattribute/LSattr_html/LSattr_html_jsonCompositeAttribute.docbook @@ -0,0 +1,96 @@ + + LSattr_html_jsonCompositeAttribute + Ce type est utilisé pour la gestion des attributs dont les valeurs sont + des dictionnaires de valeurs encodées aux formats JSON. + + +Exemple de valeur gérée + + + + Le principe est que ces dictionnaires contienent plusieurs composants référencés + par leur clé et stockant une valeur dont le type peut être un texte libre ou + bien être issue d'une liste déroulante configurable selon le même principe que + le type d'attribut &LSattr_html_select_list;. + + +Structure... + array ( + 'components' => array ( + '[clé composant 1]' => array ( + 'label' => '[Label du composant]', + 'type' => '[Type de la valeur stocké]', + 'required' => [Booléen], + 'check_data' => => array ( + // Régle de vérification syntaxique des données saisies + ), + ), + '[clé composant 2]' => array ( + 'label' => '[Label du composant 2]', + 'type' => 'select_list', + 'required' => [Booléen], + 'options' => array ( + [Configuration équivalente à un attribut LSattr_html_select_list] + ) + ), + [...] + ), +),]]> +... + + + +Paramètres de configuration + + + components + + Tableau associatif obligatoire contenant en valeur clé, l'identifiant des + composants, correspondant à la clé dans le dictionnaire JSON, + et en valeurs associés, la configuration du composant. + + + + label + + Le label du composant. + + + + + type + + Le type de valeur du composant. Les types possibles sont + text ou select_list pour respectivement + soit une valeur saisie librement, soit une valeur sélectionnée parmis une liste + déroulante. + + + + + options + + Dans le cadre d'un composant de type select_list, cela + correspond à la configuration de la liste déroulante. Cette configuration utilise la + même syntaxe de configuration que celle du type d'attribut &LSattr_html_select_list; + et son paramètre html_options. + + + + + check_data + + Tableau associatif contenant les règles de vérification syntaxique + des données du composant. Ces règles sont configurables de la même manière + que les celles des valeurs attributs. + Voir la section concernée. + + + + + + + + + +