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