LSform : Added data entry form in create mode
[ldapsaisie.git] / public_html / includes / class / class.LSform.php
1 <?php
2 /*******************************************************************************
3  * Copyright (C) 2007 Easter-eggs
4  * http://ldapsaisie.labs.libre-entreprise.org
5  *
6  * Author: See AUTHORS file in top-level directory.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 ******************************************************************************/
22
23
24 /**
25  * Formulaire pour LdapSaisie
26  *
27  * Cette classe gère les formulaires
28  *
29  * @author Benjamin Renard <brenard@easter-eggs.com>
30  */
31
32 class LSform {
33   var $ldapObject;
34   var $idForm;
35   var $can_validate = true;
36   var $elements = array();
37   var $_rules = array();
38
39   var $_postData = array();
40  
41   var $_elementsErrors = array();
42   var $_isValidate = false;
43
44   var $_notUpdate = array();
45   
46   var $maxFileSize = NULL;
47
48   var $dataEntryForm = NULL;
49   var $dataEntryFormConfig = NULL;
50
51   var $warnings = array();
52
53   /**
54    * Constructeur
55    *
56    * Cette methode construit l'objet et définis la configuration.
57    *
58    * @author Benjamin Renard <brenard@easter-eggs.com>
59    *
60    * @param[in] $idForm [<b>required</b>] string L'identifiant du formulaire
61    * @param[in] $submit string La valeur du bouton submit
62    *
63    * @retval void
64    */ 
65   function LSform (&$ldapObject,$idForm,$submit=NULL){
66     $this -> idForm = $idForm;
67     if (!$submit) {
68       $this -> submit = _("Validate");
69     }
70     else {
71       $this -> submit = $submit;
72     }
73     $this -> ldapObject = $ldapObject;
74     LSsession :: loadLSclass('LSformElement');
75   }
76   
77   /**
78    * Affiche le formualaire
79    *
80    * @author Benjamin Renard <brenard@easter-eggs.com>
81    *
82    * @retval void
83    */ 
84   function display(){
85     if ($this -> idForm == 'view') {
86       self :: loadDependenciesDisplayView();
87     }
88     else {
89       LSsession :: addJSscript('LSformElement_field.js');
90       LSsession :: addJSscript('LSformElement.js');
91       LSsession :: addJSscript('LSform.js');
92       LSsession :: addCssFile('LSform.css');
93     }
94     
95     LSsession :: addHelpInfos(
96       'LSform',
97       array(
98         'addFieldBtn' => _('Add a field to add another values.'),
99         'removeFieldBtn' => _('Delete this field.')
100       )
101     );
102     
103     $GLOBALS['Smarty'] -> assign('LSform_action',$_SERVER['PHP_SELF']);
104     $LSform_header = "\t<input type='hidden' name='validate' value='LSform'/>\n
105     \t<input type='hidden' name='idForm' id='LSform_idform' value='".$this -> idForm."'/>\n
106     \t<input type='hidden' name='LSform_objecttype' id='LSform_objecttype'  value='".$this -> ldapObject -> getType()."'/>\n
107     \t<input type='hidden' name='LSform_objectdn' id='LSform_objectdn'  value='".$this -> ldapObject -> getValue('dn')."'/>\n";
108
109     
110     $LSform_object = array(
111       'type' => $this -> ldapObject -> getType(),
112       'dn' => $this -> ldapObject -> getValue('dn')
113     );
114     $GLOBALS['Smarty'] -> assign('LSform_object',$LSform_object);
115     
116     $layout_config=LSconfig :: get("LSobjects.".$LSform_object['type'].".LSform.layout");
117
118     if (!isset($this -> dataEntryFormConfig['disabledLayout']) || $this -> dataEntryFormConfig['disabledLayout']==false) {
119       if (is_array($layout_config)) {
120         $GLOBALS['Smarty'] -> assign('LSform_layout',$layout_config);
121         $GLOBALS['Smarty'] -> assign('LSform_layout_nofield_label',_('No field.'));
122       }
123     }
124     
125     $fields = array();
126     if (!isset($this -> dataEntryFormConfig['displayedElements']) && !is_array($this -> dataEntryFormConfig['displayedElements'])) {
127       foreach($this -> elements as $element) {
128         $field = array();
129         $field = $element -> getDisplay();
130         if (isset($this -> _elementsErrors[$element -> name])) {
131           $field['errors']= $this -> _elementsErrors[$element -> name];
132         }
133         $fields[$element -> name] = $field;
134       }
135     }
136     else {
137       foreach($this -> dataEntryFormConfig['displayedElements'] as $elementName) {
138         if (!isset($this -> elements[$elementName])) {
139           LSerror :: addErrorCode('LSform_09',$elementName);
140           continue;
141         }
142         $element = $this -> elements[$elementName];
143         $field = array();
144         $field = $element -> getDisplay();
145         if (isset($this -> _elementsErrors[$element -> name])) {
146           $field['errors']= $this -> _elementsErrors[$element -> name];
147         }
148         $fields[$element -> name] = $field;
149       }
150       // Add warning for other elements errors
151       foreach(array_keys($this -> elements) as $name) {
152         if (isset($this -> _elementsErrors[$name]) && !isset($fields[$name])) {
153           foreach ($this -> _elementsErrors[$name] as $error) {
154             $this -> addWarning("$name : $error");
155           }
156         }
157       }
158       $LSform_header .= "\t<input type='hidden' name='LSform_dataEntryForm' value='".$this -> dataEntryForm."'/>\n";
159     }
160     
161     if ($this -> maxFileSize) {
162       $LSform_header.="\t<input type='hidden' name='MAX_FILE_SIZE' value='".$this -> maxFileSize."'/>\n";
163     }
164     $GLOBALS['Smarty'] -> assign('LSform_header',$LSform_header);
165     
166     $GLOBALS['Smarty'] -> assign('LSform_fields',$fields);
167
168     $JSconfig = array (
169       'ajaxSubmit' => ((isset($this -> config['LSform']['ajaxSubmit']))?$this -> config['LSform']['ajaxSubmit']:1)
170     );
171
172     if (!empty($this -> warnings)) {
173       $JSconfig['warnings']=$this -> warnings;
174     }
175
176     LSsession :: addJSconfigParam('LSform_'.$this -> idForm,$JSconfig);
177
178     if($this -> can_validate) {
179       $GLOBALS['Smarty'] -> assign('LSform_submittxt',$this -> submit);
180     }
181   }
182   
183  /*
184   * Méthode chargeant les dépendances d'affichage d'une LSview
185   * 
186   * @retval void
187   */
188   public static function loadDependenciesDisplayView() {
189     LSsession :: addCssFile('LSform.css');
190     LSsession :: addJSscript('LSform.js');
191     LSsession :: addJSconfigParam('LSview_labels', array(
192       'delete_confirm_text'     => _("Do you really want to delete"),
193       'delete_confirm_title'    => _("Caution"),
194       'delete_confirm_validate'  => _("Delete")
195     ));
196     if (LSsession :: loadLSclass('LSconfirmBox')) {
197       LSconfirmBox :: loadDependenciesDisplay();
198     }
199     LSsession :: addJSscript('LSview.js');
200   }
201   
202   /**
203    * Affiche la vue
204    *
205    * @author Benjamin Renard <brenard@easter-eggs.com>
206    *
207    * @retval void
208    */ 
209   function displayView(){
210     self :: loadDependenciesDisplayView();
211     
212     $LSform_object = array(
213       'type' => $this -> ldapObject -> getType(),
214       'dn' => $this -> ldapObject -> getDn()
215     );
216     $GLOBALS['Smarty'] -> assign('LSform_object',$LSform_object);
217     $fields = array();
218     foreach($this -> elements as $element) {
219       $field = $element -> getDisplay();
220       $fields[$element -> name] = $field;
221     }
222     $GLOBALS['Smarty'] -> assign('LSform_fields',$fields);
223     
224     $layout_config=LSconfig :: get("LSobjects.".$LSform_object['type'].".LSform.layout");
225     if (is_array($layout_config)) {
226       $GLOBALS['Smarty'] -> assign('LSform_layout',$layout_config);
227       $GLOBALS['Smarty'] -> assign('LSform_layout_nofield_label',_('No field.'));
228     }
229   }  
230   
231   /**
232    * Défini l'erreur sur un champ
233    *
234    * @author Benjamin Renard <brenard@easter-eggs.com>
235    *
236    * @param[in] $attr [<b>required</b>] string Le nom du champ
237    * @param[in] $msg Le format du message d'erreur à afficher (pouvant comporter
238    *                 des valeurs %{[n'importe quoi]} qui seront remplacé par le label
239    *                 du champs concerné.
240    *
241    * @retval void
242    */ 
243   function setElementError($attr,$msg=NULL) {
244     if($msg!='') {
245       $msg_error=getFData($msg,$attr->getLabel());
246     }
247     else {
248       $msg_error=getFData(_("%{label} attribute data is not valid."),$attr->getLabel());
249     }
250     $this -> _elementsErrors[$attr->name][]=$msg_error;
251   }
252   
253   /**
254    * Savoir si des erreurs son définie pour un élement du formulaire
255    *
256    * @author Benjamin Renard <brenard@easter-eggs.com>
257    *
258    * @param[in] $element [<b>required</b>] string Le nom de l'élement
259    * 
260    * @retval boolean
261    */ 
262   function definedError($element=NULL) {
263     if ($element) {
264       return isset($this -> _elementsErrors[$element]);
265     }
266     else {
267       return !empty($this -> _elementsErrors);
268     }
269   }
270   
271   /**
272    * Retourne le tableau des erreurs
273    * 
274    * @retval Array array(element => array(errors))
275    */
276   function getErrors() {
277     return $this -> _elementsErrors;
278   }
279   
280   /**
281    * Verifie si le formulaire a été validé et que les données sont valides.
282    *
283    * @author Benjamin Renard <brenard@easter-eggs.com>
284    *
285    * @retval boolean true si le formulaire a été validé et que les données ont été validées, false sinon
286    */ 
287   function validate(){
288     if(!$this -> can_validate)
289       return;
290     if ($this -> isSubmit()) {
291       if (!$this -> getPostData()) {
292         LSerror :: addErrorCode('LSform_01');
293         return;
294       }
295       $this -> setValuesFromPostData();
296       //Validation des données ici !!! ///
297       if (!$this -> checkData()) {
298         return;
299       }
300       LSdebug("Data are checked up");
301       $this -> _isValidate = true;
302       return true;
303     }
304     return false;
305   }
306
307   /**
308    * Vérifier les données du formulaire à partir des régles définis sur les champs
309    *
310    * @author Benjamin Renard <brenard@easter-eggs.com>
311    *
312    * @retval boolean true si toutes la saisie est OK, false sinon
313    */
314   function checkData() {
315     $retval=true;
316     foreach ($this -> _postData as $element => $values) {
317       if(!is_array($values)) {
318         $values=array($values);
319       }
320       if ($this -> elements[$element] -> isRequired()) {
321         if (!$this -> checkRequired($values)) {
322           $this -> setElementError($this -> elements[$element],_("Mandatory field"));
323           $retval=false;
324         }
325       }
326
327       foreach($values as $value) {
328         if (empty($value)) {
329           continue;
330         }
331         if (!is_array($this -> _rules[$element]))
332           continue;
333         LSsession :: loadLSclass('LSformRule');
334         foreach($this -> _rules[$element] as $rule) {
335           $ruleType="LSformRule_".$rule['name'];
336           LSsession :: loadLSclass($ruleType);
337           if (! call_user_func(array( $ruleType,'validate') , $value, $rule['options'], $this -> getElement($element))) {
338             $retval=false;
339             $this -> setElementError($this -> elements[$element],$rule['options']['msg']);
340           }
341         }
342       }
343     }
344     return $retval;
345   }
346
347   /**
348    * Vérifie si au moins une valeur est présente dans le tableau
349    *
350    * @author Benjamin Renard <brenard@easter-eggs.com>
351    *
352    * @param[in] $data array tableau de valeurs
353    *
354    * @retval boolean true si au moins une valeur est présente, false sinon
355    */
356   function checkRequired($data) {
357     foreach($data as $val) {
358       if (!empty($val)||(is_string($val)&&($val=="0")))
359         return true;
360     }
361     return;
362   }
363
364   /**
365    * Verifie si la saisie du formulaire est présente en POST
366    *
367    * @author Benjamin Renard <brenard@easter-eggs.com>
368    *
369    * @retval boolean true si la saisie du formulaire est présente en POST, false sinon
370    */
371   function isSubmit() {
372     if( (isset($_POST['validate']) && ($_POST['validate']=='LSform')) && (isset($_POST['idForm']) && ($_POST['idForm'] == $this -> idForm)) )
373       return true;
374     return;
375   }
376
377   /**
378    * Défini arbitrairement des données en POST
379    * 
380    * @author Benjamin Renard <brenard@easter-eggs.com>
381    * 
382    * @param[in] $data array('attr' => array(values)) Tableau des données du formulaire
383    * @param[in] $consideredAsSubmit Définie si on force le formualaire comme envoyer
384    * 
385    * @retval boolean true si les données ont été définies, false sinon
386    */
387   function setPostData($data,$consideredAsSubmit=false) {
388     if (is_array($data)) {
389       foreach($data as $key => $values) {
390         if (!is_array($values)) {
391           $values = array($values);
392         }
393         $_POST[$key] = $values;
394       }
395       
396       if ($consideredAsSubmit) {
397         $_POST['validate']='LSform';
398         $_POST['idForm']=$this -> idForm;
399       }
400       
401       return true;
402     }
403     return;
404   }
405
406   /**
407    * Récupère les valeurs postées dans le formulaire
408    *
409    * @author Benjamin Renard <brenard@easter-eggs.com>
410    *
411    * @retval boolean true si les valeurs ont bien été récupérées, false sinon.
412    */
413   function getPostData() {
414     if (is_null($this -> dataEntryForm)) {
415       foreach($this -> elements as $element_name => $element) {
416         if( !($element -> getPostData($this -> _postData)) ) {
417           LSerror :: addErrorCode('LSform_02',$element_name);
418           return;
419         }
420       }
421     }
422     else {
423       $elementsList = $this -> dataEntryFormConfig['displayedElements'];
424       if (isset($this -> dataEntryFormConfig['defaultValues']) && is_array($this -> dataEntryFormConfig['defaultValues'])) {
425         $this -> setPostData($this -> dataEntryFormConfig['defaultValues']);
426         $elementsList = array_merge($elementsList,array_keys($this -> dataEntryFormConfig['defaultValues']));
427       }
428
429       foreach($elementsList as $elementName) {
430         if (!isset($this -> elements[$elementName])) {
431           LSerror :: addErrorCode('LSform_09',$elementName);
432           continue;
433         }
434         $element = $this -> elements[$elementName];
435         if( !($element -> getPostData($this -> _postData)) ) {
436           LSerror :: addErrorCode('LSform_02',$element_name);
437           return;
438         }
439       }
440     }
441     return true;
442   }
443
444   /**
445    * Ajoute un élément au formulaire
446    * 
447    * Ajoute un élément au formulaire et définis les informations le concernant.
448    *
449    * @param[in] $type string Le type de l'élément
450    * @param[in] $name string Le nom de l'élément
451    * @param[in] $label string Le label de l'élément
452    * @param[in] $param mixed Paramètres supplémentaires
453    *
454    * @retval LSformElement
455    */
456   function addElement($type,$name,$label,$params=array(),&$attr_html) {
457     $elementType='LSformElement_'.$type;
458     LSsession :: loadLSclass($elementType);
459     if (!class_exists($elementType)) {
460       LSerror :: addErrorCode('LSform_05',array('type' => $type));  
461       return;
462     }
463     $element=$this -> elements[$name] = new $elementType($this,$name,$label,$params,$attr_html);
464     if ($element) {
465       return $element;
466     }
467     else {
468       unset ($this -> elements[$name]);
469       LSerror :: addErrorCode('LSform_06',array('element' => $name));
470       return;
471     }
472   }
473
474   /**
475    * Ajoute une règle sur un élément du formulaire
476    *
477    * @author Benjamin Renard <brenard@easter-eggs.com>
478    *
479    * @param[in] $element string Le nom de l'élément conserné
480    * @param[in] $rule string Le nom de la règle à ajouter
481    * @param[in] $options array Options (facultative)
482    *
483    * @retval boolean
484    */
485   function addRule($element, $rule, $options=array()) {
486     if ( isset($this ->elements[$element]) ) {
487       if ($this -> isRuleRegistered($rule)) {
488         $this -> _rules[$element][]=array(
489                   'name' => $rule,
490                   'options' => $options
491                   );
492         return true;
493       }
494       else {
495         LSerror :: addErrorCode('LSattribute_03',array('attr' => $element,'rule'=>$rule));      
496         return;
497       }
498     }
499     else {  
500       LSerror :: addErrorCode('LSform_04',array('element' => $element));
501       return;
502     }
503   }
504
505
506
507
508   /**
509    * Définis comme requis un élément
510    *
511    * @author Benjamin Renard <brenard@easter-eggs.com>
512    *
513    * @param[in] $element string Le nom de l'élément conserné
514    *
515    * @retval boolean
516    */
517   function setRequired($element) {
518     if (isset( $this -> elements[$element] ) )
519       return $this -> elements[$element] -> setRequired();
520     else
521       return;
522   }
523
524   /**
525    * Détermine la valider de la règle
526    *
527    * Devra déterminer si la règle passez en paramètre est correcte
528    *
529    * @author Benjamin Renard <brenard@easter-eggs.com>
530    *
531    * @param[in] $element string Le nom de l'élément conserné
532    */
533   function isRuleRegistered($rule) {
534     LSsession :: loadLSclass('LSformRule');
535     LSsession :: loadLSclass('LSformRule_'.$rule);
536     return class_exists('LSformRule_'.$rule);
537   }
538
539   /**
540    * Retourne les valeurs validés du formulaire
541    *
542    * @retval mixed Les valeurs validés du formulaire, ou false si elles ne le sont pas
543    */
544   function exportValues() {
545     if ($this -> _isValidate) {
546       $retval=array();
547       foreach($this -> _postData as $element => $values) {
548         $retval[$element] = $this -> elements[$element] -> exportValues();
549       }
550       return $retval;
551     }
552     else {
553       return;
554     }
555   }
556
557   /**
558    * Retourn un élement du formulaire
559    *
560    * @param[in] string $element Nom de l'élement voulu
561    *
562    * @retval LSformElement L'élement du formulaire voulu
563    */
564   function getElement($element) {
565     return $this -> elements[$element];
566   }
567
568   /**
569    * Défini les valeurs des élements à partir des valeurs postées
570    *
571    * @retval boolean True si les valeurs ont été définies, false sinon.
572    */
573   function setValuesFromPostData() {
574     if (empty($this -> _postData)) {
575       return;
576     }
577     foreach($this -> _postData as $element => $values) {
578       $this -> elements[$element] -> setValueFromPostData($values);
579     }
580     return true;
581   }
582
583   /**
584    * Retourne le code HTML d'un champ vide.
585    * 
586    * @param[in] string Le nom du champ du formulaire
587    *
588    * @retval string Le code HTML du champ vide.
589    */
590   function getEmptyField($element) {
591     $element = $this -> getElement($element);
592     if ($element) {      
593       return $element -> getEmptyField();     
594     }
595     else {
596       return;
597     }
598   }
599   
600   /**
601    * Défini la taille maximal pour les fichiers envoyés par le formualaire
602    * 
603    * @param[in] $size La taille maximal en octets
604    * 
605    * @retval  void
606    **/
607   function setMaxFileSize($size) {
608     $this -> maxFileSize = $size;
609   }
610
611   /**
612    * Applique un masque de saisie au formulaire
613    *
614    * @param[in] $dataEntryForm string Le nom du masque de saisie
615    *
616    * @retval boolean True si le masque de saisie a été appliqué, False sinon
617    **/
618    function applyDataEntryForm($dataEntryForm) {
619      $dataEntryForm=(string)$dataEntryForm;
620      $objType = $this -> ldapObject -> getType();
621      $config=LSconfig :: get("LSobjects.".$objType.".LSform.dataEntryForm.".$dataEntryForm);
622      if (is_array($config)) {
623        if (!is_array($config['displayedElements'])) {
624          LSerror :: addErrorCode('LSform_08',$dataEntryForm);
625        }
626        $this -> dataEntryForm       = $dataEntryForm;
627        $this -> dataEntryFormConfig = $config;
628        return true;
629      }
630      LSerror :: addErrorCode('LSform_07',$dataEntryForm);
631      return;
632    }
633
634    /**
635     * Liste les dataEntryForm disponible pour un type d'LSldapObject
636     *
637     * @param[in] $type string Le type d'LSldapObject
638     *
639     * @retval array Tableau contenant la liste de dataEntryForm disponible pour ce type d'LSldapObject (nom => label)
640     **/
641     public static function listAvailableDataEntryForm($type) {
642       $retval=array();
643       if (LSsession ::loadLSobject($type)) {
644         $config=LSconfig :: get("LSobjects.".$type.".LSform.dataEntryForm");
645         if (is_array($config)) {
646           foreach($config as $name => $conf) {
647             if (isset($conf['label'])) {
648               $retval[$name]=__($conf['label']);
649             }
650             else {
651               $retval[$name]=__($name);
652             }
653           }
654         }
655       }
656       return $retval;
657     }
658
659    /**
660     * Ajoute un avertissement au sujet du formulaire
661     *
662     * @param[in] $txt string Le texte de l'avertissement
663     *
664     * @retval void
665     **/
666    function addWarning($txt) {
667      $this -> warnings[]=$txt;
668    }
669
670   /**
671    * Méthode Ajax permetant de retourner le code HTML d'un élément du formulaire vide
672    *
673    * @param[in] &$data Variable de retour
674    *
675    * @retval void
676    **/
677   public static function ajax_onAddFieldBtnClick(&$data) {
678     if ((isset($_REQUEST['attribute'])) && (isset($_REQUEST['objecttype'])) && (isset($_REQUEST['objectdn'])) && (isset($_REQUEST['idform'])) && (isset($_REQUEST['fieldId'])) ) {
679       if (LSsession ::loadLSobject($_REQUEST['objecttype'])) {
680         $object = new $_REQUEST['objecttype']();
681         $object -> loadData($_REQUEST['objectdn']);
682         $form = $object -> getForm($_REQUEST['idform']);
683         $emptyField=$form -> getEmptyField($_REQUEST['attribute']);
684         if ( $emptyField ) {
685           $data = array(
686             'html' => $form -> getEmptyField($_REQUEST['attribute']),
687             'fieldId' => $_REQUEST['fieldId'],
688             'fieldtype' => get_class($form -> getElement($_REQUEST['attribute']))
689           );
690         }
691       }
692     }
693   }
694 }
695
696 /**
697  * Error Codes
698  */
699 LSerror :: defineError('LSform_01',
700 _("LSform : Error during the recovery of the values of the form.")
701 );
702 LSerror :: defineError('LSform_02',
703 _("LSform : Error durring the recovery of the value of the field '%{element}'.")
704 );
705 // No longer used
706 /*LSerror :: defineError(203,
707 _("LSform : Data of the field %{element} are not validate.")
708 );*/
709 LSerror :: defineError('LSform_04',
710 _("LSform : The field %{element} doesn't exist.")
711 );
712 LSerror :: defineError('LSform_05',
713 _("LSfom : Field type unknow (%{type}).")
714 );
715 LSerror :: defineError('LSform_06',
716 _("LSform : Error during the creation of the element '%{element}'.")
717 );
718 LSerror :: defineError('LSform_07',
719 _("LSform : The data entry form %{name} doesn't exist.")
720 );
721 LSerror :: defineError('LSform_08',
722 _("LSform : The data entry form %{name} is not correctly configured.")
723 );
724 LSerror :: defineError('LSform_09',
725 _("LSform : The element %{name}, listed as displayed in data entry form configuration, doesn't exist.")
726 );
727 ?>