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