44dd42ebc279eb20ebacb217eb411a4c48851ac9
[ldapsaisie.git] / public_html / includes / class / class.LSsearch.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 /**
24  * Object LSsearch
25  *
26  * @author Benjamin Renard <brenard@easter-eggs.com>
27  */
28 class LSsearch { 
29   
30   // The LdapObject type of search
31   private $LSobject=NULL;
32   
33   // The configuration of search
34   private $config;
35   
36   // The context of search
37   private $context;
38   
39   // The parameters of the search
40   private $params=array (
41     // Search params
42     'filter' => NULL,
43     'pattern' => NULL,
44     'predefinedFilter' => false,
45     'basedn' => NULL,
46     'subDn' => NULL,
47     'scope' => NULL,
48     'sizelimit' => 0,
49     'attronly' => false,    // If true, only attribute names are returned
50     'approx' => false,
51     'recursive' => false,
52     'attributes' => array(),
53     // Display params
54     'sortDirection' => NULL,
55     'sortBy' => NULL,
56     'sortlimit' => 0,
57     'displaySubDn' => NULL,
58     'displayFormat' => NULL,
59     'nbObjectsByPage' => NB_LSOBJECT_LIST,
60     'nbPageLinkByPage' => 10,
61     'customInfos' => array(),
62     'withoutCache' => false
63   );
64   
65   // The cache of search parameters
66   private $_searchParams = NULL;
67   
68   // The cache of the hash of the search parameters
69   private $_hash = NULL;
70   
71   // The result of the search
72   private $result=NULL;
73   
74   // Caches
75   private $_canCopy=NULL;
76   
77   /**
78    * Constructor
79    * 
80    * @param[in] $LSobject string The LdapObject type of search
81    * @param[in] $context string Context of search (LSrelation / LSldapObject/ ...)
82    * @param[in] $params array Parameters of search
83    * @param[in] $purgeParams boolean If params in session have to be purged
84    * 
85    **/
86   function LSsearch($LSobject,$context,$params=null,$purgeParams=false) {
87     if (!LSsession :: loadLSobject($LSobject)) {
88       return;
89     }
90     $this -> LSobject = $LSobject;
91     
92     $this -> loadConfig();
93     
94     if (isset($_REQUEST['LSsearchPurgeSession'])) {
95       $this -> purgeSession();
96     }
97     
98     $this -> context = $context;
99     
100     if (!$purgeParams) {
101       if (! $this -> loadParamsFromSession()) {
102         LSdebug('LSsearch : load default parameters');
103         $this -> loadDefaultParameters();
104       }
105     }
106     else {
107       $this -> purgeParams();
108       $this -> loadDefaultParameters();
109     }
110     
111     if (is_array($params)) {
112       $this -> setParams($params);
113     }
114     
115   }
116
117   /**
118    * Load configuration from LSconfig
119    * 
120    * @retval void
121    */
122   private function loadConfig() {
123     $this -> config = LSconfig::get("LSobjects.".$this -> LSobject.".LSsearch");
124   }
125   
126   /**
127    * Load default search parameters from configuration
128    * 
129    * @retval boolean True on success or False
130    */
131   private function loadDefaultParameters() {
132     if (is_array($this -> config['params'])) {
133       return $this -> setParams($this -> config['params']);
134     }
135     return true;
136   }
137   
138   /**
139    * Load search parameters from session
140    * 
141    * @retval boolean True if params has been loaded from session or False
142    */
143   private function loadParamsFromSession() {
144     LSdebug('LSsearch : load context params session '.$this -> context);
145     if (is_array($_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context])) {
146       $params = $_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context];
147       
148       if ($params['filter']) {
149         $params['filter'] = Net_LDAP2_Filter::parse($params['filter']);
150       }
151       
152       $this -> params = $params;
153       return true;
154     }
155     return;
156   }
157
158   /**
159    * Save search parameters in session
160    * 
161    * @retval void
162    */
163   private function saveParamsInSession() {
164     LSdebug('LSsearch : save context params session '.$this -> context);
165     $params = $this -> params;
166     if ($params['filter'] instanceof Net_LDAP2_Filter) {
167       $params['filter'] = $params['filter'] -> asString();
168     }
169     
170     foreach ($params as $param => $value) {
171       if ($_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context][$param]!=$value) {
172         LSdebug("S: $param => $value");
173         $_SESSION['LSsession']['LSsearch'][$this -> LSobject]['params'][$this -> context][$param]=$value;
174       }
175     }
176   }
177   
178   /**
179    * Purge parameters in session
180    * 
181    * @param[in] $LSobject string The LSobject type
182    * 
183    * @retval void
184    */
185   public function purgeParams($LSobject=NULL) {
186     if (is_null($LSobject)) {
187       $LSobject = $this -> LSobject;
188     }
189     unset($_SESSION['LSsession']['LSsearch'][$LSobject]['params']);
190   }
191   
192   /**
193    * Purge cache
194    * 
195    * @retval void
196    */
197   public function purgeCache($LSobject=NULL) {
198     if (is_null($LSobject))
199       $LSobject = $this -> LSobject;
200     unset($_SESSION['LSsession']['LSsearch'][$LSobject]);
201   }
202   
203   /**
204    * Purge session
205    * 
206    * @retval void
207    */
208   private function purgeSession() {
209     unset($_SESSION['LSsession']['LSsearch']);
210   }
211   
212   /**
213    * Define one search parameter
214    * 
215    * @param[in] $param string The parameter name
216    * @param[in] $value mixed The parameter value
217    * 
218    * @retval boolean True on success or False
219    */
220   public function setParam($param,$value) {
221     return $this -> setParams(array($param => $value));
222   }
223   
224   /**
225    * Define search parameters
226    * 
227    * @param[in] $params array Parameters of search
228    * 
229    * @retval boolean True on success or False
230    */
231   public function setParams($params) {
232     $OK=true;
233     
234     // Filter
235     if (is_string($params['filter'])) {
236       $filter = Net_LDAP2_Filter::parse($params['filter']);
237       if (!LSerror::isLdapError($filter)) {
238         $this -> params['filter'] = $filter;
239       }
240       else {
241         LSerror :: addErrorCode('LSsearch_01',$params['filter']);
242         $OK=false;
243       }
244     }
245     elseif($params['filter'] instanceof Net_LDAP2_Filter) {
246       $this -> params['filter'] =& $params['filter'];
247     }
248
249     // Approx
250     if (isset($params['approx'])) {
251       if (is_bool($params['approx']) || $params['approx']==0 || $params['approx']==1) {
252         $this -> params['approx'] = (bool)$params['approx'];
253       }
254       else {
255         LSerror :: addErrorCode('LSsearch_05','approx');
256         $OK=false;
257       }
258     }
259     
260     // Without Cache
261     if (isset($params['withoutCache'])) {
262       if (is_bool($params['withoutCache']) || $params['withoutCache']==0 || $params['withoutCache']==1) {
263         $this -> params['withoutCache'] = (bool)$params['withoutCache'];
264       }
265       else {
266         LSerror :: addErrorCode('LSsearch_05','withoutCache');
267         $OK=false;
268       }
269     }
270     
271     // Patterm
272     if (isset($params['pattern']) && $params['pattern']=="") {
273       $this -> params['pattern'] = NULL;
274       $this -> params['filter'] = NULL;
275     }
276     elseif (self :: isValidPattern($params['pattern'])) {
277       $this -> params['pattern'] = $params['pattern'];
278       if (!is_string($params['filter'])) {
279         $this -> params['filter']=NULL;
280       }
281     }
282     
283     
284     // BaseDN
285     if (is_string($params['basedn'])) {
286       if (isCompatibleDNs(LSsession :: getRootDn(),$params['basedn'])) {
287         $this -> params['basedn'] = $params['basedn'];
288       }
289       else {
290         LSerror :: addErrorCode('LSsearch_02',$params['basedn']);
291         $OK=false;
292       }
293     }
294     
295     // subDn
296     if (is_string($params['subDn'])) {
297       if (LSsession :: validSubDnLdapServer($params['subDn'])) {
298         $this -> params['subDn'] = $params['subDn'];
299       }
300       else {
301         LSerror :: addErrorCode('LSsearch_03','subDn');
302         $OK=false;
303       }
304     }
305     
306     // Scope
307     if (is_string($params['scope'])) {
308       if (in_array($params['scope'],array('sub','one','base'))) {
309         $this -> params['scope'] = $params['scope'];
310       }
311       else {
312         LSerror :: addErrorCode('LSsearch_03','scope');
313         $OK=false;
314       }
315     }
316     
317     // nbObjectsByPage
318     if (isset($params['nbObjectsByPage'])) {
319       if (((int)$params['nbObjectsByPage'])>1 ) {
320         $this -> params['nbObjectsByPage'] = (int)$params['nbObjectsByPage'];
321       }
322       else {
323         LSerror :: addErrorCode('LSsearch_03','nbObjectsByPage');
324         $OK=false;
325       }
326     }
327     
328     // Sort Limit
329     if (isset($params['sortlimit'])) {
330       if (is_int($params['sortlimit']) && $params['sortlimit']>=0 ) {
331         $this -> params['sortlimit'] = $params['sortlimit'];
332       }
333       elseif ((int)$params['sortlimit'] > 0) {
334         $this -> params['sortlimit'] = (int)$params['sortlimit'];
335       }
336       else {
337         LSerror :: addErrorCode('LSsearch_03','sortlimit');
338         $OK=false;
339       }
340     }
341     
342     // Sort Direction
343     if (is_string($params['sortDirection'])) {
344       if (in_array($params['sortDirection'],array('ASC','DESC'))) {
345         $this -> params['sortDirection'] = $params['sortDirection'];
346       }
347       else {
348         LSerror :: addErrorCode('LSsearch_03','sortDirection');
349         $OK=false;
350       }
351     }
352     
353     // Sort By
354     if (is_string($params['sortBy'])) {
355       if (in_array($params['sortBy'],array('displayName','subDn'))) {
356         if ($this -> params['sortBy'] == $params['sortBy']) {
357           $this -> toggleSortDirection();
358         }
359         else {
360           $this -> params['sortBy'] = $params['sortBy'];
361           if (!is_string($params['sortDirection'])) {
362             $this -> params['sortDirection']='ASC';
363           }
364         }
365       }
366       else {
367         LSerror :: addErrorCode('LSsearch_03','sortBy');
368         $OK=false;
369       }
370     }
371     
372     // Size Limit
373     if (isset($params['sizelimit'])) {
374       if (((int)$params['sizelimit']) >= 0) {
375         $this -> params['sizelimit'] = $params['sizelimit'];
376       }
377       else {
378         LSerror :: addErrorCode('LSsearch_04');
379         $OK=false;
380       }
381     }
382     
383     // Attronly
384     if (isset($params['attronly'])) {
385       if (is_bool($params['attronly']) || $params['attronly']==0 || $params['attronly']==1) {
386         $this -> params['attronly'] = (bool)$params['attronly'];
387       }
388       else {
389         LSerror :: addErrorCode('LSsearch_05','attronly');
390         $OK=false;
391       }
392     }
393     
394     // Recursive
395     if (isset($params['recursive'])) {
396       if (is_bool($params['recursive']) || $params['recursive']==0 || $params['recursive']==1) {
397         $this -> params['recursive'] = (bool)$params['recursive'];
398       }
399       else {
400         LSerror :: addErrorCode('LSsearch_05','recursive');
401         $OK=false;
402       }
403     }
404     
405     // displaySubDn
406     if (isset($params['displaySubDn'])) {
407       if (! LSsession :: isSubDnLSobject($this -> LSobject) ) {
408         if (is_bool($params['displaySubDn']) || $params['displaySubDn']==0 || $params['displaySubDn']==1) {
409           $this -> params['displaySubDn'] = (bool)$params['displaySubDn'];
410         }
411         else {
412           LSerror :: addErrorCode('LSsearch_05','displaySubDn');
413           $OK=false;
414         }
415       }
416     }
417     
418     // Attributes
419     if (isset($params['attributes'])) {
420       if (is_string($params['attributes'])) {
421         $this -> params['attributes'] = array($params['attributes']);
422       }
423       elseif (is_array($params['attributes'])) {
424         $this -> params['attributes']=array();
425         foreach ($this -> params['attributes'] as $attr) {
426           if (is_string($attr)) {
427             if (LSconfig::get("LSobjects.".$this -> LSobject.".attrs.$attr")) {;
428               $this -> params['attributes'][] = $attr;
429             }
430             else {
431               LSerror :: addErrorCode('LSsearch_11',$attr);
432             }
433           }
434         }
435       }
436       else {
437         LSerror :: addErrorCode('LSsearch_06');
438         $OK=false;
439       }
440     }
441
442     // predefinedFilter
443     if (isset($params['predefinedFilter'])) {
444       if (is_string($params['predefinedFilter'])) {
445         if (empty($params['predefinedFilter'])) {
446           $this->params['predefinedFilter']=false;
447         }
448         elseif(is_array($this -> config['predefinedFilters'])) {
449           if(isset($this->config['predefinedFilters'][$params['predefinedFilter']])) {
450             $this -> params['predefinedFilter'] = $params['predefinedFilter'];
451           }
452           else {
453             LSerror :: addErrorCode('LSsearch_03','predefinedFilter');
454             $OK=false;
455           }
456         }
457       }
458       else {
459         LSerror :: addErrorCode('LSsearch_03','predefinedFilter');
460         $OK=false;
461       }
462     }
463     
464     // Display Format
465     if (is_string($params['displayFormat'])) {
466       $this -> params['displayFormat'] = $params['displayFormat'];
467     }
468     
469     // Custom Infos
470     if (is_array($params['customInfos'])) {
471       foreach($params['customInfos'] as $name => $data) {
472         if(is_array($data['function']) && is_string($data['function'][0])) {
473           LSsession::loadLSclass($data['function'][0]);
474         }
475         if (is_callable($data['function'])) {
476           $this -> params['customInfos'][$name] = array (
477             'function' => &$data['function'],
478             'args' => $data['args']
479           );
480         }
481         else {
482           LSerror :: addErrorCode('LSsearch_14',$name);
483         }
484       }
485     }
486
487     $this -> saveParamsInSession();
488     return $OK;
489   }
490
491   /**
492    * Define search parameters by reading Post Data ($_REQUEST)
493    * 
494    * @retval void
495    */
496   public function setParamsFormPostData() {
497     $data = $_REQUEST;
498     
499     if (isset($data['LSsearch_submit'])) {
500       // Recursive 
501       if (is_null($data['recursive'])) {
502         $data['recursive']=false;
503       }
504       else {
505         $data['recursive']=true;
506       }
507       
508       // Approx 
509       if (is_null($data['approx'])) {
510         $data['approx']=false;
511       }
512       else {
513         $data['approx']=true;
514       }
515       
516       if (isset($data['ajax']) && !isset($data['pattern'])) {
517         $data['pattern']="";
518       }
519     }
520     
521     $this -> setParams($data);
522   }
523   
524   /**
525    * Toggle the sort direction
526    * 
527    * @retval void
528    **/
529   private function toggleSortDirection() {
530     if ($this -> params['sortDirection']=="ASC") {
531       $this -> params['sortDirection'] = "DESC";
532     }
533     else {
534       $this -> params['sortDirection'] = "ASC";
535     }
536   }
537   
538   /**
539    * Make a filter object with a pattern of search
540    *
541    * @param[in] $pattern The pattern of search. If is null, the pattern in params will be used.
542    * 
543    * @retval mixed Net_LDAP2_Filter on success or False
544    */ 
545   function getFilterFromPattern($pattern=NULL) {
546     if ($pattern==NULL) {
547       $pattern=$this -> params['pattern'];
548     }
549     if (self :: isValidPattern($pattern)) {
550       $operator=( ($params['approx'])?'approx':'contains' );
551       $attrsList=LSconfig::get("LSobjects.".$this -> LSobject.".LSsearch.attrs");
552       if (!is_array($attrsList)) {
553         $attrsList = array_keys(LSconfig::get("LSobjects.".$this -> LSobject.".attrs"));
554       }
555       
556       if (empty($attrsList)) {
557         LSerror :: addErrorCode('LSsearch_07');
558         return;
559       }
560       
561       $filters=array();
562       foreach ($attrsList as $attr) {
563         $filter=Net_LDAP2_Filter::create($attr,$operator,$pattern);
564         if (!Net_LDAP2::isError($filter)) {
565           $filters[]=$filter;
566         }
567         else {
568           LSerror :: addErrorCode('LSsearch_08',array('attr' => $attr,'pattern' => $pattern));
569           return;
570         }
571       }
572       if(!empty($filters)) {
573         $filter=LSldap::combineFilters('or',$filters);
574         if ($filter) {
575           return $filter;
576         }
577         else {
578           LSerror :: addErrorCode('LSsearch_09');
579         }
580       }
581     }
582     else {
583       LSerror :: addErrorCode('LSsearch_10');
584     }
585     return;
586   }
587   
588   /**
589    * Check if search pattern is valid
590    * 
591    * @param[in] $pattern string The pattern
592    * 
593    * @retval boolean True if pattern is valid or False
594    **/
595   static function isValidPattern($pattern) {
596     return (is_string($pattern) && $pattern!= "" && $pattern!="*");
597   }
598   
599   /**
600    * Check if cache is enabled
601    * 
602    * @retval boolean True if cache is enabled or False
603    **/
604   public function cacheIsEnabled() {
605     if (isset($this -> config['cache'])) {
606       $conf=$this -> config['cache'];
607       if (is_bool($conf) || $conf==0 || $conf==1) {
608         return (bool)$conf;
609       }
610       else {
611         LSerror :: addErrorCode('LSsearch_03','cache');
612       }
613     }
614     return LSsession :: cacheSearch();
615   }
616   
617   /**
618    * Methode for parameters value access
619    * 
620    * @param[in] $key string The parameter name
621    * 
622    * @retval mixed The parameter value or NULL
623    **/
624   public function getParam($key) {
625     if(in_array($key,array_keys($this -> params))) {
626       return $this -> params[$key];
627     }
628     return NULL;
629   }
630   
631   /**
632    * Return hidden fileds to add in search form
633    * 
634    * @retval array The hield fields whith their values
635    **/
636   public function getHiddenFieldForm() {
637     return array (
638       'LSobject' => $this -> LSobject
639     );
640   }
641   
642   /**
643    * Generate an array with search parameters, only parameters whitch have to be
644    * passed to Net_LDAP2 for the LDAP search. This array will be store in 
645    * $this -> _searchParams private variable.
646    * 
647    * @retval void
648    **/
649   private function generateSearchParams() {
650     // Purge the cache of the hash
651     $this -> _hash = NULL;
652     
653     // Base
654     $retval = array(
655       'filter' => $this -> params['filter'],
656       'basedn' => $this -> params['basedn'],
657       'scope' => $this -> params['scope'],
658       'sizelimit' => $this -> params['sizelimit'],
659       'attronly' => $this -> params['attronly'],
660       'attributes' => $this -> params['attributes']
661     );
662     
663     // Pattern
664     if (!is_null($this -> params['pattern'])) {
665       $filter=$this ->getFilterFromPattern();
666       if (is_null($retval['filter'])) {
667         $retval['filter']=$filter;
668       }
669       else {
670         $retval['filter']=LSldap::combineFilters('and',array($retval['filter'],$filter));
671       }
672     }
673     
674     // predefinedFilter
675     if (is_string($this -> params['predefinedFilter'])) {
676       if (!is_null($retval['filter'])) {
677         $filter=LSldap::combineFilters('and',array($this -> params['predefinedFilter'],$retval['filter']));
678         if ($filter) {
679           $retval['filter']=$filter;
680         }
681       }
682       else {
683         $retval['filter']=$this -> params['predefinedFilter'];
684       }
685     }
686     
687     // Filter
688     $objFilter=LSldapObject::getObjectFilter($this -> LSobject);
689     if ($objFilter) {
690       if (!is_null($retval['filter'])) {
691         $filter=LSldap::combineFilters('and',array($objFilter,$retval['filter']));
692         if ($filter) {
693           $retval['filter']=$filter;
694         }
695       }
696       else {
697         $retval['filter']=$objFilter;
698       }
699     }
700     
701     // Recursive
702     if (is_null($retval['basedn'])) {
703       if (!is_null($this -> params['subDn'])) {
704         if ($this -> params['recursive']) {
705           $retval['basedn'] = $this -> params['subDn'];
706         }
707         else {
708           $retval['basedn'] = LSconfig::get("LSobjects.".$this -> LSobject.".container_dn").','.$this -> params['subDn'];
709         }
710       }
711       else {
712         if ($this -> params['recursive']) {
713           $retval['basedn'] = LSsession :: getTopDn();
714         }
715         else {
716           $retval['basedn'] = LSconfig::get("LSobjects.".$this -> LSobject.".container_dn").','.LSsession :: getTopDn();
717         }
718       }
719     }
720     if ($this -> params['recursive'] || !isset($retval['scope'])) {
721       $retval['scope'] = 'sub';
722     }
723     
724     if (is_null($this -> params['displayFormat'])) {
725       $this -> params['displayFormat']=LSconfig::get("LSobjects.".$this -> LSobject.".display_name_format");
726     }
727     
728     // Display Format
729     $attrs=getFieldInFormat($this -> params['displayFormat']);
730     if(is_array($retval['attributes'])) {
731       $retval['attributes']=array_merge($attrs,$retval['attributes']);
732     }
733     else {
734       $retval['attributes']=$attrs;
735     }
736     
737     $this -> _searchParams = $retval;
738   }
739   
740   /**
741    * Run the search
742    *
743    * @param[in] $cache boolean Define if the cache can be used
744    * 
745    * @retval boolean True on success or False
746    */ 
747   public function run($cache=true) {
748     $this -> generateSearchParams();
749     if ($this -> _searchParams['filter'] instanceof Net_LDAP2_Filter) {
750       LSdebug('LSsearch : filter : '.$this -> _searchParams['filter']->asString());
751     }
752     LSdebug('LSsearch : basedn : '.$this -> _searchParams['basedn'].' - scope : '.$this -> _searchParams['scope']);
753     
754     if( $cache && (!isset($_REQUEST['refresh'])) && (!$this -> params['withoutCache']) ) {
755       LSdebug('LSsearch : with the cache');
756       $this -> result = $this -> getResultFromCache();
757     }
758     else {
759       LSdebug('LSsearch : without the cache');
760       $this -> setParam('withoutCache',false);
761     }
762     
763     if (!$this -> result) {
764       LSdebug('LSsearch : Not in cache');
765       $this -> result=array(
766         'sortBy' => NULL,
767         'sortDirection' => NULL
768       );
769       $this -> result['list'] = LSldap :: search(
770         $this -> _searchParams['filter'],
771         $this -> _searchParams['basedn'],
772         $this -> _searchParams
773       );
774       if ($this -> result['list'] === false) {
775         LSerror :: addErrorCode('LSsearch_12');
776         unset($this -> result['list']);
777         return;
778       }
779       $this -> addResultToCache();
780     }
781     
782     $this -> doSort();
783     
784     return true;
785   }
786   
787   /**
788    * Return an hash corresponding to the parameters of the search
789    * 
790    * @param[in] $searchParams array An optional search params array
791    * 
792    * @retval string The hash of the parameters of the search
793    **/  
794   public function getHash($searchParams=null) {
795     if(is_null($searchParams)) {
796       $searchParams=$this -> _searchParams;
797       if ($this -> _hash) {
798         return $this -> _hash;
799       }
800     }
801     if ($searchParams['filter'] instanceof Net_LDAP_Filter) {
802       $searchParams['filter']=$searchParams['filter']->asString();
803     }
804     return hash('md5',print_r($searchParams,true));
805   }
806   
807   /**
808    * Add the result of the search to cache of the session
809    * 
810    * @retval void
811    **/  
812   public function addResultToCache() {
813     if ($this -> cacheIsEnabled()) {
814       LSdebug('LSsearch : Save result in cache.');
815       $hash=$this->getHash();
816       $_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash]=$this->result;
817     }
818   }
819   
820   /**
821    * Get the result of the search from cache of the session
822    * 
823    * @retval array | False The array of the result of the search or False
824    **/  
825   private function getResultFromCache() {
826     if ($this -> cacheIsEnabled()) {
827       $hash=$this->getHash();
828       if (isset($_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash])) {
829         LSdebug('LSsearch : Load result from cache.');
830         return $_SESSION['LSsession']['LSsearch'][$this -> LSobject][$hash];
831       }
832     }
833     return;
834   }
835   
836   /**
837    * Get page informations to display
838    * 
839    * @param[in] $page integer The number of the page
840    * 
841    * @retval array The information of the page
842    **/
843   public function getPage($page=0) {
844     if (!LSsession::loadLSclass('LSsearchEntry')) {
845       LSerror::addErrorCode('LSsession_05',$this -> LSobject);
846       return;
847     }
848     $page = (int)$page;
849
850     $retval=array(
851       'nb' => $page,
852       'nbPages' => 1,
853       'list' => array(),
854       'total' => $this -> total
855     );
856     
857     if ($retval['total']>0) {
858       LSdebug('Total : '.$retval['total']);
859       
860       if (!$this->params['nbObjectsByPage']) {
861         $this->params['nbObjectsByPage']=NB_LSOBJECT_LIST;
862       }
863       $retval['nbPages']=ceil($retval['total']/$this->params['nbObjectsByPage']);
864       
865       $sortTable=$this -> getSortTable();
866       
867       $list = array_slice(
868         $sortTable,
869         ($page * $this->params['nbObjectsByPage']),
870         $this->params['nbObjectsByPage']
871       );
872       
873       foreach ($list as $key => $id) {
874         $retval['list'][]=new LSsearchEntry($this,$this -> LSobject,$this -> params,$this -> _hash,$this -> result['list'],$id);
875       }
876     }
877     return $retval;
878   }
879   
880   /**
881    * Get search entries
882    * 
883    * @retval array The entries
884    **/
885   public function getSearchEntries() {
886     if (!LSsession::loadLSclass('LSsearchEntry')) {
887       LSerror::addErrorCode('LSsession_05',$this -> LSobject);
888       return;
889     }
890     $retval=array();
891     if ($this -> total>0) {
892       $sortTable=$this -> getSortTable();
893       
894       foreach ($sortTable as $key => $id) {
895         $retval[]=new LSsearchEntry($this,$this -> LSobject,$this -> params,$this -> _hash,$this -> result['list'],$id);
896       }
897     }
898     return $retval;
899   }
900   
901   /**
902    * Access to information of this object
903    * 
904    * @param[in] $key string The key of the info
905    * 
906    * @retval mixed The info
907    **/
908   public function __get($key) {
909     $params = array (
910       'sortBy',
911       'sortDirection'
912     );
913     if ($key=='LSobject') {
914       return $this -> LSobject;
915     }
916     elseif (in_array($key,$params)) {
917       return $this -> params[$key];
918     }
919     elseif ($key=='label_objectName') {
920       return LSldapObject::getLabel($this -> LSobject);
921     }
922     elseif ($key=='label_level') {
923       return LSsession :: getSubDnLabel();
924     }
925     elseif ($key=='label_actions') {
926       return _('Actions');
927     }
928     elseif ($key=='label_no_result') {
929       return _("This search didn't get any result.");
930     }
931     elseif ($key=='sort') {
932       if (isset($this -> params['sortlimit']) && ($this -> params['sortlimit']>0)) {
933         return ($this -> total < $this -> params['sortlimit']);
934       }
935       return true;
936     }
937     elseif ($key=='sortlimit') {
938       return $this -> params['sortlimit'];
939     }
940     elseif ($key=='total') {
941       return count($this -> result['list']);
942     }
943     elseif ($key=='label_total') {
944       return $this -> total." ".$this -> label_objectName;
945     }
946     elseif ($key=='displaySubDn') {
947       if (LSsession :: subDnIsEnabled()) {
948         if (!is_null($this -> params[$key])) {
949           return $this -> params[$key];
950         }
951         else {
952           return (! LSsession :: isSubDnLSobject($this -> LSobject) );
953         }
954       }
955       return false;
956     }
957     elseif ($key=='canCopy') {
958       if (!is_null($this -> _canCopy))
959         return $this -> _canCopy;
960       $this -> _canCopy = LSsession :: canCreate($this -> LSobject);
961       return $this -> _canCopy;
962     }
963     elseif ($key=='predefinedFilters') {
964       return ((is_array($this -> config['predefinedFilters']))?$this -> config['predefinedFilters']:array());
965     }
966     else {
967       throw new Exception('Incorrect property !');
968     }
969   }
970   
971   /**
972    * Function use with uasort to sort two entry
973    * 
974    * @param[in] $a array One line of result
975    * @param[in] $b array One line of result
976    * 
977    * @retval int Value for uasort
978    **/
979   private function _sortTwoEntry(&$a,&$b) {
980     $sortBy = $this -> params['sortBy'];
981     $sortDirection = $this -> params['sortDirection'];
982     if ($sortDirection=='ASC') {
983       $dir = -1;
984     }
985     else {
986       $dir = 1;
987     }
988     $oa = new LSsearchEntry($this,$this -> LSobject,$this -> params,$this -> _hash,$this -> result['list'],$a);
989     $va = $oa->$sortBy;
990     $ob = new LSsearchEntry($this,$this -> LSobject,$this -> params,$this -> _hash,$this -> result['list'],$b);
991     $vb = $ob->$sortBy;
992     
993     if ($va == $vb) return 0;
994     
995     $val = array($va,$vb);
996     sort($val);
997     
998     if ($val[0]==$va)
999       return 1*$dir;
1000       
1001     return -1*$dir;
1002   }
1003   
1004   /**
1005    * Function to run after using the result. It's update the cache
1006    * 
1007    * IT'S FUNCTION IS VERY IMPORTANT !!!
1008    * 
1009    * @retval void
1010    **/
1011   function afterUsingResult() {
1012     $this -> addResultToCache();
1013   }
1014   
1015   /**
1016    * Run the sort if it's enabled and if the result is not in the cache
1017    * 
1018    * @retval boolean True on success or false
1019    **/
1020   function doSort() {
1021     if (!$this -> sort) {
1022       LSdebug('doSort : sort is disabled');
1023       return true;
1024     }
1025     if (is_null($this -> params['sortBy'])) {
1026       return;
1027     }
1028     if (is_null($this -> params['sortDirection'])) {
1029       $this -> params['sortDirection']='ASC';
1030     }
1031
1032     if ($this->total==0) {
1033       return true;
1034     }
1035     
1036     if (isset($this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']])) {
1037       LSdebug('doSort : from cache');
1038       return true;
1039     }
1040      
1041     LSdebug('doSort : '.$this -> params['sortBy'].' - '.$this -> params['sortDirection']);
1042     
1043     $this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']]=range(0,($this -> total-1));
1044     
1045     if (!LSsession :: loadLSClass('LSsearchEntry')) {
1046       LSerror::addErrorCode('LSsession_05','LSsearchEntry');
1047       return;
1048     }
1049     
1050     if (!uasort(
1051       $this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']],
1052       array($this,'_sortTwoEntry')
1053     )) {
1054       LSerror :: addErrorCode('LSsearch_13');
1055       return;
1056     }
1057     
1058     return true;
1059   }
1060   
1061   /**
1062    * Returns the id of table rows in the result sorted according to criteria 
1063    * defined in the parameters
1064    * 
1065    * @retval array The Table of id lines of results sorted
1066    **/
1067   function getSortTable() {
1068     if ($this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']]) {
1069       return $this -> result['sort'][$this -> params['sortBy']][$this -> params['sortDirection']];
1070     }
1071     return range(0,($this -> total-1));
1072   }
1073   
1074   /**
1075    * List objects name
1076    * 
1077    * @retval Array DN associate with name
1078    **/
1079   public function listObjectsName() {
1080     if (!LSsession::loadLSclass('LSsearchEntry')) {
1081       LSerror::addErrorCode('LSsession_05',$this -> LSobject);
1082       return;
1083     }
1084     
1085     $retval=array();
1086     
1087     if ($this -> total>0) {
1088       $sortTable=$this -> getSortTable();
1089       
1090       foreach ($sortTable as $key => $id) {
1091         $entry=new LSsearchEntry($this,$this -> LSobject,$this -> params,$this -> _hash,$this -> result['list'],$id);
1092         $retval[$entry->dn]=$entry->displayName;
1093       }
1094     }
1095     
1096     return $retval;
1097   }
1098   
1099   /**
1100    * List LSldapObjects 
1101    * 
1102    * @retval Array of LSldapObjects
1103    **/
1104   public function listObjects() {    
1105     $retval=array();
1106     
1107     if ($this -> total>0) {
1108       $sortTable=$this -> getSortTable();
1109
1110       $c=0;      
1111       foreach ($sortTable as $key => $id) {
1112         $retval[$c]=new $this -> LSobject();
1113         $retval[$c] -> loadData($this -> result['list'][$id]['dn']);
1114         $c++;
1115       }
1116     }
1117     
1118     return $retval;
1119   }
1120   
1121   /**
1122    * List objects dn
1123    * 
1124    * @retval Array of DN
1125    **/
1126   public function listObjectsDn() {    
1127     $retval=array();
1128     
1129     if ($this -> total>0) {
1130       $sortTable=$this -> getSortTable();
1131
1132       $c=0;      
1133       foreach ($sortTable as $key => $id) {
1134         $retval[$c] = $this -> result['list'][$id]['dn'];
1135         $c++;
1136       }
1137     }
1138     
1139     return $retval;
1140   }
1141   
1142 }
1143
1144 /**
1145  * Error Codes
1146  **/
1147 LSerror :: defineError('LSsearch_01',
1148 _("LSsearch : Invalid filter : %{filter}.")
1149 );
1150 LSerror :: defineError('LSsearch_02',
1151 _("LSsearch : Invalid basedn : %{basedn}.")
1152 );
1153 LSerror :: defineError('LSsearch_03',
1154 _("LSsearch : Invalid value for %{param} parameter.")
1155 );
1156 LSerror :: defineError('LSsearch_04',
1157 _("LSsearch : Invalid size limit. Must be an integer greater or equal to 0.")
1158 );
1159 LSerror :: defineError('LSsearch_05',
1160 _("LSsearch : Invalid parameter %{attr}. Must be an boolean.")
1161 );
1162 LSerror :: defineError('LSsearch_06',
1163 _("LSsearch : Invalid parameter attributes. Must be an string or an array of strings.")
1164 );
1165 LSerror :: defineError('LSsearch_07',
1166 _("LSsearch : Can't build attributes list for make filter.")
1167 );
1168 LSerror :: defineError('LSsearch_08',
1169 _("LSsearch : Error building filter with attribute '%{attr}' and pattern '%{pattern}'")
1170 );
1171 LSerror :: defineError('LSsearch_09',
1172 _("LSsearch : Error combining filters.")
1173 );
1174 LSerror :: defineError('LSsearch_10',
1175 _("LSsearch : Invalid pattern.")
1176 );
1177 LSerror :: defineError('LSsearch_11',
1178 _("LSsearch : Invalid attribute %{attr} in parameters.")
1179 );
1180 LSerror :: defineError('LSsearch_12',
1181 _("LSsearch : Error during the search.")
1182 );
1183 LSerror :: defineError('LSsearch_13',
1184 _("LSsearch : Error sorting the search.")
1185 );
1186 LSerror :: defineError('LSsearch_14',
1187 _("LSsearch : The function of the custum information %{name} is not callable.")
1188 );
1189
1190 ?>