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