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