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