LSldapObject : Fixed a forgetfulness in last commit
[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] $attr L'attribut dans lequel l'objet doit apparaitre
1444    * @param[in] $objectType Le type d'objet en relation
1445    * @param[in] $value La valeur que doit avoir l'attribut :
1446    *                      - soit le dn (par defaut)
1447    *                      - soit la valeur [0] d'un attribut
1448    * 
1449    * @retval Mixed La valeur clef d'un objet en relation
1450    **/
1451   function getObjectKeyValueInRelation($object,$attr,$objectType,$attrValue='dn') {
1452     if ((!$attr)||(!$objectType)) {
1453       LSerror :: addErrorCode('LSrelations_05','getObjectKeyValueInRelation');
1454       return;
1455     }
1456     if ($attrValue=='dn') {
1457       $val = $object -> getDn();
1458     }
1459     else {
1460       $val = $object -> getValue($attrValue);
1461       $val = $val[0];
1462     }
1463     return $val;
1464   }
1465   
1466   /**
1467    * Retourne la liste des relations pour l'objet en fonction de sa présence 
1468    * dans un des attributs
1469    * 
1470    * Retourne un tableau de d'objet (type : $objectType) correspondant à la 
1471    * relation entre l'objet $object et les objets de type $objectType. Cette relation
1472    * est établis par la présence de la valeur de référence à l'objet dans 
1473    * l'attribut des objets de type $objectType.
1474    * 
1475    * @param[in] $object Un object de type $objectType
1476    * @param[in] $attr L'attribut dans lequel l'objet doit apparaitre
1477    * @param[in] $objectType Le type d'objet en relation
1478    * @param[in] $value La valeur que doit avoir l'attribut :
1479    *                      - soit le dn (par defaut)
1480    *                      - soit la valeur [0] d'un attribut
1481    * 
1482    * @retval Array of $objectType Les objets en relations
1483    **/
1484   function listObjectsInRelation($object,$attr,$objectType,$attrValue='dn') {
1485     if ((!$attr)||(!$objectType)) {
1486       LSerror :: addErrorCode('LSrelations_05','listObjectsInRelation');
1487       return;
1488     }
1489     if ($attrValue=='dn') {
1490       $val = $object -> getDn();
1491     }
1492     else {
1493       $val = $object -> getValue($attrValue);
1494       $val = $val[0];
1495     }
1496     if ($val) {
1497       $filter = Net_LDAP2_Filter::create($attr,'equals',$val);
1498       return $this -> listObjects($filter,LSsession :: getRootDn(),array('scope' => 'sub','recursive' => true,'withoutCache'=>true));
1499     }
1500     return;
1501   }
1502
1503   /**
1504    * Ajoute un objet en relation dans l'attribut $attr de $this
1505    * 
1506    * @param[in] $object Un objet de type $objectType à ajouter
1507    * @param[in] $attr L'attribut dans lequel l'objet doit être ajouté
1508    * @param[in] $objectType Le type d'objet en relation
1509    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1510    *                      - soit le dn (par defaut)
1511    *                      - soit la valeur [0] d'un attribut
1512    * @param[in] $canEditFunction  Le nom de la fonction pour vérifier que la
1513    *                              relation avec l'objet est éditable par le user
1514    * 
1515    * @retval boolean true si l'objet à été ajouté, False sinon
1516    **/  
1517   function addOneObjectInRelation($object,$attr,$objectType,$attrValue='dn',$canEditFunction=NULL) {
1518     if ((!$attr)||(!$objectType)) {
1519       LSerror :: addErrorCode('LSrelations_05','addOneObjectInRelation');
1520       return;
1521     }
1522     if ($object instanceof $objectType) {
1523       if ($canEditFunction) {
1524         if (!$this -> $canEditFunction()) {
1525           LSerror :: addErrorCode('LSsession_11');
1526           return;
1527         }
1528       }
1529       if ($this -> attrs[$attr] instanceof LSattribute) {
1530         if ($attrValue=='dn') {
1531           $val = $object -> getDn();
1532         }
1533         else {
1534           $val = $object -> getValue($attrValue);
1535           $val = $val[0];
1536         }
1537         $values = $this -> attrs[$attr] -> getValue();
1538         if ($this -> attrs[$attr] -> config['multiple']) {
1539           if (!is_array($values)) {
1540             $updateData = array($val);
1541           }
1542           else if (!in_array($val,$values)) {
1543             $values[]=$val;
1544             $updateData = $values;
1545           }
1546         }
1547         else {
1548           if (($values[0]!=$val)&&($values!=$val)) {
1549             $updateData = array($val);
1550           }
1551         }
1552         if (isset($updateData)) {
1553           return $this -> _updateData(array($attr => $updateData));
1554         }
1555         return true;
1556       }
1557     }
1558     return;
1559   }
1560   
1561   /**
1562    * Supprime un objet en relation dans l'attribut $attr de $this
1563    * 
1564    * @param[in] $object Un objet de type $objectType à supprimer
1565    * @param[in] $attr L'attribut dans lequel l'objet doit être supprimé
1566    * @param[in] $objectType Le type d'objet en relation
1567    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1568    *                      - soit le dn (par defaut)
1569    *                      - soit la valeur [0] d'un attribut
1570    * @param[in] $canEditFunction  Le nom de la fonction pour vérifier que la
1571    *                              relation avec l'objet est éditable par le user
1572    * 
1573    * @retval boolean true si l'objet à été supprimé, False sinon
1574    **/  
1575   function deleteOneObjectInRelation($object,$attr,$objectType,$attrValue='dn',$canEditFunction=NULL) {
1576     if ((!$attr)||(!$objectType)) {
1577       LSerror :: addErrorCode('LSrelations_05','deleteOneObjectInRelation');
1578       return;
1579     }
1580     if ($object instanceof $objectType) {
1581       if ($canEditFunction) {
1582         if (!$this -> $canEditFunction()) {
1583           LSerror :: addErrorCode('LSsession_11');
1584           return;
1585         }
1586       }
1587       if ($this -> attrs[$attr] instanceof LSattribute) {
1588         if ($attrValue=='dn') {
1589           $val = $object -> getDn();
1590         }
1591         else {
1592           $val = $object -> getValue($attrValue);
1593           $val = $val[0];
1594         }
1595         $values = $this -> attrs[$attr] -> getValue();
1596         if ((!is_array($values)) && (!empty($values))) {
1597           $values = array($values);
1598         }
1599         if (is_array($values)) {
1600           $updateData=array();
1601           foreach($values as $value) {
1602             if ($value!=$val) {
1603               $updateData[]=$value;
1604             }
1605           }
1606           return $this -> _updateData(array($attr => $updateData));
1607         }
1608       }
1609     }
1610     return;
1611   }
1612   
1613  /**
1614   * Renome un objet en relation dans l'attribut $attr de $this
1615   * 
1616   * @param[in] $object Un objet de type $objectType à renomer
1617   * @param[in] $oldValue string L'ancienne valeur faisant référence à l'objet
1618   * @param[in] $attr L'attribut dans lequel l'objet doit être supprimé
1619   * @param[in] $objectType Le type d'objet en relation
1620   * @param[in] $attrValue La valeur que doit avoir l'attribut :
1621   *                      - soit le dn (par defaut)
1622   *                      - soit la valeur [0] d'un attribut
1623   *  
1624   * @retval boolean True en cas de succès, False sinon
1625   */
1626   function renameOneObjectInRelation($object,$oldValue,$attr,$objectType,$attrValue='dn') {
1627     if ((!$attr)||(!$objectType)) {
1628       LSerror :: addErrorCode('LSrelations_05','renameOneObjectInRelation');
1629       return;
1630     }
1631     if ($object instanceof $objectType) {
1632       if ($this -> attrs[$attr] instanceof LSattribute) {
1633         $values = $this -> attrs[$attr] -> getValue();
1634         if ((!is_array($values)) && (!empty($values))) {
1635           $values = array($values);
1636         }
1637         if (is_array($values)) {
1638           $updateData=array();
1639           foreach($values as $value) {
1640             if ($value!=$oldValue) {
1641               $updateData[] = $value;
1642             }
1643             else {
1644               if ($attrValue=='dn') {
1645                 $val = $object -> getDn();
1646               }
1647               else {
1648                 $val = $object -> getValue($attrValue);
1649                 $val = $val[0];
1650               }
1651               $updateData[] = $val;
1652             }
1653           }
1654           return $this -> _updateData(array($attr => $updateData));
1655         }
1656       }
1657     }
1658     return;
1659   }
1660   
1661   /**
1662    * Met à jour les objets du meme type que $this en relation avec l'objet $object
1663    * de type $objectType en modifiant la valeur de leur attribut $attr des objets
1664    * en relation
1665    * 
1666    * @param[in] $object Mixed Un object (type : $this -> userObjectType) : l'utilisateur
1667    * @param[in] $listDns Array(string) Un tableau des DNs des objets en relation
1668    * @param[in] $attr L'attribut dans lequel l'utilisateur doit apparaitre
1669    * @param[in] $objectType Le type d'objet en relation
1670    * @param[in] $attrValue La valeur que doit avoir l'attribut :
1671    *                      - soit le dn (par defaut)
1672    *                      - soit la valeur [0] d'un attribut
1673    * @param[in] $canEditFunction  Le nom de la fonction pour vérifier que la
1674    *                              relation avec l'objet est éditable par le user
1675    * 
1676    * @retval boolean true si tout c'est bien passé, False sinon
1677    **/  
1678   function updateObjectsInRelation($object,$listDns,$attr,$objectType,$attrValue='dn',$canEditFunction=NULL) {
1679     if ((!$attr)||(!$objectType)) {
1680       LSerror :: addErrorCode('LSrelations_05','updateObjectsInRelation');
1681       return;
1682     }
1683     $currentObjects = $this -> listObjectsInRelation($object,$attr,$objectType,$attrValue);
1684     $type=$this -> getType();
1685     if(is_array($currentObjects)) {
1686       if (is_array($listDns)) {
1687         $values=array();
1688         if ($attrValue!='dn') {
1689           $obj=new $objectType();
1690           foreach ($listDns as $dn) {
1691             $obj -> loadData($dn);
1692             $val = $obj -> getValue($attrValue);
1693             $values[$dn] = $val[0];
1694           }
1695         }
1696         else {
1697           foreach($listDns as $dn) {
1698             $values[$dn] = $dn;
1699           }
1700         }
1701         $dontDelete=array();
1702         $dontAdd=array();
1703         for ($i=0;$i<count($currentObjects);$i++) {
1704           if ($attrValue=='dn') {
1705             $val = $currentObjects[$i] -> getDn();
1706           }
1707           else {
1708             $val = $currentObjects[$i] -> getValue($attrValue);
1709             $val = $val[0];
1710           }
1711           if (in_array($val, $listDns)) {
1712             $dontDelete[$i]=true;
1713             $dontAdd[]=$val;
1714           }
1715         }
1716         
1717         for($i=0;$i<count($currentObjects);$i++) {
1718           if ($dontDelete[$i]) {
1719             continue;
1720           }
1721           else {
1722             if (!$currentObjects[$i] -> deleteOneObjectInRelation($object,$attr,$objectType,$attrValue,$canEditFunction)) {
1723               return;
1724             }
1725           }
1726         }
1727         
1728         foreach($values as $dn => $val) {
1729           if (in_array($val,$dontAdd)) {
1730             continue;
1731           }
1732           else {
1733             $obj = new $type();
1734             if ($obj -> loadData($dn)) {
1735               if (!$obj -> addOneObjectInRelation($object,$attr,$objectType,$attrValue,$canEditFunction)) {
1736                 return;
1737               }
1738             }
1739             else {
1740               return;
1741             }
1742           }
1743         }
1744         return true;
1745       }
1746     }
1747     else {
1748       if(!is_array($listDns)) {
1749         return true;
1750       }
1751       foreach($listDns as $dn) {
1752         $obj = new $type();
1753         if ($obj -> loadData($dn)) {
1754           if (!$obj -> addOneObjectInRelation($object,$attr,$objectType,$attrValue,$canEditFunction)) {
1755             return;
1756           }
1757         }
1758         else {
1759           return;
1760         }
1761       }
1762     }
1763   }
1764   
1765   /**
1766    * Ajouter une action lors d'un événement
1767    * 
1768    * @param[in] $event string Le nom de l'événement
1769    * @param[in] $fct string Le nom de la fonction à exectuer
1770    * @param[in] $param mixed Paramètre pour le lancement de la fonction
1771    * @param[in] $class Nom de la classe possèdant la méthode $fct à executer
1772    * 
1773    * @retval void
1774    */
1775   function addEvent($event,$fct,$param=NULL,$class=NULL) {
1776     $this -> _events[$event][] = array(
1777       'function'  => $fct,
1778       'param'    => $param,
1779       'class'     => $class
1780     );
1781   }
1782   
1783   /**
1784    * Ajouter une action sur un objet lors d'un événement
1785    * 
1786    * @param[in] $event string Le nom de l'événement
1787    * @param[in] $obj object L'objet dont la méthode doit être executé
1788    * @param[in] $meth string Le nom de la méthode
1789    * @param[in] $param mixed Paramètre d'execution de la méthode
1790    * 
1791    * @retval void
1792    */
1793   function addObjectEvent($event,&$obj,$meth,$param=NULL) {
1794     $this -> _objectEvents[$event][] = array(
1795       'obj'  => $obj,
1796       'meth'  => $meth,
1797       'param'    => $param
1798     );
1799   }
1800   
1801   /**
1802    * Lance les actions à executer lors d'un événement
1803    * 
1804    * @param[in] $event string Le nom de l'événement
1805    * 
1806    * @retval boolean True si tout c'est bien passé, false sinon
1807    */
1808   function fireEvent($event) {
1809     
1810     // Object event
1811     $return = $this -> fireObjectEvent($event);
1812     
1813     // Config
1814     if(isset($this -> config[$event])) {
1815       if (!is_array($this -> config[$event])) {
1816         $funcs = array($this -> config[$event]);
1817       }
1818       else {
1819         $funcs = $this -> config[$event];
1820       }
1821       foreach($funcs as $func) {
1822         if(function_exists($func)) {
1823           if(!$func($this)) {
1824             $return = false;
1825             LSerror :: addErrorCode('LSldapObject_07',array('func' => $func,'event' => $event));
1826           }
1827         }
1828         else {
1829           $return = false;
1830           LSerror :: addErrorCode('LSldapObject_06',array('func' => $func,'event' => $event));
1831         }
1832       }
1833     }
1834     
1835     // Binding via addEvent
1836     if (is_array($this -> _events[$event])) {
1837       foreach ($this -> _events[$event] as $e) {
1838         if ($e['class']) {
1839           if (class_exists($e['class'])) {
1840             $obj = new $e['class']();
1841             if (method_exists($obj,$e['fct'])) {
1842               try {
1843                 $obj -> $e['fct']($e['param']);
1844               }
1845               catch(Exception $er) {
1846                 LSerror :: addErrorCode('LSldapObject_10',array('class' => $e['class'],'meth' => $e['fct'],'event' => $event));
1847                 $return = false;
1848               }
1849             }
1850             else {
1851               LSerror :: addErrorCode('LSldapObject_09',array('class' => $e['class'],'meth' => $e['fct'],'event' => $event));
1852               $return = false;
1853             }
1854           }
1855           else {
1856             LSerror :: addErrorCode('LSldapObject_08',array('class' => $e['class'],'meth' => $e['fct'],'event' => $event));
1857             $return = false;
1858           }
1859         }
1860         else {
1861           if (function_exists($e['fct'])) {
1862             try {
1863               $e['fct']($e['param']);
1864             }
1865             catch(Exception $er) {
1866               LSerror :: addErrorCode('LSldapObject_27',array('func' => $e['fct'],'event' => $event));
1867               $return = false;
1868             }
1869           }
1870           else {
1871             LSerror :: addErrorCode('LSldapObject_26',array('func' => $e['fct'],'event' => $event));
1872             $return = false;
1873           }
1874         }
1875       }
1876     }
1877     
1878     // Binding via addObjectEvent
1879     if (is_array($this -> _objectEvents[$event])) {
1880       foreach ($this -> _objectEvents[$event] as $e) {
1881         if (method_exists($e['obj'],$e['meth'])) {
1882           try {
1883             $e['obj'] -> $e['meth']($e['param']);
1884           }
1885           catch(Exception $er) {
1886             LSerror :: addErrorCode('LSldapObject_29',array('meth' => $e['meth'],'event' => $event));
1887             $return = false;
1888           }
1889         }
1890         else {
1891           LSerror :: addErrorCode('LSldapObject_28',array('meth' => $e['meth'],'event' => $event));
1892           $return = false;
1893         }
1894       }
1895     }
1896     
1897     return $return;
1898   }
1899   
1900   /**
1901    * Lance les actions à executer lors d'un événement sur l'objet lui-même
1902    * 
1903    * @param[in] $event string Le nom de l'événement
1904    * 
1905    * @retval boolean True si tout c'est bien passé, false sinon
1906    **/
1907   function fireObjectEvent($event) {
1908     switch($event) {
1909       case 'after_create':
1910         return $this -> afterCreate();
1911       case 'after_delete':
1912         return $this -> afterDelete();
1913       case 'after_rename':
1914         return $this -> afterRename();
1915       case 'after_modify':
1916         return $this -> afterModify();
1917 /*
1918       case 'before_create':
1919         return $this -> beforeCreate();
1920 */
1921       case 'before_delete':
1922         return $this -> beforeDelete();
1923       case 'before_rename':
1924         return $this -> beforeRename();
1925 /*
1926       case 'before_modify':
1927         return $this -> beforeModify();
1928 */
1929     }
1930     return true;
1931   }
1932   
1933   /**
1934    * Access to infos of the object
1935    * 
1936    * @param[in] $key string The name of the value
1937    * 
1938    * @retval mixed The value
1939    **/
1940   function __get($key) {
1941     if ($key=='subDnValue') {
1942       if ($this -> cache['subDnValue']) {
1943         return $this -> cache['subDnValue'];
1944       }
1945       $this -> cache['subDnValue'] = self :: getSubDnValue($this -> dn);
1946       return $this -> cache['subDnValue'];
1947     }
1948     if ($key=='subDnName') {
1949       if ($this -> cache['subDnName']) {
1950         return $this -> cache['subDnName'];
1951       }
1952       $this -> cache['subDnName'] = self :: getSubDnName($this -> dn);
1953       return $this -> cache['subDnName'];
1954     }
1955   }
1956   
1957 }
1958
1959 /**
1960  * Error Codes
1961  **/
1962 LSerror :: defineError('LSldapObject_01',
1963 _("LSldapObject : Object type unknown.")
1964 );
1965 LSerror :: defineError('LSldapObject_02',
1966 _("LSldapObject : Update form is not defined for the object %{obj}.")
1967 );
1968 LSerror :: defineError('LSldapObject_03',
1969 _("LSldapObject : No form exists for the object %{obj}.")
1970 );
1971 LSerror :: defineError('LSldapObject_04',
1972 _("LSldapObject : The function %{func} to validate the attribute %{attr} the object %{obj} is unknow.")
1973 );
1974 LSerror :: defineError('LSldapObject_05',
1975 _("LSldapObject : Configuration data are missing to validate the attribute %{attr} of the object %{obj}.")
1976 );
1977
1978 LSerror :: defineError('LSldapObject_06',
1979 _("LSldapObject : The function %{func} to be executed on the object event %{event} doesn't exist.")
1980 );
1981 LSerror :: defineError('LSldapObject_07',
1982 _("LSldapObject : The %{func} execution on the object event %{event} failed.")
1983 );
1984
1985 LSerror :: defineError('LSldapObject_08',
1986 _("LSldapObject : Class %{class}, which method %{meth} to be executed on the object event %{event}, doesn't exist.")
1987 );
1988 LSerror :: defineError('LSldapObject_09',
1989 _("LSldapObject : Method %{meth} within %{class} class to be executed on object event %{event}, doesn't exist.")
1990 );
1991 LSerror :: defineError('LSldapObject_10',
1992 _("LSldapObject : Error during execute %{meth} method within %{class} class, to be executed on object event %{event}.")
1993 );
1994
1995 LSerror :: defineError('LSldapObject_11',
1996 _("LSldapObject : Some configuration data of the object type %{obj} are missing to generate the DN of the new object.")
1997 );
1998 LSerror :: defineError('LSldapObject_12',
1999 _("LSldapObject : The attibute %{attr} of the object is not yet defined. Can't generate DN.")
2000 );
2001 LSerror :: defineError('LSldapObject_13',
2002 _("LSldapObject : Without DN, the object could not be changed.")
2003 );
2004 LSerror :: defineError('LSldapObject_14',
2005 _("LSldapObject : The attribute %{attr_depend} depending on the attribute %{attr} doesn't exist.")
2006 );
2007 LSerror :: defineError('LSldapObject_15',
2008 _("LSldapObject : Error during deleting the object %{objectname}.")
2009 );
2010
2011 LSerror :: defineError('LSldapObject_16',
2012 _("LSldapObject : Error during actions to be executed before renaming the objet.")
2013 );
2014 LSerror :: defineError('LSldapObject_17',
2015 _("LSldapObject : Error during actions to be executed after renaming the objet.")
2016 );
2017
2018 LSerror :: defineError('LSldapObject_18',
2019 _("LSldapObject : Error during actions to be executed before deleting the objet.")
2020 );
2021 LSerror :: defineError('LSldapObject_19',
2022 _("LSldapObject : Error during actions to be executed after deleting the objet.")
2023 );
2024
2025 LSerror :: defineError('LSldapObject_20',
2026 _("LSldapObject : Error during the actions to be executed before creating the object.")
2027 );
2028 LSerror :: defineError('LSldapObject_21',
2029 _("LSldapObject : Error during the actions to be executed after creating the object. It was created anyway.")
2030 );
2031
2032 LSerror :: defineError('LSldapObject_22',
2033 _("LSldapObject : The function %{func} to be executed before creating the object doesn't exist.")
2034 );
2035 LSerror :: defineError('LSldapObject_23',
2036 _("LSldapObject : Error executing the function %{func} to be execute after deleting the object.")
2037 );
2038 LSerror :: defineError('LSldapObject_24',
2039 _("LSldapObject : The function %{func} to be executed after deleting the object doesn't exist.")
2040 );
2041 LSerror :: defineError('LSldapObject_25',
2042 _("LSldapObject : Error executing the function %{func} to be execute after creating the object.")
2043 );
2044
2045 LSerror :: defineError('LSldapObject_26',
2046 _("LSldapObject : %{func} function, to be executed on object event %{event}, doesn't exist.")
2047 );
2048 LSerror :: defineError('LSldapObject_27',
2049 _("LSldapObject : Error during the execution of %{func} function on object event %{event}.")
2050 );
2051
2052 LSerror :: defineError('LSldapObject_28',
2053 _("LSldapObject : %{meth} method, to be executed on object event %{event}, doesn't exist.")
2054 );
2055 LSerror :: defineError('LSldapObject_29',
2056 _("LSldapObject : Error during execution of %{meth} method on object event %{event}.")
2057 );
2058 LSerror :: defineError('LSldapObject_30',
2059 _("LSldapObject : Error during generate LDAP filter for %{LSobject}.")
2060 );
2061
2062 // LSrelation
2063 LSerror :: defineError('LSrelations_05',
2064 _("LSrelation : Some parameters are missing in the call of methods to handle standard relations (Method : %{meth}).")
2065 );
2066
2067 ?>