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