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