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