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