Initial import
[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
24 /**
25  * Base d'un objet ldap
26  *
27  * Cette classe définis la base de tout objet ldap géré par LdapSaisie
28  *
29  * @author Benjamin Renard <brenard@easter-eggs.com>
30  */
31 class LSldapObject { 
32         
33         var $config;
34         var $type_name;
35         var $attrs;
36   var $forms;
37   var $dn=false;
38   var $other_values=array();
39   
40   /**
41    * Constructeur
42    *
43    * Cette methode construit l'objet et définis la configuration.
44    * Elle lance la construction du tableau d'attributs représentés par un objet LSattribute.
45    *
46    * @author Benjamin Renard <brenard@easter-eggs.com>
47    *
48    * @param[in] $type_name [<b>required</b>] string Le nom du type de l'objet
49    * @param[in] $config array La configuration de l'objet
50    *
51    * @retval boolean true si l'objet a été construit, false sinon.
52    */   
53         function LSldapObject($type_name,$config='auto') {
54                 $this -> type_name = $type_name;
55     $this -> config = $config;
56     if($config=='auto') {
57       if(isset($GLOBALS['LSobjects'][$type_name]))
58         $this -> config = $GLOBALS['LSobjects'][$type_name];
59       else {
60         $GLOBALS['LSerror'] -> addErrorCode(21);
61         return;
62       }
63     }
64                 foreach($this -> config['attrs'] as $attr_name => $attr_config) {
65                         if(!$this -> attrs[$attr_name]=new LSattribute($attr_name,$attr_config))
66         return;
67                 }
68     return true;
69         }
70         
71   /**
72    * Charge les données de l'objet
73    *
74    * Cette methode définis le DN de l'objet et charge les valeurs de attributs de l'objet
75    * à partir de l'annuaire.
76    *
77    * @author Benjamin Renard <brenard@easter-eggs.com>
78    *
79    * @param[in] $dn string Le DN de l'objet.
80    *
81    * @retval boolean true si la chargement a réussi, false sinon.
82    */   
83   function loadData($dn) {
84     $this -> dn = $dn;
85     $data = $GLOBALS['LSldap'] -> getAttrs($dn);
86     foreach($this -> attrs as $attr_name => $attr) {
87       if(!$this -> attrs[$attr_name] -> loadData($data[$attr_name]))
88         return;
89     }
90     return true;
91   }
92   
93   /**
94    * Retourne le format d'affichage de l'objet
95    *
96    * @author Benjamin Renard <brenard@easter-eggs.com>
97    *
98    * @retval string Format d'affichage de l'objet.
99    */   
100         function getDisplayAttributes() {
101                 return $this -> config['select_display_attrs'];
102         }
103   
104   /**
105    * Retourne la valeur descriptive d'affichage de l'objet
106    * 
107    * Cette fonction retourne la valeur descriptive d'affichage de l'objet en fonction
108    * du format défini dans la configuration de l'objet ou spécifié en paramètre.
109    *
110    * @author Benjamin Renard <brenard@easter-eggs.com>
111    *
112    * @param[in] $spe [<i>optionnel</i>] string Format d'affichage de l'objet
113    *
114    * @retval string Valeur descriptive d'affichage de l'objet
115    */   
116   function getDisplayValue($spe) {
117     if ($spe=='') {
118       $spe = $this -> getDisplayAttributes();
119     }
120     return $this -> getFData($spe,&$this -> attrs,'getDisplayValue');
121   }
122   
123   /**
124    * Chaine formatée
125    * 
126    * Cette fonction retourne la valeur d'une chaine formatée en prennant les valeurs
127    * de l'objet.
128    *
129    * @author Benjamin Renard <brenard@easter-eggs.com>
130    *
131    * @param[in] $format string Format de la chaine
132    *
133    * @retval string Valeur d'une chaine formatée
134    */   
135   function getFData($format) {
136     $format=getFData($format,$this,'getValue');
137     return $format;
138   }
139   
140   /**
141    * DEBUG : Affiche le nom et la valeur de chaque attribut
142    *
143    * @author Benjamin Renard <brenard@easter-eggs.com>
144    *
145    * @retval void
146    */   
147   function debug_printAttrsValues() {
148     foreach($this -> attrs as $attr_name => $attr) {
149       print $attr_name.' : ';
150       $attr -> debug_printValue();
151       print "\n";
152     }
153   }
154
155   /**
156    * Construit un formulaire de l'objet
157    * 
158    * Cette méthode construit un formulaire LSform à partir de la configuration de l'objet
159    * et de chaque attribut.
160    *
161    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
162    *
163    * @author Benjamin Renard <brenard@easter-eggs.com>
164    *
165    * @retval LSform Le formulaire crée
166    */   
167   function getForm($idForm,$config=array()) {
168     $LSform = new LSform($idForm);
169     $this -> forms[$idForm] = array($LSform,$config);
170     foreach($this -> attrs as $attr_name => $attr) {
171       if(!$this -> attrs[$attr_name] -> addToForm($LSform -> quickform,$idForm)) {
172         $LSform -> can_validate = false;
173       }
174     }
175     return $LSform;
176   }
177   
178   /**
179    * Met à jour les données de l'objet et de l'entré de l'annuaire
180    * 
181    * Met à jour les données de l'objet à partir d'un retour d'un formulaire.
182    *
183    * @param[in] $idForm Identifiant du formulaire d'origine
184    *
185    * @author Benjamin Renard <brenard@easter-eggs.com>
186    *
187    * @retval boolean true si la mise à jour a réussi, false sinon
188    *
189    * @see validateAttrsData()
190    * @see submitChange()
191    */   
192   function updateData($idForm=NULL) {
193     if($idForm!=NULL) {
194       if(isset($this -> forms[$idForm]))
195         $LSform = $this -> forms[$idForm][0];
196       else {
197         $GLOBALS['LSerror'] -> addErrorCode(22,$this -> type_name);
198         return;
199       }
200     }
201     else {
202       if(count($this -> forms) > 0) {
203         reset($this -> forms);
204         $idForm = key($this -> forms);
205         $LSform = current($this -> forms);
206         $config = $LSform[1];
207         $LSform = $LSform[0];
208       }
209       else {
210         $GLOBALS['LSerror'] -> addErrorCode(23,$this -> type_name);
211         $GLOBALS['LSerror'] -> stop();
212       }
213     }
214     $new_data = $LSform -> quickform -> exportValues();
215     foreach($new_data as $attr_name => $attr_val) {
216       if(isset($this -> attrs[$attr_name])) {
217         $this -> attrs[$attr_name] -> setUpdateData($attr_val);
218       }
219     }
220     if($this -> validateAttrsData($idForm)) {
221       if(isset($this -> config['before_save'])) {
222         if(function_exists($this -> config['before_save'])) {
223           if(!$this -> config['before_save']($this)) {
224             $GLOBALS['LSerror'] -> addErrorCode(28,$this -> config['before_save']);
225             $GLOBALS['LSerror'] -> stop();
226           }
227         }
228         else {
229           $GLOBALS['LSerror'] -> addErrorCode(27,$this -> config['before_save']);
230           $GLOBALS['LSerror'] -> stop();
231         }
232       }
233       $this -> submitChange($idForm);
234       if(isset($this -> config['after_save'])) {
235         if(function_exists($this -> config['after_save'])) {
236           if(!$this -> config['after_save']($this)) {
237             $GLOBALS['LSerror'] -> addErrorCode(30,$this -> config['after_save']);
238           }
239         }
240         else {
241           $GLOBALS['LSerror'] -> addErrorCode(29,$this -> config['after_save']);
242         }
243       }
244     }
245   }
246   
247   /**
248    * Valide les données retournées par un formulaire
249    *
250    * @param[in] $idForm Identifiant du formulaire d'origine
251    *
252    * @author Benjamin Renard <brenard@easter-eggs.com>
253    *
254    * @retval boolean true si les données sont valides, false sinon
255    */   
256   function validateAttrsData($idForm) {
257     $LSform=$this -> forms[$idForm][0];
258     foreach($this -> attrs as $attr) {
259       if(($attr -> isUpdate())&&(!$attr -> isValidate())) {
260         //~ echo 'NAME : '.$attr -> name.' Val : '.$attr -> getUpdateData();
261         $vconfig=$attr -> getValidateConfig();
262         if(is_array($vconfig)) {
263           foreach($vconfig as $test) {
264             $data=$attr -> getUpdateData();
265             if(!is_array($data))
266               $data=array($data);
267             foreach($data as $val) {
268               // validation par check LDAP
269               if((isset($test['filter'])||isset($test['basedn']))&&(isset($test['result']))) {
270                 $sparams=(isset($test['scope']))?array('scope' => $test['scope']):array();
271                 $this -> other_values['val']=$val;
272                 $sfilter_user=(isset($test['basedn']))?getFData($test['filter'],$this,'getValue'):NULL;
273                 //~ echo $sfilter_user;
274                 if(isset($test['object_type'])) {
275                   $test_obj = new $test['object_type']('auto');
276                   $sfilter=$test_obj->getObjectFilter();
277                   $sfilter='(&'.$sfilter;
278                   if($sfilter_user[0]=='(')
279                     $sfilter=$sfilter.$sfilter_user.')';
280                   else
281                     $sfilter=$sfilter.'('.$sfilter_user.'))';
282                 }
283                 else {
284                   $sfilter=$sfilter_user;
285                 }
286                 $sbasedn=(isset($test['basedn']))?getFData($test['basedn'],$this,'getValue'):NULL;
287                 $ret=$GLOBALS['LSldap'] -> getNumberResult ($sfilter,$sbasedn,$sparams);
288                 //~ echo 'Basedn : "'.$sbasedn.'" Filter : "'.$sfilter.'" NAME : '.$attr -> name.' Nb : '.$ret."<br />\n";
289                 if($test['result']==0) {
290                   if($ret!=0) {
291                     $LSform -> setElementError($attr,$test['msg']);
292                     return;
293                   }
294                 }
295                 else {
296                   if($ret<=0) {
297                     $LSform -> setElementError($attr,$msg_error);
298                     return;
299                   }
300                 }
301               }
302               // Validation par fonction externe
303               else if(isset($test['function'])) {
304                 if (function_exists($test['function'])) {
305                   if(!$test['function']($this)) {
306                     $LSform -> setElementError($attr,$msg_error);
307                     return;
308                   }
309                 }
310                 else {
311                   $GLOBALS['LSerror'] -> addErrorCode(24,array('attr' => $attr->name,'obj' => $this->type_name,'func' => $test['function']));
312                   return;
313                 }
314               }
315               else {
316                 $GLOBALS['LSerror'] -> addErrorCode(25,array('attr' => $attr->name,'obj' => $this->type_name));
317                 return;
318               }
319             }
320           }
321         }
322         $attr -> validate();
323       }
324     }
325     unset($this -> other_values['val']);
326     return true;
327   }
328   
329   /**
330    * Met à jour les données modifiés dans l'annuaire
331    *
332    * @param[in] $idForm Identifiant du formulaire d'origine
333    *
334    * @author Benjamin Renard <brenard@easter-eggs.com>
335    *
336    * @retval boolean true si la mise à jour a réussi, false sinon
337    */   
338   function submitChange($idForm) {
339     $submit_data=array();
340     foreach($this -> attrs as $attr) {
341       if(($attr -> isUpdate())&&($attr -> isValidate())) {
342         $submit_data[$attr -> name] = $attr -> getUpdateData();
343       }
344     }
345     print_r($submit_data);
346   }
347   
348   /**
349    * Retourne les informations issus d'un DN
350    *
351    * @param[in] $dn Un DN.
352    *
353    * @author Benjamin Renard <brenard@easter-eggs.com>
354    *
355    * @retval array Tableau : 
356    *                  - [0] : le premier paramètre
357    *                  - [1] : les paramètres suivants
358    */   
359   function getDnInfos($dn) {
360     $infos=ldap_explode_dn($dn,0);
361     if(!$infos)
362       return;
363     $first=true;
364     for($i=1;$i<$infos['count'];$i++)
365       if($first) {
366         $basedn.=$infos[$i];
367         $first=false;
368       }
369       else
370         $basedn.=','.$infos[$i];
371     return array($infos[0],$basedn);
372   }
373   
374   /**
375    * Fait la somme de DN
376    *
377    * Retourne un DN qui correspond au point de séparation des DN si les DN 
378    * ne sont pas dans la meme dans la meme branche ou le dn le plus long sinon.
379    *
380    * @param[in] $dn Un premier DN.
381    * @param[in] $dn Un deuxième DN.
382    *
383    * @author Benjamin Renard <brenard@easter-eggs.com>
384    *
385    * @retval string Un DN (ou false si les DN ne sont pas valide)
386    */   
387   function sumDn($dn1,$dn2) {
388     $infos1=ldap_explode_dn($dn1,0);
389     if(!$infos1)
390       return;
391     $infos2=ldap_explode_dn($dn2,0);
392     if(!$infos2)
393       return;
394     if($infos2['count']>$infos1['count']) {
395       $tmp=$infos1;
396       $infos1=$infos2;
397       $infos2=$tmp;
398     }
399     $infos1=array_reverse($infos1);
400     $infos2=array_reverse($infos2);
401     
402     $first=true;
403     $basedn='';
404     for($i=0;$i<$infos1['count'];$i++) {
405       if(($infos1[$i]==$infos2[$i])||(!isset($infos2[$i]))) {
406         if($first) {
407           $basedn=$infos1[$i];
408           $first=false;
409         }
410         else
411           $basedn=$infos1[$i].','.$basedn;
412       }
413       else {
414         return $basedn;
415       }
416     }
417     return $basedn;
418   }
419   
420   /**
421    * Vérifie la compatibilite des DN
422    *
423    * Vérifie que les DNs sont dans la même branche de l'annuaire.
424    *
425    * @param[in] $dn Un premier DN.
426    * @param[in] $dn Un deuxième DN.
427    *
428    * @author Benjamin Renard <brenard@easter-eggs.com>
429    *
430    * @retval boolean true si les DN sont compatibles, false sinon.
431    */   
432   function isCompatibleDNs($dn1,$dn2) {
433     $infos1=ldap_explode_dn($dn1,0);
434     if(!$infos1)
435       return;
436     $infos2=ldap_explode_dn($dn2,0);
437     if(!$infos2)
438       return;
439     if($infos2['count']>$infos1['count']) {
440       $tmp=$infos1;
441       $infos1=$infos2;
442       $infos2=$tmp;
443     }
444     $infos1=array_reverse($infos1);
445     $infos2=array_reverse($infos2);
446     
447     for($i=0;$i<$infos1['count'];$i++) {
448       if(($infos1[$i]==$infos2[$i])||(!isset($infos2[$i])))
449         continue;
450       else
451         return false;
452     }
453     return true;
454   }
455   
456   /**
457    * Retourne le filtre correpondants aux objetcClass de l'objet
458    *
459    * @author Benjamin Renard <brenard@easter-eggs.com>
460    *
461    * @retval string le filtre ldap correspondant au type de l'objet
462    */   
463   function getObjectFilter() {
464     if(!isset($this -> config['objectclass'])) return;
465     foreach ($this -> config['objectclass'] as $class)
466       $filter.='(objectClass='.$class.')';
467     return $filter;
468   }
469   
470   /**
471    * Retourne une liste d'objet du même type.
472    *
473    * Effectue une recherche en fonction des paramètres passé et retourne un
474    * tableau d'objet correspond au resultat de la recherche.
475    *
476    * @author Benjamin Renard <brenard@easter-eggs.com>
477    *
478    * @param[in] $filter array (ou string) Filtre de recherche Ldap / Tableau de filtres de recherche
479    * @param[in] $basedn string DN de base pour la recherche
480    * @param[in] $params array Paramètres de recherche au format Net_LDAP::search()
481    *
482    * @retval array Tableau d'objet correspondant au resultat de la recherche
483    */   
484   function listObjects($filter='',$basedn=NULL,$params=array()) {
485     $retInfos=array();
486     $attrs=false;
487     $check_final_dn=false;
488
489     if(!is_array($filter))
490       $filter=array(array('filter' => $filter));
491     
492     $nbFilter=count($filter);
493
494     for($i=0;$i<$nbFilter;$i++) {
495       $new_attrs=array();
496       // Défintion des paramètres de base pour la recherche
497       $sbasedn=$basedn;
498       $sparams=$params;
499       $ret=array();
500       if (isset($filter[$i]['scope']))
501         $sparams["scope"]=$filter[$i]['scope'];
502       
503       // Definition des critères de recherche correspondant au type d'objet à lister
504       if(($nbFilter==1)||(!isset($filter[$i]['attr']))) {
505         // Filtre sur l'objet souhaité
506         $sfilter='(&';
507         $sfilter.=$this -> getObjectFilter();
508         $sfilter_end=')';
509         $check_final_dn=true;
510       }
511       // Initialisation des critères d'une recherche intermédiaire
512       else {
513         if(isset($filter[$i]['object_type'])) {
514           $obj_tmp=new $filter[$i]['object_type']();
515           $obj_filter=$obj_tmp->getObjectFilter();
516           $sfilter='(&'.$obj_filter;
517           $sfilter_end=')';
518         }
519         else {
520           $sfilter='';
521           $sfilter_end='';
522         }
523         if(isset($filter[$i]['scope'])) {
524           $sparams['scope']=$filter[$i]['scope'];
525         }
526         if(isset($filter[$i]['basedn'])) {
527           $sbasedn=$filter[$i]['basedn'];
528         }
529       }
530       // Dans le cas d'une recherche intermédiaire ou finale
531       if($attrs!=false) {
532         // Initialisation des variables
533         $ret_gen=array();
534         $new_attrs=array();
535         
536         // Pour tout les attributs retournés
537         for($ii=0;$ii<count($attrs);$ii++) {
538           $sfilter_for='';
539           // Définition du filtre de recherche à partir des paramètres utilisateurs et
540           // des paramètres de recherche de l'objet à listé (dans le cas d'une recherche finale
541           if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
542             $sfilter_user=getFData($filter[$i]['filter'],$attrs[$ii]);
543             if($sfilter_user[0]=='(')
544               $sfilter_for=$sfilter.$sfilter_user;
545             else
546               $sfilter_for=$sfilter.'('.$sfilter_user.')';
547           }
548           else {
549             $sfilter_for=$sfilter;
550           }
551           
552           if(isset($filter[$i]['basedn'])) {
553             $sbasedn=getFData($filter[$i]['basedn'],$attrs[$ii]);
554             if ((!$this -> isCompatibleDNs($sbasedn,$basedn))&&($check_final_dn)) continue;
555           }
556         
557           // Vérification de la compatibilité du basedn de la recherche et du basedn générale
558           //~ if ($this -> isCompatibleDNs($filter[$i]['basedn'],$basedn)) {
559             //~ $sbasedn=$this -> sumDn($filter[$i]['basedn'],$basedn);
560           //~ }
561           // Finalisation du filtre
562           $sfilter_for.=$sfilter_end;
563         
564           //~ print 'filter1 : '.$sfilter_for." | basedn : ".$sbasedn."\n";
565         
566           // Execution de la recherche
567           $ret=$GLOBALS['LSldap'] -> search ($sfilter_for,$sbasedn,$sparams);
568           
569           //~ print('Nb resultat : '.count($ret));
570           
571           // Si il y un retour
572           if(isset($ret[0])) {
573             //~ print_r($ret);
574             // si il ya une suite (recherche intermédiaire)
575             if($filter[$i]['attr']){
576               for($iii=0;$iii<count($ret);$iii++) {
577                 if(isset($ret[$iii]['attrs'][$filter[$i]['attr']])) {
578                   // cas de valeur multiple
579                   if(is_array($ret[$iii]['attrs'][$filter[$i]['attr']])) {
580                     foreach($ret[$iii]['attrs'][$filter[$i]['attr']] as $val_attr) {
581                       $new_attrs[]=$val_attr;
582                     }
583                   }
584                   // cas de valeur unique
585                   else {
586                     $new_attrs[]=$ret[$iii]['attrs'][$filter[$i]['attr']];
587                   }
588                 }
589               }
590             }
591             else {
592               // vérification de la compatibilité de la compatibilité du DN resultant
593               // et du basedn de recherche 
594               if (!$this -> isCompatibleDNs($ret[0]['dn'],$basedn))
595                 continue;
596               // ajout du DN au resultat finale
597               $ret_gen[]=$ret[0]['dn'];
598             }
599           }
600         }
601         // cas du dernier filtre
602         if(!empty($ret_gen)) {
603           // on quitte la boucle des filtres de la conf
604           $ret=$ret_gen;
605           break;
606         }
607         // dans le cas d'une suite prévu mais d'un retour nul de la précédente recherche
608         else if(empty($new_attrs)) {
609             // retour vide et arrêt de la recherche
610             $ret=array();
611             break;
612         }
613         else {
614           $attrs=$new_attrs;
615         }
616       }
617       // Dans le cas de la recherche initiale
618       else {
619         // Déclaration du filtre de recherche
620         if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
621           if($filter[$i]['filter'][0]=='(') {
622             $sfilter.=$filter[$i]['filter'];
623           }
624           else {
625             $sfilter.='('.$filter[$i]['filter'].')';
626           }
627         }
628         // fermeture du filtre
629         $sfilter.=$sfilter_end;
630         
631         //~ print 'filter2 : '.$sfilter."\n";
632         //~ print_r($sparams);
633         
634         // Lancement de la recherche
635         $ret=$GLOBALS['LSldap'] -> search ($sfilter,$sbasedn,$sparams);
636         
637         //~ print('Nb resultat : '.count($ret));
638         
639         //Si filtre multiple => on recupère une liste d'attributs
640         if(isset($filter[$i]['attr'])) {
641           for($ii=0;$ii<count($ret);$ii++) {
642             if(isset($ret[$ii]['attrs'][$filter[$i]['attr']])) {
643               // cas de valeur multiple
644               if(is_array($ret[$ii]['attrs'][$filter[$i]['attr']])) {
645                 foreach($ret[$ii]['attrs'][$filter[$i]['attr']] as $val_attr) {
646                   $attrs[]=$val_attr;
647                 }
648               }
649               // cas de valeur unique
650               else {
651                 $attrs[]=$ret[$ii]['attrs'][$filter[$i]['attr']];
652               }
653             }
654           }
655           
656           // Si aucunne valeur n'est retournées
657           if(empty($attrs)){
658             // arrêt et retour à zéro
659             $ret=array();
660             break;
661           }
662         }
663         // Si recherche unique
664         else {
665           // préparation du retour finale
666           $ret_final=array();
667           foreach($ret as $obj)
668             $ret_final[]=$obj['dn'];
669           $ret=$ret_final;
670           break;
671         }
672       }
673       //~ print_r($attrs);
674     }
675     
676     // Création d'un tableau d'objet correspondant au valeur retourné
677     for($i=0;$i<count($ret);$i++) {
678       $retInfos[$i] = new $this -> type_name($this -> config);
679       $retInfos[$i] -> loadData($ret[$i]);
680       //~ echo $ret[$i]['dn']."\n";
681     }
682     
683     return $retInfos;
684     
685   }
686   
687   /**
688    * Retourne une valeur de l'objet
689    *
690    * Retourne une valeur en fonction du paramètre. Si la valeur est inconnue, la valeur retourné est ' '.
691    * tableau d'objet correspond au resultat de la recherche.
692    *
693    * Valeurs possibles :
694    * - 'dn' ou '%{dn} : DN de l'objet
695    * - [nom d'un attribut] : valeur de l'attribut
696    * - [clef de $this -> other_values] : valeur de $this -> other_values
697    *
698    * @author Benjamin Renard <brenard@easter-eggs.com>
699    *
700    * @param[in] $val string nom de la valeur demandée
701    *
702    * @retval mixed la valeur demandé ou ' ' si celle-ci est inconnue.
703    */   
704   function getValue($val) {
705     if(($val=='dn')||($val=='%{dn}')) {
706       return $this -> dn;
707     }
708     else if(isset($this ->  attrs[$val])){
709       if (method_exists($this ->  attrs[$val],'getValue'))
710         return $this -> attrs[$val] -> getValue();
711       else
712         return ' ';
713     }
714     else if(isset($this -> other_values[$val])){
715       return $this -> other_values[$val];
716     }
717     else {
718       return ' ';
719     }
720   }
721   
722 }
723
724 ?>