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