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