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