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