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