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