- config.inc.php : Ajout d'une constante LS_CSS_DIR
[ldapsaisie.git] / trunk / includes / class / class.LSldapObject.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 $GLOBALS['LSsession'] -> loadLSclass('LSattribute');
24
25 /**
26  * Base d'un objet ldap
27  *
28  * Cette classe définis la base de tout objet ldap géré par LdapSaisie
29  *
30  * @author Benjamin Renard <brenard@easter-eggs.com>
31  */
32 class LSldapObject { 
33   
34   var $config = array();
35   var $type_name;
36   var $attrs = array();
37   var $forms;
38   var $view;
39   var $dn=false;
40   var $other_values=array();
41   var $submitError=true;
42   var $_whoami=NULL;
43   var $_subDn_value=NULL;
44   
45   /**
46    * Constructeur
47    *
48    * Cette methode construit l'objet et définis la configuration.
49    * Elle lance la construction du tableau d'attributs représentés par un objet LSattribute.
50    *
51    * @author Benjamin Renard <brenard@easter-eggs.com>
52    *
53    * @param[in] $type_name [<b>required</b>] string Le nom du type de l'objet
54    * @param[in] $config array La configuration de l'objet
55    *
56    * @retval boolean true si l'objet a été construit, false sinon.
57    */ 
58   function LSldapObject($type_name,$config='auto') {
59     $this -> type_name = $type_name;
60     $this -> config = $config;
61     if($config=='auto') {
62       if(isset($GLOBALS['LSobjects'][$type_name])) {
63         $this -> config = $GLOBALS['LSobjects'][$type_name];
64       }
65       else {
66         $GLOBALS['LSerror'] -> addErrorCode(21);
67         return;
68       }
69     }
70     foreach($this -> config['attrs'] as $attr_name => $attr_config) {
71       if(!$this -> attrs[$attr_name]=new LSattribute($attr_name,$attr_config,$this)) {
72         return;
73       }
74     }
75     return true;
76   }
77   
78   /**
79    * Charge les données de l'objet
80    *
81    * Cette methode définis le DN de l'objet et charge les valeurs de attributs de l'objet
82    * à partir de l'annuaire.
83    *
84    * @author Benjamin Renard <brenard@easter-eggs.com>
85    *
86    * @param[in] $dn string Le DN de l'objet.
87    *
88    * @retval boolean true si la chargement a réussi, false sinon.
89    */ 
90   function loadData($dn) {
91     $this -> dn = $dn;
92     $data = $GLOBALS['LSldap'] -> getAttrs($dn);
93     if(!empty($data)) {
94       foreach($this -> attrs as $attr_name => $attr) {
95         if(!$this -> attrs[$attr_name] -> loadData($data[$attr_name]))
96           return;
97       }
98       return true;
99     }
100     return;
101   }
102   
103   /**
104    * Recharge les données de l'objet
105    *
106    * @author Benjamin Renard <brenard@easter-eggs.com>
107    *
108    * @retval boolean true si la rechargement a réussi, false sinon.
109    */ 
110   function reloadData() {
111     $data = $GLOBALS['LSldap'] -> getAttrs($this -> dn);
112     foreach($this -> attrs as $attr_name => $attr) {
113       if(!$this -> attrs[$attr_name] -> reloadData($data[$attr_name]))
114         return;
115     }
116     return true;
117   }
118   
119   /**
120    * Retourne le format d'affichage de l'objet
121    *
122    * @author Benjamin Renard <brenard@easter-eggs.com>
123    *
124    * @retval string Format d'affichage de l'objet.
125    */ 
126   function getDisplayAttributes() {
127     return $this -> config['select_display_attrs'];
128   }
129   
130   /**
131    * Retourne la valeur descriptive d'affichage de l'objet
132    * 
133    * Cette fonction retourne la valeur descriptive d'affichage de l'objet en fonction
134    * du format défini dans la configuration de l'objet ou spécifié en paramètre.
135    *
136    * @author Benjamin Renard <brenard@easter-eggs.com>
137    *
138    * @param[in] $spe [<i>optionnel</i>] string Format d'affichage de l'objet
139    * @param[in] $full [<i>optionnel</i>] boolean True pour afficher en plus le
140    *                                             subDnName
141    *
142    * @retval string Valeur descriptive d'affichage de l'objet
143    */ 
144   function getDisplayValue($spe='',$full=false) {
145     if ($spe=='') {
146       $spe = $this -> getDisplayAttributes();
147     }
148     $val = $this -> getFData($spe,&$this -> attrs,'getDisplayValue');
149     if ($GLOBALS['LSsession'] -> haveSubDn() && $full) {
150       $val.=' ('.$this -> getSubDnName().')';
151     }
152     return $val;
153   }
154   
155   /**
156    * Chaine formatée
157    * 
158    * Cette fonction retourne la valeur d'une chaine formatée en prennant les valeurs
159    * de l'objet.
160    *
161    * @author Benjamin Renard <brenard@easter-eggs.com>
162    *
163    * @param[in] $format string Format de la chaine
164    *
165    * @retval string Valeur d'une chaine formatée
166    */ 
167   function getFData($format) {
168     $format=getFData($format,$this,'getValue');
169     return $format;
170   }
171   
172   /**
173    * Construit un formulaire de l'objet
174    * 
175    * Cette méthode construit un formulaire LSform à partir de la configuration de l'objet
176    * et de chaque attribut.
177    *
178    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
179    * @param[in] $load DN d'un objet similaire dont la valeur des attribut doit être chargé dans le formulaire.
180    *
181    * @author Benjamin Renard <brenard@easter-eggs.com>
182    *
183    * @retval LSform Le formulaire crée
184    */ 
185   function getForm($idForm,$load=NULL) {
186     $GLOBALS['LSsession'] -> loadLSclass('LSform');
187     $LSform = new LSform($this,$idForm);
188     $this -> forms[$idForm] = array($LSform,$load);
189     
190     if ($load) {
191       $type = $this -> getType();
192       $loadObject = new $type();
193       if (!$loadObject -> loadData($load)) {
194         $load=false;
195       }
196     }
197     
198     if ($load) {
199       foreach($this -> attrs as $attr_name => $attr) {
200         if(!$this -> attrs[$attr_name] -> addToForm($LSform,$idForm,$this,$loadObject -> getValue($attr_name))) {
201           $LSform -> can_validate = false;
202         }
203       }
204     }
205     else {
206       foreach($this -> attrs as $attr_name => $attr) {
207         if(!$this -> attrs[$attr_name] -> addToForm($LSform,$idForm,$this)) {
208           $LSform -> can_validate = false;
209         }
210       }      
211     }
212     return $LSform;
213   }
214   
215   /**
216    * Construit un formulaire de l'objet
217    * 
218    * Cette méthode construit un formulaire LSform à partir de la configuration de l'objet
219    * et de chaque attribut.
220    *
221    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
222    * @param[in] $config Configuration spécifique pour le formulaire
223    *
224    * @author Benjamin Renard <brenard@easter-eggs.com>
225    *
226    * @retval LSform Le formulaire crée
227    */ 
228   function getView() {
229     $GLOBALS['LSsession'] -> loadLSclass('LSform');
230     $this -> view = new LSform($this,'view');
231     foreach($this -> attrs as $attr_name => $attr) {
232       $this -> attrs[$attr_name] -> addToView($this -> view);
233     }
234     $this -> view -> can_validate = false;
235     return $this -> view;
236   }  
237   
238   /**
239    * Rafraichis le formulaire de l'objet
240    * 
241    * Cette méthode recharge les données d'un formulaire LSform.
242    *
243    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
244    *
245    * @author Benjamin Renard <brenard@easter-eggs.com>
246    *
247    * @retval boolean true sile formulaire a été rafraichis, false sinon
248    */ 
249   function refreshForm($idForm) {
250     $LSform = $this -> forms[$idForm][0];
251     foreach($this -> attrs as $attr_name => $attr) {
252       if(!$this -> attrs[$attr_name] -> refreshForm($LSform,$idForm)) {
253         return;
254       }
255     }
256     return true;
257   }
258   
259   /**
260    * Met à jour les données de l'objet et de l'entré de l'annuaire
261    * 
262    * Met à jour les données de l'objet à partir d'un retour d'un formulaire.
263    *
264    * @param[in] $idForm Identifiant du formulaire d'origine
265    *
266    * @author Benjamin Renard <brenard@easter-eggs.com>
267    *
268    * @retval boolean true si la mise à jour a réussi, false sinon
269    *
270    * @see validateAttrsData()
271    * @see submitChange()
272    */ 
273   function updateData($idForm=NULL) {
274     if($idForm!=NULL) {
275       if(isset($this -> forms[$idForm]))
276         $LSform = $this -> forms[$idForm][0];
277       else {
278         $GLOBALS['LSerror'] -> addErrorCode(22,$this -> getType());
279         return;
280       }
281     }
282     else {
283       if(count($this -> forms) > 0) {
284         reset($this -> forms);
285         $idForm = key($this -> forms);
286         $LSform = current($this -> forms);
287         $config = $LSform[1];
288         $LSform = $LSform[0];
289       }
290       else {
291         $GLOBALS['LSerror'] -> addErrorCode(23,$this -> getType());
292         return;
293       }
294     }
295     $new_data = $LSform -> exportValues();
296     if(!is_array($new_data)) {
297       return;
298     }
299     foreach($new_data as $attr_name => $attr_val) {
300       if(isset($this -> attrs[$attr_name])) {
301         $this -> attrs[$attr_name] -> setUpdateData($attr_val);
302       }
303     }
304     if($this -> validateAttrsData($idForm)) {
305       debug("les données sont validées");
306       if(isset($this -> config['before_save'])) {
307         if(function_exists($this -> config['before_save'])) {
308           if(!$this -> config['before_save']($this)) {
309             $GLOBALS['LSerror'] -> addErrorCode(28,$this -> config['before_save']);
310             return;
311           }
312         }
313         else {
314           $GLOBALS['LSerror'] -> addErrorCode(27,$this -> config['before_save']);
315           return;
316         }
317       }
318       if ($this -> submitChange($idForm)) {
319         debug('Les modifications sont submitées');
320         $this -> submitError = false;
321         $this -> reloadData();
322         $this -> refreshForm($idForm);
323       }
324       else {
325         return;
326       }
327       if((isset($this -> config['after_save']))&&(!$this -> submitError)) {
328         if(function_exists($this -> config['after_save'])) {
329           if(!$this -> config['after_save']($this)) {
330             $GLOBALS['LSerror'] -> addErrorCode(30,$this -> config['after_save']);
331             return;
332           }
333         }
334         else {
335           $GLOBALS['LSerror'] -> addErrorCode(29,$this -> config['after_save']);
336           return;
337         }
338       }
339       return true;
340     }
341     else {
342       return;
343     }
344   }
345   
346   /**
347    * Valide les données retournées par un formulaire
348    *
349    * @param[in] $idForm Identifiant du formulaire d'origine
350    *
351    * @author Benjamin Renard <brenard@easter-eggs.com>
352    *
353    * @retval boolean true si les données sont valides, false sinon
354    */ 
355   function validateAttrsData($idForm) {
356     $LSform=$this -> forms[$idForm][0];
357     foreach($this -> attrs as $attr) {
358       if (!$attr -> isValidate()) {
359         if($attr -> isUpdate()) {
360           if (!$this -> validateAttrData($LSform, $attr)) {
361             return;
362           }
363         }
364         else if( ($attr -> getValue() == '') && ($attr -> isRequired()) ) { 
365           if ( $attr -> canBeGenerated()) {
366             if ($attr -> generateValue()) {
367               if (!$this -> validateAttrData($LSform, $attr)) {
368                 $GLOBALS['LSerror'] -> addErrorCode(48,$attr -> getLabel());
369                 return;
370               }
371             }
372             else {
373               $GLOBALS['LSerror'] -> addErrorCode(47,$attr -> getLabel());
374               return;
375             }
376           }
377           else {
378             $GLOBALS['LSerror'] -> addErrorCode(46,$attr -> getLabel());
379             return;
380           }
381
382         }
383       }
384     }
385     return true;
386   }
387
388    /**
389    * Valide les données d'un attribut
390    *
391    * @param[in] $LSForm Formulaire d'origine
392    * @param[in] &$attr Attribut à valider
393    *
394    * @author Benjamin Renard <brenard@easter-eggs.com>
395    *
396    * @retval boolean true si les données sont valides, false sinon
397    */
398   function validateAttrData(&$LSform,&$attr) {
399     $vconfig=$attr -> getValidateConfig();
400
401     $data=$attr -> getUpdateData();
402     if(!is_array($data)) {
403       $data=array($data);
404     }
405
406     // Validation des valeurs de l'attribut
407     if(is_array($vconfig)) {
408       foreach($vconfig as $test) {
409         // Définition du basedn par défaut
410         if (!isset($test['basedn'])) {
411           $test['basedn']=$GLOBALS['LSsession']->topDn;
412         }
413
414         // Définition du message d'erreur
415         if (!empty($test['msg'])) {
416           $msg_error=getFData($test['msg'],$this,'getValue');
417         }
418         else {
419           $msg_error=getFData(_("L'attribut %{attr} n'est pas valide."),$attr -> getLabel());
420         }
421         foreach($data as $val) {
422           // validation par check LDAP
423           if((isset($test['filter'])||isset($test['basedn']))&&(isset($test['result']))) {
424             $sparams=(isset($test['scope']))?array('scope' => $test['scope']):array();
425             $this -> other_values['val']=$val;
426             $sfilter_user=(isset($test['basedn']))?getFData($test['filter'],$this,'getValue'):NULL;
427             if(isset($test['object_type'])) {
428               $test_obj = new $test['object_type']();
429               $sfilter=$test_obj->getObjectFilter();
430               $sfilter='(&'.$sfilter;
431               if($sfilter_user[0]=='(') {
432                 $sfilter=$sfilter.$sfilter_user.')';
433               }
434               else {
435                 $sfilter=$sfilter.'('.$sfilter_user.'))';
436               }
437             }
438             else {
439               $sfilter=$sfilter_user;
440             }
441             $sbasedn=(isset($test['basedn']))?getFData($test['basedn'],$this,'getValue'):NULL;
442             $ret=$GLOBALS['LSldap'] -> getNumberResult ($sfilter,$sbasedn,$sparams);
443             if($test['result']==0) {
444               if($ret!=0) {
445                 $LSform -> setElementError($attr,$msg_error);
446                 return;
447               }
448             }
449             else {
450               if($ret<=0) {
451                 $LSform -> setElementError($attr,$msg_error);
452                 return;
453               }
454             }
455           }
456           // Validation par fonction externe
457           else if(isset($test['function'])) {
458             if (function_exists($test['function'])) {
459               if(!$test['function']($this)) {
460                 $LSform -> setElementError($attr,$msg_error);
461               return;
462               }
463             }
464             else {
465               $GLOBALS['LSerror'] -> addErrorCode(24,array('attr' => $attr->name,'obj' => $this->getType(),'func' => $test['function']));
466               return;
467             }
468           }
469           else {
470             $GLOBALS['LSerror'] -> addErrorCode(25,array('attr' => $attr->name,'obj' => $this->getType()));
471             return;
472           }
473         }
474       }
475     }
476     // Génération des valeurs des attributs dépendants
477     $dependsAttrs=$attr->getDependsAttrs();
478     if (!empty($dependsAttrs)) {
479       foreach($dependsAttrs as $dependAttr) {
480         if(!isset($this -> attrs[$dependAttr])){
481           $GLOBALS['LSerror'] -> addErrorCode(34,array('attr_depend' => $dependAttr, 'attr' => $attr -> getLabel()));
482           continue;
483         }
484         if($this -> attrs[$dependAttr] -> canBeGenerated()) {
485           if (!$this -> attrs[$dependAttr] -> generateValue()) {
486             $GLOBALS['LSerror'] -> addErrorCode(47,$this -> attrs[$dependAttr] -> getLabel());
487             return;
488           }
489         }
490         else {
491           $GLOBALS['LSerror'] -> addErrorCode(46,$this -> attrs[$dependAttr] -> getLabel());
492           return;
493         }
494       }
495     }
496
497     $attr -> validate();
498     unset($this -> other_values['val']);
499     return true;
500   }
501
502   /**
503    * Met à jour les données modifiés dans l'annuaire
504    *
505    * @param[in] $idForm Identifiant du formulaire d'origine
506    *
507    * @author Benjamin Renard <brenard@easter-eggs.com>
508    *
509    * @retval boolean true si la mise à jour a réussi, false sinon
510    */ 
511   function submitChange($idForm) {
512     $submitData=array();
513     foreach($this -> attrs as $attr) {
514       if(($attr -> isUpdate())&&($attr -> isValidate())) {
515         $submitData[$attr -> name] = $attr -> getUpdateData();
516       }
517     }
518     if(!empty($submitData)) {
519       $dn=$this -> getDn();
520       if($dn) {
521         $this -> dn=$dn;
522         debug($submitData);
523         return $GLOBALS['LSldap'] -> update($this -> getType(),$dn, $submitData);
524       }
525       else {
526         $GLOBALS['LSerror'] -> addErrorCode(33);
527         return;
528       }
529     }
530     else {
531       return true;
532     }
533   }
534   
535   /**
536    * Retourne les informations issus d'un DN
537    *
538    * @param[in] $dn Un DN.
539    *
540    * @author Benjamin Renard <brenard@easter-eggs.com>
541    *
542    * @retval array Tableau : 
543    *                  - [0] : le premier paramètre
544    *                  - [1] : les paramètres suivants
545    */ 
546   function getDnInfos($dn) {
547     $infos=ldap_explode_dn($dn,0);
548     if(!$infos)
549       return;
550     $first=true;
551     for($i=1;$i<$infos['count'];$i++)
552       if($first) {
553         $basedn.=$infos[$i];
554         $first=false;
555       }
556       else
557         $basedn.=','.$infos[$i];
558     return array($infos[0],$basedn);
559   }
560   
561   /**
562    * Retourne le filtre correpondants aux objetcClass de l'objet
563    *
564    * @author Benjamin Renard <brenard@easter-eggs.com>
565    *
566    * @retval string le filtre ldap correspondant au type de l'objet
567    */ 
568   function getObjectFilter() {
569     if(!isset($this -> config['objectclass'])) return;
570     foreach ($this -> config['objectclass'] as $class)
571       $filter.='(objectClass='.$class.')';
572     return $filter;
573   }
574   
575   /**
576    * Retourne une liste d'objet du même type.
577    *
578    * Effectue une recherche en fonction des paramètres passé et retourne un
579    * tableau d'objet correspond au resultat de la recherche.
580    *
581    * @author Benjamin Renard <brenard@easter-eggs.com>
582    *
583    * @param[in] $filter array (ou string) Filtre de recherche Ldap / Tableau de filtres de recherche
584    * @param[in] $basedn string DN de base pour la recherche
585    * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search()
586    *
587    * @retval array Tableau d'objets correspondant au resultat de la recherche
588    */ 
589   function listObjects($filter='',$basedn=NULL,$params=array()) {
590     $retInfos=array();
591     $attrs=false;
592     $check_final_dn=false;
593
594     if(!is_array($filter))
595       $filter=array(array('filter' => $filter));
596     
597     $nbFilter=count($filter);
598
599     for($i=0;$i<$nbFilter;$i++) {
600       $new_attrs=array();
601       // Défintion des paramètres de base pour la recherche
602       $sbasedn=$basedn;
603       $sparams=$params;
604       $ret=array();
605       if (isset($filter[$i]['scope']))
606         $sparams["scope"]=$filter[$i]['scope'];
607       
608       // Definition des critères de recherche correspondant au type d'objet à lister
609       if(($nbFilter==1)||(!isset($filter[$i]['attr']))) {
610         // Filtre sur l'objet souhaité
611         $sfilter='(&';
612         $sfilter.=$this -> getObjectFilter();
613         $sfilter_end=')';
614         $check_final_dn=true;
615       }
616       // Initialisation des critères d'une recherche intermédiaire
617       else {
618         if(isset($filter[$i]['object_type'])) {
619           $obj_tmp=new $filter[$i]['object_type']();
620           $obj_filter=$obj_tmp->getObjectFilter();
621           $sfilter='(&'.$obj_filter;
622           $sfilter_end=')';
623         }
624         else {
625           $sfilter='';
626           $sfilter_end='';
627         }
628         if(isset($filter[$i]['scope'])) {
629           $sparams['scope']=$filter[$i]['scope'];
630         }
631         if(isset($filter[$i]['basedn'])) {
632           $sbasedn=$filter[$i]['basedn'];
633         }
634       }
635       // Dans le cas d'une recherche intermédiaire ou finale
636       if($attrs!=false) {
637         // Initialisation des variables
638         $ret_gen=array();
639         $new_attrs=array();
640         
641         // Pour tout les attributs retournés
642         for($ii=0;$ii<count($attrs);$ii++) {
643           $sfilter_for='';
644           // Définition du filtre de recherche à partir des paramètres utilisateurs et
645           // des paramètres de recherche de l'objet à listé (dans le cas d'une recherche finale
646           if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
647             $sfilter_user=getFData($filter[$i]['filter'],$attrs[$ii]);
648             if($sfilter_user[0]=='(')
649               $sfilter_for=$sfilter.$sfilter_user;
650             else
651               $sfilter_for=$sfilter.'('.$sfilter_user.')';
652           }
653           else {
654             $sfilter_for=$sfilter;
655           }
656           
657           if(isset($filter[$i]['basedn'])) {
658             $sbasedn=getFData($filter[$i]['basedn'],$attrs[$ii]);
659             if ((!$this -> isCompatibleDNs($sbasedn,$basedn))&&($check_final_dn)) continue;
660           }
661         
662           // Vérification de la compatibilité du basedn de la recherche et du basedn générale
663           // Finalisation du filtre
664           $sfilter_for.=$sfilter_end;
665         
666         
667           // Execution de la recherche
668           $ret=$GLOBALS['LSldap'] -> search ($sfilter_for,$sbasedn,$sparams);
669           
670           // Si il y un retour
671           if(isset($ret[0])) {
672             // si il ya une suite (recherche intermédiaire)
673             if($filter[$i]['attr']){
674               for($iii=0;$iii<count($ret);$iii++) {
675                 if(isset($ret[$iii]['attrs'][$filter[$i]['attr']])) {
676                   // cas de valeur multiple
677                   if(is_array($ret[$iii]['attrs'][$filter[$i]['attr']])) {
678                     foreach($ret[$iii]['attrs'][$filter[$i]['attr']] as $val_attr) {
679                       $new_attrs[]=$val_attr;
680                     }
681                   }
682                   // cas de valeur unique
683                   else {
684                     $new_attrs[]=$ret[$iii]['attrs'][$filter[$i]['attr']];
685                   }
686                 }
687               }
688             }
689             else {
690               // vérification de la compatibilité de la compatibilité du DN resultant
691               // et du basedn de recherche 
692               if (!$this -> isCompatibleDNs($ret[0]['dn'],$basedn))
693                 continue;
694               // ajout du DN au resultat finale
695               $ret_gen[]=$ret[0]['dn'];
696             }
697           }
698         }
699         // cas du dernier filtre
700         if(!empty($ret_gen)) {
701           // on quitte la boucle des filtres de la conf
702           $ret=$ret_gen;
703           break;
704         }
705         // dans le cas d'une suite prévu mais d'un retour nul de la précédente recherche
706         else if(empty($new_attrs)) {
707             // retour vide et arrêt de la recherche
708             $ret=array();
709             break;
710         }
711         else {
712           $attrs=$new_attrs;
713         }
714       }
715       // Dans le cas de la recherche initiale
716       else {
717         // Déclaration du filtre de recherche
718         if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
719           if($filter[$i]['filter'][0]=='(') {
720             $sfilter.=$filter[$i]['filter'];
721           }
722           else {
723             $sfilter.='('.$filter[$i]['filter'].')';
724           }
725         }
726         // fermeture du filtre
727         $sfilter.=$sfilter_end;
728         
729         // Lancement de la recherche
730         $ret=$GLOBALS['LSldap'] -> search ($sfilter,$sbasedn,$sparams);
731         
732         //Si filtre multiple => on recupère une liste d'attributs
733         if(isset($filter[$i]['attr'])) {
734           for($ii=0;$ii<count($ret);$ii++) {
735             if(isset($ret[$ii]['attrs'][$filter[$i]['attr']])) {
736               // cas de valeur multiple
737               if(is_array($ret[$ii]['attrs'][$filter[$i]['attr']])) {
738                 foreach($ret[$ii]['attrs'][$filter[$i]['attr']] as $val_attr) {
739                   $attrs[]=$val_attr;
740                 }
741               }
742               // cas de valeur unique
743               else {
744                 $attrs[]=$ret[$ii]['attrs'][$filter[$i]['attr']];
745               }
746             }
747           }
748           
749           // Si aucunne valeur n'est retournées
750           if(empty($attrs)){
751             // arrêt et retour à zéro
752             $ret=array();
753             break;
754           }
755         }
756         // Si recherche unique
757         else {
758           // préparation du retour finale
759           if (is_array($ret)) {
760             $ret_final=array();
761             foreach($ret as $obj)
762               $ret_final[]=$obj['dn'];
763             $ret=$ret_final;
764           }
765           else {
766             $ret=array();
767           }
768           break;
769         }
770       }
771     }
772     
773     // Création d'un tableau d'objet correspondant au valeur retourné
774     for($i=0;$i<count($ret);$i++) {
775       $retInfos[$i] = new $this -> type_name($this -> config);
776       $retInfos[$i] -> loadData($ret[$i]);
777     }
778     
779     return $retInfos;
780   }
781  
782  
783   /**
784    * Recherche un objet à partir de la valeur exact de son RDN
785    * 
786    * @author Benjamin Renard <brenard@easter-eggs.com>
787    * 
788    * @param[in] $name string Valeur de son RDN
789    * @param[in] $basedn string Le DN de base de la recherche
790    * 
791    * @retval array Tableau d'objets correspondant au resultat de la recherche
792    */
793   function searchObject($name,$basedn=NULL) {
794     $filter = $this -> config['rdn'].'='.$name; 
795     return $this -> listObjects($filter,$basedn); 
796   }
797
798   /**
799    * Retourne une valeur de l'objet
800    *
801    * Retourne une valeur en fonction du paramètre. Si la valeur est inconnue, la valeur retourné est ' '.
802    * tableau d'objet correspond au resultat de la recherche.
803    *
804    * Valeurs possibles :
805    * - 'dn' ou '%{dn} : DN de l'objet
806    * - [nom d'un attribut] : valeur de l'attribut
807    * - [clef de $this -> other_values] : valeur de $this -> other_values
808    *
809    * @author Benjamin Renard <brenard@easter-eggs.com>
810    *
811    * @param[in] $val string Le nom de la valeur demandée
812    *
813    * @retval mixed la valeur demandé ou ' ' si celle-ci est inconnue.
814    */ 
815   function getValue($val) {
816     if(($val=='dn')||($val=='%{dn}')) {
817       return $this -> dn;
818     }
819     else if(($val=='rdn')||($val=='%{rdn}')) {
820       return $this -> attrs[ $this -> config['rdn'] ] -> getValue();
821     }
822     else if(isset($this ->  attrs[$val])){
823       if (method_exists($this ->  attrs[$val],'getValue'))
824         return $this -> attrs[$val] -> getValue();
825       else
826         return ' ';
827     }
828     else if(isset($this -> other_values[$val])){
829       return $this -> other_values[$val];
830     }
831     else {
832       return ' ';
833     }
834   }
835
836   /**
837    * Retourn un tableau pour un select d'un objet du même type
838    * 
839    * @author Benjamin Renard <brenard@easter-eggs.com>
840    *
841    * @retval array('dn' => 'display')
842    */
843   function getSelectArray($topDn=NULL) {
844     $list = $this -> listObjects(NULL,$topDn);
845     $return=array();
846     foreach($list as $object) {
847       $return[$object -> getDn()] = $object -> getDisplayValue(); 
848     }
849     return $return;
850   }
851
852   /**
853    * Retourne le DN de l'objet
854    *
855    * Cette methode retourne le DN de l'objet. Si celui-ci n'existe pas, il le construit à partir de la 
856    * configuration de l'objet et la valeur de son attribut rdn.
857    *
858    * @author Benjamin Renard <brenard@easter-eggs.com>
859    *
860    * @retval string Le DN de l'objet
861    */   
862   function getDn() {
863     if($this -> dn) {
864       return $this -> dn;
865     }
866     else {
867       $rdn_attr=$this -> config['rdn'];
868       if( (isset($this -> config['rdn'])) && (isset($this -> attrs[$rdn_attr])) && (isset($this -> config['container_dn'])) && (isset($GLOBALS['LSsession']->topDn)) ) {
869         $rdn_val=$this -> attrs[$rdn_attr] -> getUpdateData();
870         if (!empty($rdn_val)) {
871           return $rdn_attr.'='.$rdn_val[0].','.$this -> config['container_dn'].','.$GLOBALS['LSsession']->topDn;
872         }
873         else {
874           $GLOBALS['LSerror'] -> addErrorCode(32,$this -> config['rdn']);
875           return;
876         }
877       }
878       else {
879         $GLOBALS['LSerror'] -> addErrorCode(31,$this -> getType());
880         return;
881       }
882     }
883   }
884
885   /**
886    * Retourne le type de l'objet
887    *
888    * @author Benjamin Renard <brenard@easter-eggs.com>
889    * 
890    * @retval string Le type de l'objet ($this -> type_name)
891    */
892   function getType() {
893     return $this -> type_name;
894   }
895   
896   /**
897    * Retourne qui est l'utilisateur par rapport à cet object
898    *
899    * @author Benjamin Renard <brenard@easter-eggs.com>
900    * 
901    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
902    */
903   function whoami() {
904     if (!$this -> _whoami)
905       $this -> _whoami = $GLOBALS['LSsession'] -> whoami($this -> dn);
906     return $this -> _whoami;
907   }
908   
909   /**
910    * Retourne le label de l'objet
911    *
912    * @author Benjamin Renard <brenard@easter-eggs.com>
913    * 
914    * @retval string Le label de l'objet ($this -> config['label'])
915    */
916   function getLabel() {
917     return $this -> config['label'];
918   }
919   
920   
921   /**
922    * Supprime l'objet dans l'annuaire
923    *
924    * @author Benjamin Renard <brenard@easter-eggs.com>
925    * 
926    * @retval boolean True si l'objet à été supprimé, false sinon
927    */
928   function remove() {
929     return $GLOBALS['LSldap'] -> remove($this -> getDn());
930   }
931   
932   /**
933    * L'objet est-il nouveau
934    * 
935    * @author Benjamin Renard <brenard@easter-eggs.com>
936    * 
937    * @retval boolean True si l'objet est nouveau, false sinon
938    */
939   function isNew() {
940     return (!$this -> dn);
941   }
942
943   /**
944    * Retourne la valeur (DN) du subDn de l'objet  
945    * 
946    * @return string La valeur du subDn de l'object
947    */
948   function getSubDnValue() {
949     if ($this -> _subDn_value) {
950       return $this -> _subDn_value;
951     }
952     $dn = $this -> getValue('dn');
953     $subDn_value='';
954     $subDnLdapServer = $GLOBALS['LSsession'] -> getSortSubDnLdapServer();
955     foreach ($subDnLdapServer as $subDn => $subDn_name) {
956       if (isCompatibleDNs($subDn,$dn)&&($subDn!=$dn)) {
957         $subDn_value=$subDn;
958         break;
959       }
960     }
961     $this -> _subDn_value = $subDn_value;
962     return $subDn_value;
963   }
964
965   /**
966    * Retourne la nom du subDn de l'objet  
967    * 
968    * @return string Le nom du subDn de l'object
969    */
970   function getSubDnName() {
971     $subDnLdapServer = $GLOBALS['LSsession'] -> getSortSubDnLdapServer();
972     return $subDnLdapServer[$this -> getSubDnValue()];
973   }
974 }
975
976 ?>