- LSldap : Ajout de debug
[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   var $_relationsCache=array();
45   
46   /**
47    * Constructeur
48    *
49    * Cette methode construit l'objet et définis la configuration.
50    * Elle lance la construction du tableau d'attributs représentés par un objet LSattribute.
51    *
52    * @author Benjamin Renard <brenard@easter-eggs.com>
53    *
54    * @param[in] $type_name [<b>required</b>] string Le nom du type de l'objet
55    * @param[in] $config array La configuration de l'objet
56    *
57    * @retval boolean true si l'objet a Ã©té construit, false sinon.
58    */ 
59   function LSldapObject($type_name,$config='auto') {
60     $this -> type_name = $type_name;
61     $this -> config = $config;
62     if($config=='auto') {
63       if(isset($GLOBALS['LSobjects'][$type_name])) {
64         $this -> config = $GLOBALS['LSobjects'][$type_name];
65       }
66       else {
67         $GLOBALS['LSerror'] -> addErrorCode(21);
68         return;
69       }
70     }
71     foreach($this -> config['attrs'] as $attr_name => $attr_config) {
72       if(!$this -> attrs[$attr_name]=new LSattribute($attr_name,$attr_config,$this)) {
73         return;
74       }
75     }
76     return true;
77   }
78   
79   /**
80    * Charge les données de l'objet
81    *
82    * Cette methode définis le DN de l'objet et charge les valeurs de attributs de l'objet
83    * Ã  partir de l'annuaire.
84    *
85    * @author Benjamin Renard <brenard@easter-eggs.com>
86    *
87    * @param[in] $dn string Le DN de l'objet.
88    *
89    * @retval boolean true si la chargement a réussi, false sinon.
90    */ 
91   function loadData($dn) {
92     $this -> dn = $dn;
93     $data = $GLOBALS['LSldap'] -> getAttrs($dn);
94     if(!empty($data)) {
95       foreach($this -> attrs as $attr_name => $attr) {
96         if(!$this -> attrs[$attr_name] -> loadData($data[$attr_name]))
97           return;
98       }
99       return true;
100     }
101     return;
102   }
103   
104   /**
105    * Recharge les données de l'objet
106    *
107    * @author Benjamin Renard <brenard@easter-eggs.com>
108    *
109    * @retval boolean true si la rechargement a réussi, false sinon.
110    */ 
111   function reloadData() {
112     $data = $GLOBALS['LSldap'] -> getAttrs($this -> dn);
113     foreach($this -> attrs as $attr_name => $attr) {
114       if(!$this -> attrs[$attr_name] -> reloadData($data[$attr_name]))
115         return;
116     }
117     return true;
118   }
119   
120   /**
121    * Retourne le format d'affichage de l'objet
122    *
123    * @author Benjamin Renard <brenard@easter-eggs.com>
124    *
125    * @retval string Format d'affichage de l'objet.
126    */ 
127   function getDisplayAttributes() {
128     return $this -> config['select_display_attrs'];
129   }
130   
131   /**
132    * Retourne la valeur descriptive d'affichage de l'objet
133    * 
134    * Cette fonction retourne la valeur descriptive d'affichage de l'objet en fonction
135    * du format défini dans la configuration de l'objet ou spécifié en paramètre.
136    *
137    * @author Benjamin Renard <brenard@easter-eggs.com>
138    *
139    * @param[in] $spe [<i>optionnel</i>] string Format d'affichage de l'objet
140    * @param[in] $full [<i>optionnel</i>] boolean True pour afficher en plus le
141    *                                             subDnName
142    *
143    * @retval string Valeur descriptive d'affichage de l'objet
144    */ 
145   function getDisplayValue($spe='',$full=false) {
146     if ($spe=='') {
147       $spe = $this -> getDisplayAttributes();
148     }
149     $val = $this -> getFData($spe,&$this -> attrs,'getDisplayValue');
150     if ($GLOBALS['LSsession'] -> haveSubDn() && $full) {
151       $val.=' ('.$this -> getSubDnName().')';
152     }
153     return $val;
154   }
155   
156   /**
157    * Chaine formatée
158    * 
159    * Cette fonction retourne la valeur d'une chaine formatée en prennant les valeurs
160    * de l'objet.
161    *
162    * @author Benjamin Renard <brenard@easter-eggs.com>
163    *
164    * @param[in] $format string Format de la chaine
165    *
166    * @retval string Valeur d'une chaine formatée
167    */ 
168   function getFData($format) {
169     $format=getFData($format,$this,'getValue');
170     return $format;
171   }
172   
173   /**
174    * Construit un formulaire de l'objet
175    * 
176    * Cette méthode construit un formulaire LSform Ã  partir de la configuration de l'objet
177    * et de chaque attribut.
178    *
179    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
180    * @param[in] $load DN d'un objet similaire dont la valeur des attribut doit Ãªtre chargé dans le formulaire.
181    *
182    * @author Benjamin Renard <brenard@easter-eggs.com>
183    *
184    * @retval LSform Le formulaire crée
185    */ 
186   function getForm($idForm,$load=NULL) {
187     $GLOBALS['LSsession'] -> loadLSclass('LSform');
188     $LSform = new LSform($this,$idForm);
189     $this -> forms[$idForm] = array($LSform,$load);
190     
191     if ($load) {
192       $type = $this -> getType();
193       $loadObject = new $type();
194       if (!$loadObject -> loadData($load)) {
195         $load=false;
196       }
197     }
198     
199     if ($load) {
200       foreach($this -> attrs as $attr_name => $attr) {
201         if(!$this -> attrs[$attr_name] -> addToForm($LSform,$idForm,$this,$loadObject -> getValue($attr_name))) {
202           $LSform -> can_validate = false;
203         }
204       }
205     }
206     else {
207       foreach($this -> attrs as $attr_name => $attr) {
208         if(!$this -> attrs[$attr_name] -> addToForm($LSform,$idForm,$this)) {
209           $LSform -> can_validate = false;
210         }
211       }      
212     }
213     return $LSform;
214   }
215   
216   /**
217    * Construit un formulaire de l'objet
218    * 
219    * Cette méthode construit un formulaire LSform Ã  partir de la configuration de l'objet
220    * et de chaque attribut.
221    *
222    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
223    * @param[in] $config Configuration spécifique pour le formulaire
224    *
225    * @author Benjamin Renard <brenard@easter-eggs.com>
226    *
227    * @retval LSform Le formulaire crée
228    */ 
229   function getView() {
230     $GLOBALS['LSsession'] -> loadLSclass('LSform');
231     $this -> view = new LSform($this,'view');
232     foreach($this -> attrs as $attr_name => $attr) {
233       $this -> attrs[$attr_name] -> addToView($this -> view);
234     }
235     $this -> view -> can_validate = false;
236     return $this -> view;
237   }  
238   
239   /**
240    * Rafraichis le formulaire de l'objet
241    * 
242    * Cette méthode recharge les données d'un formulaire LSform.
243    *
244    * @param[in] $idForm [<b>required</b>] Identifiant du formulaire a créer
245    *
246    * @author Benjamin Renard <brenard@easter-eggs.com>
247    *
248    * @retval boolean true sile formulaire a Ã©té rafraichis, false sinon
249    */ 
250   function refreshForm($idForm) {
251     $LSform = $this -> forms[$idForm][0];
252     foreach($this -> attrs as $attr_name => $attr) {
253       if(!$this -> attrs[$attr_name] -> refreshForm($LSform,$idForm)) {
254         return;
255       }
256     }
257     return true;
258   }
259   
260   /**
261    * Met Ã  jour les données de l'objet et de l'entré de l'annuaire
262    * 
263    * Met Ã  jour les données de l'objet Ã  partir d'un retour d'un formulaire.
264    *
265    * @param[in] $idForm Identifiant du formulaire d'origine
266    *
267    * @author Benjamin Renard <brenard@easter-eggs.com>
268    *
269    * @retval boolean true si la mise Ã  jour a réussi, false sinon
270    *
271    * @see validateAttrsData()
272    * @see submitChange()
273    */ 
274   function updateData($idForm=NULL) {
275     if($idForm!=NULL) {
276       if(isset($this -> forms[$idForm]))
277         $LSform = $this -> forms[$idForm][0];
278       else {
279         $GLOBALS['LSerror'] -> addErrorCode(22,$this -> getType());
280         return;
281       }
282     }
283     else {
284       if(count($this -> forms) > 0) {
285         reset($this -> forms);
286         $idForm = key($this -> forms);
287         $LSform = current($this -> forms);
288         $config = $LSform[1];
289         $LSform = $LSform[0];
290       }
291       else {
292         $GLOBALS['LSerror'] -> addErrorCode(23,$this -> getType());
293         return;
294       }
295     }
296     $new_data = $LSform -> exportValues();
297     if(!is_array($new_data)) {
298       return;
299     }
300     foreach($new_data as $attr_name => $attr_val) {
301       if(isset($this -> attrs[$attr_name])) {
302         $this -> attrs[$attr_name] -> setUpdateData($attr_val);
303       }
304     }
305     if($this -> validateAttrsData($idForm)) {
306       LSdebug("les données sont validées");
307       if(isset($this -> config['before_modify'])) {
308         if(function_exists($this -> config['before_modify'])) {
309           if(!$this -> config['before_modify']($this)) {
310             $GLOBALS['LSerror'] -> addErrorCode(28,$this -> config['before_modify']);
311             return;
312           }
313         }
314         else {
315           $GLOBALS['LSerror'] -> addErrorCode(27,$this -> config['before_modify']);
316           return;
317         }
318       }
319       // $this -> attrs[*] => before_modify
320       foreach($new_data as $attr_name => $attr_val) {
321         if(isset($this -> config['attrs'][$attr_name]['before_modify'])) {
322           if (!is_array($this -> config['attrs'][$attr_name]['before_modify'])) {
323             $funcs = array($this -> config['attrs'][$attr_name]['before_modify']);
324           }
325           else {
326             $funcs = $this -> config['attrs'][$attr_name]['before_modify'];
327           }
328           foreach($funcs as $func) {
329             if(function_exists($func)) {
330               if(!$func($this)) {
331                 $GLOBALS['LSerror'] -> addErrorCode(309,array('func' => $func,'attr' => $attr_name));
332                 return;
333               }
334             }
335             else {
336               $GLOBALS['LSerror'] -> addErrorCode(308,array('func' => $func,'attr' => $attr_name));
337               return;
338             }
339           }
340         }
341       }
342       
343       if ($this -> submitChange($idForm)) {
344         LSdebug('Les modifications sont submitées');
345         $this -> submitError = false;
346         $this -> reloadData();
347         $this -> refreshForm($idForm);
348       }
349       else {
350         return;
351       }
352       if((isset($this -> config['after_modify']))&&(!$this -> submitError)) {
353         if(function_exists($this -> config['after_modify'])) {
354           if(!$this -> config['after_modify']($this)) {
355             $GLOBALS['LSerror'] -> addErrorCode(30,$this -> config['after_modify']);
356             return;
357           }
358         }
359         else {
360           $GLOBALS['LSerror'] -> addErrorCode(29,$this -> config['after_modify']);
361           return;
362         }
363       }
364       
365       // $this -> attrs[*] => After Modify
366       foreach($new_data as $attr_name => $attr_val) {
367         if(isset($this -> config['attrs'][$attr_name]['after_modify'])) {
368           if (!is_array($this -> config['attrs'][$attr_name]['after_modify'])) {
369             $funcs = array($this -> config['attrs'][$attr_name]['after_modify']);
370           }
371           else {
372             $funcs = $this -> config['attrs'][$attr_name]['after_modify'];
373           }
374           foreach($funcs as $func) {
375             if(function_exists($func)) {
376               if(!$func($this)) {
377                 $GLOBALS['LSerror'] -> addErrorCode(307,array('func' => $func,'attr' => $attr_name));
378                 return;
379               }
380             }
381             else {
382               $GLOBALS['LSerror'] -> addErrorCode(306,array('func' => $func,'attr' => $attr_name));
383               return;
384             }
385           }
386         }
387       }
388       return true;
389     }
390     else {
391       return;
392     }
393   }
394   
395   /**
396    * Valide les données retournées par un formulaire
397    *
398    * @param[in] $idForm Identifiant du formulaire d'origine
399    *
400    * @author Benjamin Renard <brenard@easter-eggs.com>
401    *
402    * @retval boolean true si les données sont valides, false sinon
403    */ 
404   function validateAttrsData($idForm) {
405     $LSform=$this -> forms[$idForm][0];
406     foreach($this -> attrs as $attr) {
407       $attr_values = $attr -> getValue();
408       if (!$attr -> isValidate()) {
409         if($attr -> isUpdate()) {
410           if (!$this -> validateAttrData($LSform, $attr)) {
411             return;
412           }
413         }
414         else if( (empty($attr_values)) && ($attr -> isRequired()) ) { 
415           if ( $attr -> canBeGenerated()) {
416             if ($attr -> generateValue()) {
417               if (!$this -> validateAttrData($LSform, $attr)) {
418                 $GLOBALS['LSerror'] -> addErrorCode(48,$attr -> getLabel());
419                 return;
420               }
421             }
422             else {
423               $GLOBALS['LSerror'] -> addErrorCode(47,$attr -> getLabel());
424               return;
425             }
426           }
427           else {
428             $GLOBALS['LSerror'] -> addErrorCode(46,$attr -> getLabel());
429             return;
430           }
431
432         }
433       }
434     }
435     return true;
436   }
437
438    /**
439    * Valide les données d'un attribut
440    *
441    * @param[in] $LSForm Formulaire d'origine
442    * @param[in] &$attr Attribut Ã  valider
443    *
444    * @author Benjamin Renard <brenard@easter-eggs.com>
445    *
446    * @retval boolean true si les données sont valides, false sinon
447    */
448   function validateAttrData(&$LSform,&$attr) {
449     $vconfig=$attr -> getValidateConfig();
450
451     $data=$attr -> getUpdateData();
452     if(!is_array($data)) {
453       $data=array($data);
454     }
455
456     // Validation des valeurs de l'attribut
457     if(is_array($vconfig)) {
458       foreach($vconfig as $test) {
459         // Définition du basedn par défaut
460         if (!isset($test['basedn'])) {
461           $test['basedn']=$GLOBALS['LSsession']->topDn;
462         }
463
464         // Définition du message d'erreur
465         if (!empty($test['msg'])) {
466           $msg_error=getFData($test['msg'],$this,'getValue');
467         }
468         else {
469           $msg_error=getFData(_("L'attribut %{attr} n'est pas valide."),$attr -> getLabel());
470         }
471         foreach($data as $val) {
472           // validation par check LDAP
473           if((isset($test['filter'])||isset($test['basedn']))&&(isset($test['result']))) {
474             $sparams=(isset($test['scope']))?array('scope' => $test['scope']):array();
475             $this -> other_values['val']=$val;
476             $sfilter_user=(isset($test['basedn']))?getFData($test['filter'],$this,'getValue'):NULL;
477             if(isset($test['object_type'])) {
478               $test_obj = new $test['object_type']();
479               $sfilter=$test_obj->getObjectFilter();
480               $sfilter='(&'.$sfilter;
481               if($sfilter_user[0]=='(') {
482                 $sfilter=$sfilter.$sfilter_user.')';
483               }
484               else {
485                 $sfilter=$sfilter.'('.$sfilter_user.'))';
486               }
487             }
488             else {
489               $sfilter=$sfilter_user;
490             }
491             $sbasedn=(isset($test['basedn']))?getFData($test['basedn'],$this,'getValue'):NULL;
492             $ret=$GLOBALS['LSldap'] -> getNumberResult ($sfilter,$sbasedn,$sparams);
493             if($test['result']==0) {
494               if($ret!=0) {
495                 $LSform -> setElementError($attr,$msg_error);
496                 return;
497               }
498             }
499             else {
500               if($ret<0) {
501                 $LSform -> setElementError($attr,$msg_error);
502                 return;
503               }
504             }
505           }
506           // Validation par fonction externe
507           else if(isset($test['function'])) {
508             if (function_exists($test['function'])) {
509               if(!$test['function']($this)) {
510                 $LSform -> setElementError($attr,$msg_error);
511               return;
512               }
513             }
514             else {
515               $GLOBALS['LSerror'] -> addErrorCode(24,array('attr' => $attr->name,'obj' => $this->getType(),'func' => $test['function']));
516               return;
517             }
518           }
519           else {
520             $GLOBALS['LSerror'] -> addErrorCode(25,array('attr' => $attr->name,'obj' => $this->getType()));
521             return;
522           }
523         }
524       }
525     }
526     // Génération des valeurs des attributs dépendants
527     $dependsAttrs=$attr->getDependsAttrs();
528     if (!empty($dependsAttrs)) {
529       foreach($dependsAttrs as $dependAttr) {
530         if(!isset($this -> attrs[$dependAttr])){
531           $GLOBALS['LSerror'] -> addErrorCode(34,array('attr_depend' => $dependAttr, 'attr' => $attr -> getLabel()));
532           continue;
533         }
534         if($this -> attrs[$dependAttr] -> canBeGenerated()) {
535           if (!$this -> attrs[$dependAttr] -> generateValue()) {
536             $GLOBALS['LSerror'] -> addErrorCode(47,$this -> attrs[$dependAttr] -> getLabel());
537             return;
538           }
539         }
540         else {
541           $GLOBALS['LSerror'] -> addErrorCode(46,$this -> attrs[$dependAttr] -> getLabel());
542           return;
543         }
544       }
545     }
546
547     $attr -> validate();
548     unset($this -> other_values['val']);
549     return true;
550   }
551
552   /**
553    * Met Ã  jour les données modifiés dans l'annuaire
554    *
555    * @param[in] $idForm Identifiant du formulaire d'origine
556    *
557    * @author Benjamin Renard <brenard@easter-eggs.com>
558    *
559    * @retval boolean true si la mise Ã  jour a réussi, false sinon
560    */ 
561   function submitChange($idForm) {
562     $submitData=array();
563     $new = $this -> isNew();
564     foreach($this -> attrs as $attr) {
565       if(($attr -> isUpdate())&&($attr -> isValidate())) {
566         if(($attr -> name == $this -> config['rdn'])&&(!$new)) {
567           $new = true;
568           LSdebug('Rename');
569           if (!$this -> beforeRename()) {
570             $GLOBALS['LSerror'] -> addErrorCode(36);
571             return;
572           }
573           $oldDn = $this -> getDn();
574           $this -> dn = false;
575           $newDn = $this -> getDn();
576           if ($newDn) {
577             if (!$GLOBALS['LSldap'] -> move($oldDn,$newDn)) {
578               return;
579             }
580             $this -> dn = $newDn;
581             if (!$this -> afterRename($oldDn,$newDn)) {
582               $GLOBALS['LSerror'] -> addErrorCode(37);
583               return;
584             }
585           }
586           else {
587             return;
588           }
589         }
590         else {
591           $submitData[$attr -> name] = $attr -> getUpdateData();
592         }
593       }
594     }
595     if(!empty($submitData)) {
596       $dn=$this -> getDn();
597       if($dn) {
598         $this -> dn=$dn;
599         LSdebug($submitData);
600         if (!$GLOBALS['LSldap'] -> update($this -> getType(),$dn, $submitData)) {
601           return;
602         }
603         if ($new) {
604           if (!$this -> afterCreate()) {
605             $GLOBALS['LSerror'] -> addErrorCode(301);
606             return;
607           }
608         }
609         return true;
610       }
611       else {
612         $GLOBALS['LSerror'] -> addErrorCode(33);
613         return;
614       }
615     }
616     else {
617       return true;
618     }
619   }
620   
621   /**
622    * Retourne les informations issus d'un DN
623    *
624    * @param[in] $dn Un DN.
625    *
626    * @author Benjamin Renard <brenard@easter-eggs.com>
627    *
628    * @retval array Tableau : 
629    *                  - [0] : le premier paramètre
630    *                  - [1] : les paramètres suivants
631    */ 
632   function getDnInfos($dn) {
633     $infos=ldap_explode_dn($dn,0);
634     if(!$infos)
635       return;
636     $first=true;
637     for($i=1;$i<$infos['count'];$i++)
638       if($first) {
639         $basedn.=$infos[$i];
640         $first=false;
641       }
642       else
643         $basedn.=','.$infos[$i];
644     return array($infos[0],$basedn);
645   }
646   
647   /**
648    * Retourne le filtre correpondants aux objetcClass de l'objet
649    *
650    * @author Benjamin Renard <brenard@easter-eggs.com>
651    *
652    * @retval string le filtre ldap correspondant au type de l'objet
653    */ 
654   function getObjectFilter() {
655     if(!isset($this -> config['objectclass'])) return;
656     foreach ($this -> config['objectclass'] as $class)
657       $filter.='(objectClass='.$class.')';
658     return $filter;
659   }
660   
661   /**
662    * Retourne une liste d'objet du même type.
663    *
664    * Effectue une recherche en fonction des paramètres passé et retourne un
665    * tableau d'objet correspond au resultat de la recherche.
666    *
667    * @author Benjamin Renard <brenard@easter-eggs.com>
668    *
669    * @param[in] $filter array (ou string) Filtre de recherche Ldap / Tableau de filtres de recherche
670    * @param[in] $basedn string DN de base pour la recherche
671    * @param[in] $params array Paramètres de recherche au format Net_LDAP2::search()
672    *
673    * @retval array Tableau d'objets correspondant au resultat de la recherche
674    */ 
675   function listObjects($filter='',$basedn=NULL,$params=array()) {
676     $retInfos=array();
677     $attrs=false;
678     $check_final_dn=false;
679
680     if(!is_array($filter))
681       $filter=array(array('filter' => $filter));
682     
683     $nbFilter=count($filter);
684
685     for($i=0;$i<$nbFilter;$i++) {
686       $new_attrs=array();
687       // Défintion des paramètres de base pour la recherche
688       $sbasedn=$basedn;
689       $sparams=$params;
690       $ret=array();
691       if (isset($filter[$i]['scope']))
692         $sparams["scope"]=$filter[$i]['scope'];
693       
694       // Definition des critères de recherche correspondant au type d'objet Ã  lister
695       if(($nbFilter==1)||(!isset($filter[$i]['attr']))) {
696         // Filtre sur l'objet souhaité
697         $sfilter='(&';
698         $sfilter.=$this -> getObjectFilter();
699         $sfilter_end=')';
700         $check_final_dn=true;
701       }
702       // Initialisation des critères d'une recherche intermédiaire
703       else {
704         if(isset($filter[$i]['object_type'])) {
705           $obj_tmp=new $filter[$i]['object_type']();
706           $obj_filter=$obj_tmp->getObjectFilter();
707           $sfilter='(&'.$obj_filter;
708           $sfilter_end=')';
709         }
710         else {
711           $sfilter='';
712           $sfilter_end='';
713         }
714         if(isset($filter[$i]['scope'])) {
715           $sparams['scope']=$filter[$i]['scope'];
716         }
717         if(isset($filter[$i]['basedn'])) {
718           $sbasedn=$filter[$i]['basedn'];
719         }
720       }
721       // Dans le cas d'une recherche intermédiaire ou finale
722       if($attrs!=false) {
723         // Initialisation des variables
724         $ret_gen=array();
725         $new_attrs=array();
726         
727         // Pour tout les attributs retournés
728         for($ii=0;$ii<count($attrs);$ii++) {
729           $sfilter_for='';
730           // Définition du filtre de recherche Ã  partir des paramètres utilisateurs et
731           // des paramètres de recherche de l'objet Ã  listé (dans le cas d'une recherche finale
732           if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
733             $sfilter_user=getFData($filter[$i]['filter'],$attrs[$ii]);
734             if($sfilter_user[0]=='(')
735               $sfilter_for=$sfilter.$sfilter_user;
736             else
737               $sfilter_for=$sfilter.'('.$sfilter_user.')';
738           }
739           else {
740             $sfilter_for=$sfilter;
741           }
742           
743           if(isset($filter[$i]['basedn'])) {
744             $sbasedn=getFData($filter[$i]['basedn'],$attrs[$ii]);
745             if ((!$this -> isCompatibleDNs($sbasedn,$basedn))&&($check_final_dn)) continue;
746           }
747         
748           // Vérification de la compatibilité du basedn de la recherche et du basedn générale
749           // Finalisation du filtre
750           $sfilter_for.=$sfilter_end;
751         
752         
753           // Execution de la recherche
754           $ret=$GLOBALS['LSldap'] -> search ($sfilter_for,$sbasedn,$sparams);
755           
756           // Si il y un retour
757           if(isset($ret[0])) {
758             // si il ya une suite (recherche intermédiaire)
759             if($filter[$i]['attr']){
760               for($iii=0;$iii<count($ret);$iii++) {
761                 if(isset($ret[$iii]['attrs'][$filter[$i]['attr']])) {
762                   // cas de valeur multiple
763                   if(is_array($ret[$iii]['attrs'][$filter[$i]['attr']])) {
764                     foreach($ret[$iii]['attrs'][$filter[$i]['attr']] as $val_attr) {
765                       $new_attrs[]=$val_attr;
766                     }
767                   }
768                   // cas de valeur unique
769                   else {
770                     $new_attrs[]=$ret[$iii]['attrs'][$filter[$i]['attr']];
771                   }
772                 }
773               }
774             }
775             else {
776               // vérification de la compatibilité de la compatibilité du DN resultant
777               // et du basedn de recherche 
778               if (!$this -> isCompatibleDNs($ret[0]['dn'],$basedn))
779                 continue;
780               // ajout du DN au resultat finale
781               $ret_gen[]=$ret[0]['dn'];
782             }
783           }
784         }
785         // cas du dernier filtre
786         if(!empty($ret_gen)) {
787           // on quitte la boucle des filtres de la conf
788           $ret=$ret_gen;
789           break;
790         }
791         // dans le cas d'une suite prévu mais d'un retour nul de la précédente recherche
792         else if(empty($new_attrs)) {
793             // retour vide et arrêt de la recherche
794             $ret=array();
795             break;
796         }
797         else {
798           $attrs=$new_attrs;
799         }
800       }
801       // Dans le cas de la recherche initiale
802       else {
803         // Déclaration du filtre de recherche
804         if((isset($filter[$i]['filter']))&&(!empty($filter[$i]['filter']))) {
805           if($filter[$i]['filter'][0]=='(') {
806             $sfilter.=$filter[$i]['filter'];
807           }
808           else {
809             $sfilter.='('.$filter[$i]['filter'].')';
810           }
811         }
812         // fermeture du filtre
813         $sfilter.=$sfilter_end;
814         
815         // Lancement de la recherche
816         $ret=$GLOBALS['LSldap'] -> search ($sfilter,$sbasedn,$sparams);
817         
818         //Si filtre multiple => on recupère une liste d'attributs
819         if(isset($filter[$i]['attr'])) {
820           for($ii=0;$ii<count($ret);$ii++) {
821             if(isset($ret[$ii]['attrs'][$filter[$i]['attr']])) {
822               // cas de valeur multiple
823               if(is_array($ret[$ii]['attrs'][$filter[$i]['attr']])) {
824                 foreach($ret[$ii]['attrs'][$filter[$i]['attr']] as $val_attr) {
825                   $attrs[]=$val_attr;
826                 }
827               }
828               // cas de valeur unique
829               else {
830                 $attrs[]=$ret[$ii]['attrs'][$filter[$i]['attr']];
831               }
832             }
833           }
834           
835           // Si aucunne valeur n'est retournées
836           if(empty($attrs)){
837             // arrêt et retour Ã  zéro
838             $ret=array();
839             break;
840           }
841         }
842         // Si recherche unique
843         else {
844           // préparation du retour finale
845           if (is_array($ret)) {
846             $ret_final=array();
847             foreach($ret as $obj)
848               $ret_final[]=$obj['dn'];
849             $ret=$ret_final;
850           }
851           else {
852             $ret=array();
853           }
854           break;
855         }
856       }
857     }
858     
859     // Création d'un tableau d'objet correspondant au valeur retourné
860     for($i=0;$i<count($ret);$i++) {
861       $retInfos[$i] = new $this -> type_name($this -> config);
862       $retInfos[$i] -> loadData($ret[$i]);
863     }
864     
865     return $retInfos;
866   }
867  
868  
869   /**
870    * Recherche un objet à partir de la valeur exact de son RDN
871    * 
872    * @author Benjamin Renard <brenard@easter-eggs.com>
873    * 
874    * @param[in] $name string Valeur de son RDN
875    * @param[in] $basedn string Le DN de base de la recherche
876    * 
877    * @retval array Tableau d'objets correspondant au resultat de la recherche
878    */
879   function searchObject($name,$basedn=NULL) {
880     $filter = $this -> config['rdn'].'='.$name; 
881     return $this -> listObjects($filter,$basedn); 
882   }
883
884   /**
885    * Retourne une valeur de l'objet
886    *
887    * Retourne une valeur en fonction du paramètre. Si la valeur est inconnue, la valeur retourné est ' '.
888    * tableau d'objet correspond au resultat de la recherche.
889    *
890    * Valeurs possibles :
891    * - 'dn' ou '%{dn} : DN de l'objet
892    * - [nom d'un attribut] : valeur de l'attribut
893    * - [clef de $this -> other_values] : valeur de $this -> other_values
894    *
895    * @author Benjamin Renard <brenard@easter-eggs.com>
896    *
897    * @param[in] $val string Le nom de la valeur demandée
898    *
899    * @retval mixed la valeur demandé ou ' ' si celle-ci est inconnue.
900    */ 
901   function getValue($val) {
902     if(($val=='dn')||($val=='%{dn}')) {
903       return $this -> dn;
904     }
905     else if(($val=='rdn')||($val=='%{rdn}')) {
906       return $this -> attrs[ $this -> config['rdn'] ] -> getValue();
907     }
908     else if(($val=='subDn')||($val=='%{subDn}')) {
909       return $this -> getSubDnValue();
910     }
911     else if(($val=='subDnName')||($val=='%{subDnName}')) {
912       return $this -> getSubDnName();
913     }
914     else if(isset($this ->  attrs[$val])){
915       if (method_exists($this ->  attrs[$val],'getValue'))
916         return $this -> attrs[$val] -> getValue();
917       else
918         return ' ';
919     }
920     else if(isset($this -> other_values[$val])){
921       return $this -> other_values[$val];
922     }
923     else {
924       return ' ';
925     }
926   }
927
928   /**
929    * Retourn un tableau pour un select d'un objet du même type
930    * 
931    * @author Benjamin Renard <brenard@easter-eggs.com>
932    *
933    * @retval array('dn' => 'display')
934    */
935   function getSelectArray($topDn=NULL) {
936     $list = $this -> listObjects(NULL,$topDn);
937     $return=array();
938     foreach($list as $object) {
939       $return[$object -> getDn()] = $object -> getDisplayValue(); 
940     }
941     return $return;
942   }
943
944   /**
945    * Retourne le DN de l'objet
946    *
947    * Cette methode retourne le DN de l'objet. Si celui-ci n'existe pas, il le construit Ã  partir de la 
948    * configuration de l'objet et la valeur de son attribut rdn.
949    *
950    * @author Benjamin Renard <brenard@easter-eggs.com>
951    *
952    * @retval string Le DN de l'objet
953    */   
954   function getDn() {
955     if($this -> dn) {
956       return $this -> dn;
957     }
958     else {
959       $rdn_attr=$this -> config['rdn'];
960       if( (isset($this -> config['rdn'])) && (isset($this -> attrs[$rdn_attr])) && (isset($this -> config['container_dn'])) && (isset($GLOBALS['LSsession']->topDn)) ) {
961         $rdn_val=$this -> attrs[$rdn_attr] -> getUpdateData();
962         if (!empty($rdn_val)) {
963           return $rdn_attr.'='.$rdn_val[0].','.$this -> config['container_dn'].','.$GLOBALS['LSsession']->topDn;
964         }
965         else {
966           $GLOBALS['LSerror'] -> addErrorCode(32,$this -> config['rdn']);
967           return;
968         }
969       }
970       else {
971         $GLOBALS['LSerror'] -> addErrorCode(31,$this -> getType());
972         return;
973       }
974     }
975   }
976
977   /**
978    * Retourne le type de l'objet
979    *
980    * @author Benjamin Renard <brenard@easter-eggs.com>
981    * 
982    * @retval string Le type de l'objet ($this -> type_name)
983    */
984   function getType() {
985     return $this -> type_name;
986   }
987   
988   /**
989    * Retourne qui est l'utilisateur par rapport Ã  cet object
990    *
991    * @author Benjamin Renard <brenard@easter-eggs.com>
992    * 
993    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
994    */
995   function whoami() {
996     if (!$this -> _whoami)
997       $this -> _whoami = $GLOBALS['LSsession'] -> whoami($this -> dn);
998     return $this -> _whoami;
999   }
1000   
1001   /**
1002    * Retourne le label de l'objet
1003    *
1004    * @author Benjamin Renard <brenard@easter-eggs.com>
1005    * 
1006    * @retval string Le label de l'objet ($this -> config['label'])
1007    */
1008   function getLabel() {
1009     return $this -> config['label'];
1010   }
1011   
1012   
1013   /**
1014    * Supprime l'objet dans l'annuaire
1015    *
1016    * @author Benjamin Renard <brenard@easter-eggs.com>
1017    * 
1018    * @retval boolean True si l'objet Ã  Ã©té supprimé, false sinon
1019    */
1020   function remove() {
1021     if ($this -> beforeDelete()) {
1022       if ($GLOBALS['LSldap'] -> remove($this -> getDn())) {
1023         if ($this -> afterDelete()) {
1024           return true;
1025         }
1026         $GLOBALS['LSerror'] -> addErrorCode(39);
1027       }
1028     }
1029     else {
1030       $GLOBALS['LSerror'] -> addErrorCode(38);
1031     }
1032     return;
1033   }
1034   
1035   /**
1036    * L'objet est-il nouveau
1037    * 
1038    * @author Benjamin Renard <brenard@easter-eggs.com>
1039    * 
1040    * @retval boolean True si l'objet est nouveau, false sinon
1041    */
1042   function isNew() {
1043     return (!$this -> dn);
1044   }
1045
1046   /**
1047    * Retourne la valeur (DN) du subDn de l'objet  
1048    * 
1049    * @return string La valeur du subDn de l'object
1050    */
1051   function getSubDnValue() {
1052     if ($this -> _subDn_value) {
1053       return $this -> _subDn_value;
1054     }
1055     $dn = $this -> getValue('dn');
1056     $subDn_value='';
1057     $subDnLdapServer = $GLOBALS['LSsession'] -> getSortSubDnLdapServer();
1058     foreach ($subDnLdapServer as $subDn => $subDn_name) {
1059       if (isCompatibleDNs($subDn,$dn)&&($subDn!=$dn)) {
1060         $subDn_value=$subDn;
1061         break;
1062       }
1063     }
1064     $this -> _subDn_value = $subDn_value;
1065     return $subDn_value;
1066   }
1067
1068   /**
1069    * Retourne la nom du subDn de l'objet  
1070    * 
1071    * @return string Le nom du subDn de l'object
1072    */
1073   function getSubDnName() {
1074     $subDnLdapServer = $GLOBALS['LSsession'] -> getSortSubDnLdapServer();
1075     return $subDnLdapServer[$this -> getSubDnValue()];
1076   }
1077   
1078   /**
1079    * Methode créant la liste des objets en relations avec l'objet courant et qui
1080    * la met en cache ($this -> _relationsCache)
1081    * 
1082    * @retval True en cas de cas ce succès, False sinon.
1083    */
1084   function updateRelationsCache() {
1085     $this -> _relationsCache=array();
1086     if (is_array($this->config['relations'])) {
1087       $type = $this -> getType();
1088       $me = new $type();
1089       $me -> loadData($this -> getDn());
1090       foreach($this->config['relations'] as $relation_name => $relation_conf) {
1091         if ( isset($relation_conf['list_function']) ) {
1092           if ($GLOBALS['LSsession'] -> loadLSobject($relation_conf['LSobject'])) {
1093             $obj = new $relation_conf['LSobject']();
1094             if ((method_exists($obj,$relation_conf['list_function']))&&(method_exists($obj,$relation_conf['getkeyvalue_function']))) {
1095               $list = $obj -> $relation_conf['list_function']($me);
1096               if (is_array($list)) {
1097                 // Key Value
1098                 $key = $obj -> $relation_conf['getkeyvalue_function']($me);
1099                 
1100                 $this -> _relationsCache[$relation_name] = array(
1101                   'list' => $list,
1102                   'keyvalue' => $key
1103                 );
1104               }
1105               else {
1106                 LSdebug('Problème durant la mise en cache de la relation '.$relation_name);
1107                 return;
1108               }
1109             }
1110             else {
1111               LSdebug('Les méthodes de mise en cache de la relation '.$relation_name. ' ne sont pas toutes disponibles.');
1112               return;
1113             }
1114           }
1115           else {
1116             $GLOBALS['LSerror'] -> addErrorCode(1004,$relation_conf['LSobject']);
1117             return;
1118           }
1119         }
1120       }
1121     }
1122     return true;
1123   }
1124   
1125   /**
1126    * Methode executant les actions nécéssaires avant le changement du DN de
1127    * l'objet.
1128    * 
1129    * Cette méthode n'est qu'un exemple et elle doit être certainement réécrite
1130    * pour les objets plus complexe.
1131    * 
1132    * @retval True en cas de cas ce succès, False sinon.
1133    */
1134   function beforeRename() {
1135     return $this -> updateRelationsCache();
1136   }
1137   
1138   /**
1139    * Methode executant les actions nécéssaires après le changement du DN de
1140    * l'objet.
1141    * 
1142    * Cette méthode n'est qu'un exemple et elle doit être certainement réécrite
1143    * pour les objets plus complexe.
1144    * 
1145    * @param[in] $oldDn string L'ancien DN de l'objet
1146    * @param[in] $newDn string Le nouveau DN de l'objet
1147    * 
1148    * @retval True en cas de cas ce succès, False sinon.
1149    */
1150   function afterRename($oldDn,$newDn) {
1151     $error = 0;
1152     if($GLOBALS['LSsession'] -> dn == $oldDn) {
1153       $GLOBALS['LSsession'] -> changeAuthUser($this);
1154     }
1155     
1156     foreach($this -> _relationsCache as $relation_name => $objInfos) {
1157       if ((isset($this->config['relations'][$relation_name]['rename_function']))&&(is_array($objInfos['list']))) {
1158         foreach($objInfos['list'] as $obj) {
1159           $meth = $this->config['relations'][$relation_name]['rename_function'];
1160           if (method_exists($obj,$meth)) {
1161             if (!($obj -> $meth($this,$objInfos['keyvalue']))) {
1162               $error=1;
1163             }
1164           }
1165           else {
1166             $error=1;
1167           }
1168         }
1169       }
1170     }
1171     return !$error;
1172   }
1173   
1174   /**
1175    * Methode executant les actions nécéssaires avant la suppression de
1176    * l'objet.
1177    * 
1178    * Cette méthode n'est qu'un exemple et elle doit être certainement réécrite
1179    * pour les objets plus complexe.
1180    * 
1181    * @retval True en cas de cas ce succès, False sinon.
1182    */
1183   function beforeDelete() {
1184     return $this -> updateRelationsCache();
1185   }
1186   
1187   /**
1188    * Methode executant les actions nécéssaires après la suppression de
1189    * l'objet.
1190    * 
1191    * Cette méthode n'est qu'un exemple et elle doit être certainement réécrite
1192    * pour les objets plus complexe.
1193    * 
1194    * @retval True en cas de cas ce succès, False sinon.
1195    */
1196   function afterDelete() {
1197     $error = 0;
1198     foreach($this -> _relationsCache as $relation_name => $objInfos) {
1199       if ((isset($this->config['relations'][$relation_name]['remove_function']))&&(is_array($objInfos['list']))) {
1200         foreach($objInfos['list'] as $obj) {
1201           $meth = $this->config['relations'][$relation_name]['remove_function'];
1202           if (method_exists($obj,$meth)) {
1203             if (!($obj -> $meth($this))) {
1204               $error=1;
1205             }
1206           }
1207           else {
1208             $error=1;
1209           }
1210         }
1211       }
1212     }
1213     
1214     if (isset($this -> config['after_delete'])) {
1215       if (is_array($this -> config['after_delete'])) {
1216         $config = $this -> config['after_delete'];
1217       }
1218       else {
1219         $config = array($this -> config['after_delete']);
1220       }
1221       foreach($config as $action) {
1222         if(function_exists($action)) {
1223           if(!$action($this)) {
1224             $GLOBALS['LSerror'] -> addErrorCode(305,$action);
1225             $error=true;
1226           }
1227         }
1228         else {
1229           $GLOBALS['LSerror'] -> addErrorCode(304,$action);
1230           $error=true;
1231         }
1232       }
1233     }
1234     
1235     return !$error;
1236   }
1237   
1238   /**
1239    * Methode executant les actions nécéssaires après la création de
1240    * l'objet.
1241    * 
1242    * Cette méthode n'est qu'un exemple et elle doit être certainement réécrite
1243    * pour les objets plus complexe.
1244    * 
1245    * @retval True en cas de cas ce succès, False sinon.
1246    */
1247   function afterCreate() {
1248     LSdebug('after');
1249     $error = 0;
1250     if ($GLOBALS['LSsession'] -> isSubDnLSobject($this -> getType())) {
1251       if (is_array($GLOBALS['LSsession'] -> ldapServer['subDn']['LSobject'][$this -> getType()]['LSobjects'])) {
1252         foreach($GLOBALS['LSsession'] -> ldapServer['subDn']['LSobject'][$this -> getType()]['LSobjects'] as $type) {
1253           if ($GLOBALS['LSsession'] -> loadLSobject($type)) {
1254             if (isset($GLOBALS['LSobjects'][$type]['container_auto_create'])&&isset($GLOBALS['LSobjects'][$type]['container_dn'])) {
1255               $dn = $GLOBALS['LSobjects'][$type]['container_dn'].','.$this -> getDn();
1256               if(!$GLOBALS['LSldap'] -> getNewEntry($dn,$GLOBALS['LSobjects'][$type]['container_auto_create']['objectclass'],$GLOBALS['LSobjects'][$type]['container_auto_create']['attrs'],true)) {
1257                 LSdebug("Impossible de créer l'entrée fille : ".print_r(
1258                   array(
1259                     'dn' => $dn,
1260                     'objectClass' => $GLOBALS['LSobjects'][$type]['container_auto_create']['objectclass'],
1261                     'attrs' => $GLOBALS['LSobjects'][$type]['container_auto_create']['attrs']
1262                   )
1263                 ,true));
1264                 $error=1;
1265               }
1266             }
1267           }
1268           else {
1269             $GLOBALS['LSerror'] -> addErrorCode(1004,$type);
1270             $error=1;
1271           }
1272         }
1273       }
1274     }
1275     
1276     if (isset($this -> config['after_create'])) {
1277       if (is_array($this -> config['after_create'])) {
1278         $config = $this -> config['after_create'];
1279       }
1280       else {
1281         $config = array($this -> config['after_create']);
1282       }
1283       foreach($config as $action) {
1284         if(function_exists($action)) {
1285           if(!$action($this)) {
1286             $GLOBALS['LSerror'] -> addErrorCode(303,$action);
1287             $error=true;
1288           }
1289         }
1290         else {
1291           $GLOBALS['LSerror'] -> addErrorCode(302,$action);
1292           $error=true;
1293         }
1294       }
1295     }
1296     
1297     return !$error;
1298   }
1299   
1300   /**
1301    * Retourne la valeur clef d'un objet en relation
1302    * 
1303    * @param[in] $object Un object de type $objectType
1304    * @param[in] $attr L'attribut dans lequel l'objet doit apparaitre
1305    * @param[in] $objectType Le type d'objet en relation
1306    * @param[in] $value La valeur que doit avoir l'attribut :
1307    *                      - soit le dn (par defaut)
1308    *                      - soit la valeur [0] d'un attribut
1309    * 
1310    * @retval Mixed La valeur clef d'un objet en relation
1311    **/
1312   function getObjectKeyValueInRelation($object,$attr,$objectType,$attrValue='dn') {
1313     if ((!$attr)||(!$objectType)) {
1314       $GLOBALS['LSerror'] -> addErrorCode(1021,'getObjectKeyValueInRelation');
1315       return;
1316     }
1317     if ($attrValue=='dn') {
1318       $val = $object -> getDn();
1319     }
1320     else {
1321       $val = $object -> getValue($attrValue);
1322       $val = $val[0];
1323     }
1324     return $val;
1325   }
1326   
1327   /**
1328    * Retourne la liste des relations pour l'objet en fonction de sa présence 
1329    * dans un des attributs
1330    * 
1331    * Retourne un tableau de d'objet (type : $objectType) correspondant à la 
1332    * relation entre l'objet $object et les objets de type $objectType. Cette relation
1333    * est établis par la présence de la valeur de référence à l'objet dans 
1334    * l'attribut des objets de type $objectType.
1335    * 
1336    * @param[in] $object Un object de type $objectType
1337    * @param[in] $attr L'attribut dans lequel l'objet doit apparaitre
1338    * @param[in] $objectType Le type d'objet en relation
1339    * @param[in] $value La valeur que doit avoir l'attribut :
1340    *                      - soit le dn (par defaut)
1341    *                      - soit la valeur [0] d'un attribut
1342    * 
1343    * @retval Array of $objectType Les objets en relations
1344    **/
1345   function listObjectsInRelation($object,$attr,$objectType,$attrValue='dn') {
1346     if ((!$attr)||(!$objectType)) {
1347       $GLOBALS['LSerror'] -> addErrorCode(1021,'listObjectsInRelation');
1348       return;
1349     }
1350     if ($attrValue=='dn') {
1351       $val = $object -> getDn();
1352     }
1353     else {
1354       $val = $object -> getValue($attrValue);
1355       $val = $val[0];
1356     }
1357     if ($val) {
1358       $filter = $this -> getObjectFilter();
1359       $filter = '(&'.$filter.'('.$attr.'='.$val.'))';
1360       return $this -> listObjects($filter,$GLOBALS['LSsession'] -> ldapServer['ldap_config']['basedn'],array('scope' => 'sub'));
1361     }
1362     return;
1363   }
1364
1365   /**
1366    * Ajoute un objet en relation dans l'attribut $attr de $this
1367    * 
1368    * @param[in] $object Un objet de type $objectType à ajouter
1369    * @param[in] $attr L'attribut dans lequel l'objet doit être ajouté
1370    * @param[in] $objectType Le type d'objet en relation
1371    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1372    *                      - soit le dn (par defaut)
1373    *                      - soit la valeur [0] d'un attribut
1374    * 
1375    * @retval boolean true si l'objet à été ajouté, False sinon
1376    **/  
1377   function addOneObjectInRelation($object,$attr,$objectType,$attrValue='dn') {
1378     if ((!$attr)||(!$objectType)) {
1379       $GLOBALS['LSerror'] -> addErrorCode(1021,'addOneObjectInRelation');
1380       return;
1381     }
1382     if ($object instanceof $objectType) {
1383       if ($this -> attrs[$attr] instanceof LSattribute) {
1384         if ($attrValue=='dn') {
1385           $val = $object -> getDn();
1386         }
1387         else {
1388           $val = $object -> getValue($attrValue);
1389           $val = $val[0];
1390         }
1391         $values = $this -> attrs[$attr] -> getValue();
1392         if ($this -> attrs[$attr] -> config['multiple']) {
1393           if (!is_array($values)) {
1394             $updateData = array($val);
1395           }
1396           else if (!in_array($val,$values)) {
1397             $values[]=$val;
1398             $updateData = $values;
1399           }
1400         }
1401         else {
1402           if (($values[0]!=$val)&&($values!=$val)) {
1403             $updateData = array($val);
1404           }
1405         }
1406         if (isset($updateData)) {
1407           return $GLOBALS['LSldap'] -> update($this -> getType(),$this -> getDn(), array($attr => $updateData));
1408         }
1409         return true;
1410       }
1411     }
1412     return;
1413   }
1414   
1415   /**
1416    * Supprime un objet en relation dans l'attribut $attr de $this
1417    * 
1418    * @param[in] $object Un objet de type $objectType à supprimer
1419    * @param[in] $attr L'attribut dans lequel l'objet doit être supprimé
1420    * @param[in] $objectType Le type d'objet en relation
1421    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1422    *                      - soit le dn (par defaut)
1423    *                      - soit la valeur [0] d'un attribut
1424    * 
1425    * @retval boolean true si l'objet à été supprimé, False sinon
1426    **/  
1427   function deleteOneObjectInRelation($object,$attr,$objectType,$attrValue='dn') {
1428     if ((!$attr)||(!$objectType)) {
1429       $GLOBALS['LSerror'] -> addErrorCode(1021,'deleteOneObjectInRelation');
1430       return;
1431     }
1432     if ($object instanceof $objectType) {
1433       if ($this -> attrs[$attr] instanceof LSattribute) {
1434         if ($attrValue=='dn') {
1435           $val = $object -> getDn();
1436         }
1437         else {
1438           $val = $object -> getValue($attrValue);
1439           $val = $val[0];
1440         }
1441         $values = $this -> attrs[$attr] -> getValue();
1442         if ((!is_array($values)) && (!empty($values))) {
1443           $values = array($values);
1444         }
1445         if (is_array($values)) {
1446           $updateData=array();
1447           foreach($values as $value) {
1448             if ($value!=$val) {
1449               $updateData[]=$value;
1450             }
1451           }
1452           return $GLOBALS['LSldap'] -> update($this -> getType(),$this -> getDn(), array($attr => $updateData));
1453         }
1454       }
1455     }
1456     return;
1457   }
1458   
1459  /**
1460   * Renome un objet en relation dans l'attribut $attr de $this
1461   * 
1462   * @param[in] $object Un objet de type $objectType à renomer
1463   * @param[in] $oldValue string L'ancienne valeur faisant référence à l'objet
1464   * @param[in] $attr L'attribut dans lequel l'objet doit être supprimé
1465   * @param[in] $objectType Le type d'objet en relation
1466   * @param[in] $attrValue La valeur que doit avoir l'attribut :
1467   *                      - soit le dn (par defaut)
1468   *                      - soit la valeur [0] d'un attribut
1469   *  
1470   * @retval boolean True en cas de succès, False sinon
1471   */
1472   function renameOneObjectInRelation($object,$oldValue,$attr,$objectType,$attrValue='dn') {
1473     if ((!$attr)||(!$objectType)) {
1474       $GLOBALS['LSerror'] -> addErrorCode(1021,'renameOneObjectInRelation');
1475       return;
1476     }
1477     if ($object instanceof $objectType) {
1478       if ($this -> attrs[$attr] instanceof LSattribute) {
1479         $values = $this -> attrs[$attr] -> getValue();
1480         if ((!is_array($values)) && (!empty($values))) {
1481           $values = array($values);
1482         }
1483         if (is_array($values)) {
1484           $updateData=array();
1485           foreach($values as $value) {
1486             if ($value!=$oldValue) {
1487               $updateData[] = $value;
1488             }
1489             else {
1490               if ($attrValue=='dn') {
1491                 $val = $object -> getDn();
1492               }
1493               else {
1494                 $val = $object -> getValue($attrValue);
1495                 $val = $val[0];
1496               }
1497               $updateData[] = $val;
1498             }
1499           }
1500           return $GLOBALS['LSldap'] -> update($this -> getType(),$this -> getDn(), array($attr => $updateData));
1501         }
1502       }
1503     }
1504     return;
1505   }
1506   
1507   /**
1508    * Met à jour les objets du meme type que $this en relation avec l'objet $object
1509    * de type $objectType en modifiant la valeur de leur attribut $attr des objets
1510    * en relation
1511    * 
1512    * @param[in] $object Mixed Un object (type : $this -> userObjectType) : l'utilisateur
1513    * @param[in] $listDns Array(string) Un tableau des DNs des objets en relation
1514    * @param[in] $attr L'attribut dans lequel l'utilisateur doit apparaitre
1515    * @param[in] $objectType Le type d'objet en relation
1516    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1517    *                      - soit le dn (par defaut)
1518    *                      - soit la valeur [0] d'un attribut
1519    * 
1520    * @retval boolean true si tout c'est bien passé, False sinon
1521    **/  
1522   function updateObjectsInRelation($object,$listDns,$attr,$objectType,$attrValue='dn') {
1523     if ((!$attr)||(!$objectType)) {
1524       $GLOBALS['LSerror'] -> addErrorCode(1021,'updateObjectsInRelation');
1525       return;
1526     }
1527     $currentObjects = $this -> listObjectsInRelation($object,$attr,$objectType,$attrValue);
1528     $type=$this -> getType();
1529     if(is_array($currentObjects)) {
1530       if (is_array($listDns)) {
1531         $values=array();
1532         if ($attrValue!='dn') {
1533           $obj=new $objectType();
1534           foreach ($listDns as $dn) {
1535             $obj -> loadData($dn);
1536             $val = $obj -> getValue($attrValue);
1537             $values[$dn] = $val[0];
1538           }
1539         }
1540         else {
1541           foreach($listDns as $dn) {
1542             $values[$dn] = $dn;
1543           }
1544         }
1545         $dontDelete=array();
1546         $dontAdd=array();
1547         for ($i=0;$i<count($currentObjects);$i++) {
1548           if ($attrValue=='dn') {
1549             $val = $currentObjects[$i] -> getDn();
1550           }
1551           else {
1552             $val = $currentObjects[$i] -> getValue($attrValue);
1553             $val = $val[0];
1554           }
1555           if (in_array($val, $listDns)) {
1556             $dontDelete[$i]=true;
1557             $dontAdd[]=$val;
1558           }
1559         }
1560         
1561         for($i=0;$i<count($currentObjects);$i++) {
1562           if ($dontDelete[$i]) {
1563             continue;
1564           }
1565           else {
1566             if (!$currentObjects[$i] -> deleteOneObjectInRelation($object,$attr,$objectType,$attrValue)) {
1567               return;
1568             }
1569           }
1570         }
1571         
1572         foreach($values as $dn => $val) {
1573           if (in_array($val,$dontAdd)) {
1574             continue;
1575           }
1576           else {
1577             $obj = new $type();
1578             if ($obj -> loadData($dn)) {
1579               if (!$obj -> addOneObjectInRelation($object,$attr,$objectType,$attrValue)) {
1580                 return;
1581               }
1582             }
1583             else {
1584               return;
1585             }
1586           }
1587         }
1588         return true;
1589       }
1590     }
1591     else {
1592       if(!is_array($listDns)) {
1593         return true;
1594       }
1595       foreach($listDns as $dn) {
1596         $obj = new $type();
1597         if ($obj -> loadData($dn)) {
1598           if (!$obj -> addOneObjectInRelation($object,$attr,$objectType,$attrValue)) {
1599             return;
1600           }
1601         }
1602         else {
1603           return;
1604         }
1605       }
1606     }
1607   }
1608   
1609 }
1610
1611 ?>