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