Code

dd3c9b335a14e40e00d74a8779dedfddcdabaf5f
[gosa.git] / gosa-core / include / class_filter.inc
1 <?php
3 class filter {
5   var $xmlData;
6   var $elements= array();
7   var $elementValues= array();
8   var $alphabetElements= array();
9   var $autocompleter= array();
10   var $category= "";
11   var $objectStorage= array();
12   var $objectBase= "";
13   var $base= "";
14   var $bases= array();
15   var $scope= "";
16   var $query;
17   var $initial= false;
18   var $baseMode= false;
19   var $scopeMode= "auto";
20   var $alphabet= null;
23   function filter($filename)
24   {
25     if (!$this->load($filename)) {
26       die("Cannot parse $filename!");
27     }
28   }
31   function load($filename)
32   {
33     $contents = file_get_contents($filename);
34     $this->xmlData= xml::xml2array($contents, 1);
36     if (!isset($this->xmlData['filter'])) {
37       return false;
38     }
40     $this->xmlData= $this->xmlData["filter"];
42     // Load filter
43     if (isset($this->xmlData['search'])) {
44       if (!isset($this->xmlData['search']['query'][0])){
45         $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
46       }
48       // Move information
49       $entry= $this->xmlData['search'];
50       $this->baseMode= $entry['base'];
51       $this->scopeMode= $entry['scope'];
52       $this->query= $entry['query'];
53     } else {
54       return false;
55     }
57     // Transfer initial value
58     if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
59       $this->initial= true;
60     }
62     // Generate formular data
63     if (isset($this->xmlData['element'])) {
64       if (!isset($this->xmlData['element'][0])){
65         $this->xmlData['element']= array($this->xmlData['element']);
66       }
67       foreach ($this->xmlData['element'] as $element) {
69         // Ignore elements without type
70         if (!isset($element['type']) || !isset($element['tag'])) {
71           next;
72         }
74         $tag= $element['tag'];
76         // Fix arrays
77         if (isset($element['value']) && !isset($element['value'][0])) {
78           $element['value']= array($element['value']);
79         }
81         // Store element for quick access
82         $this->elements[$tag] = $element;
84         // Preset elementValues with default values if exist
85         if (isset($element['default']) && !is_array($element['default'])) {
86           $this->elementValues[$tag] = $element['default'];
87         } else {
88           $this->elementValues[$tag] = "";
89         }
91         // Does this element react on alphabet links?
92         if (isset($element['alphabet']) && $element['alphabet'] == "true") {
93           $this->alphabetElements[]= $tag;
94         }
95       }
96     }
98     return true;  
99   }
102   function getTextfield($element)
103   {
104     $tag= $element['tag'];
105     $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='30' maxlength='30' value='".$this->elementValues[$tag]."'>";
106     if (isset($element['autocomplete'])) {
107       $frequency= "0.5";
108       $characters= "1";
109       if (isset($element['autocomplete']['frequency'])) {
110         $frequency= $element['autocomplete']['frequency'];
111       }
112       if (isset($element['autocomplete']['characters'])) {
113         $characters= $element['autocomplete']['characters'];
114       }
115       $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
116                 "<script type='text/javascript'>".
117                 "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
118                 "</script>";
120        $this->autocompleters[$tag]= $element['autocomplete'];
121     }
122     return $result;
123   }
126   function getCheckbox($element)
127   {
128     $tag= $element['tag'];
129     $checked= "";
130     if ($this->elementValues[$tag] == "true") {
131       $checked= " checked";
132     }
134     $result= "<input class='filter_checkbox' name='$tag' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
135     return $result;
136   }
139   function getCombobox($element)
140   {
141     $result= "<select name='".$element['tag']."' size='1' onClick='document.mainform.submit();'>";
143     // Fill with presets
144     foreach ($element['value'] as $value) {
145       $selected= "";
146       if ($this->elementValues[$element['tag']] == $value['key']) {
147         $selected= " selected";
148       }
150       // Handle translations
151       if (is_array($value['set'])) {
152         $li= null;
154         // Get language index if available
155         $lang= preg_replace('/_.*$/', '', $GLOBALS['t_language']);
156         $mapper= array();
157         foreach($value['set'] as $index => $lv){
158           if (preg_match('/_attr$/', $index) && isset($lv['xml:lang']) && $lv['xml:lang'] == $lang) {
159             $li= preg_replace('/_attr$/', '', $index);
160             if (isset($mapper[$li])) {
161               unset($mapper[$li]);
162             }
163           } else {
164             $mapper[$index]= $index;
165           }
166         }
168         // Use some default if no index is available
169         if (!$li) {
170           $li= array_shift($mapper);
171         }
173         $result.= "<option value='".$value['key']."'$selected>".$value['set'][$li]."</option>";
174       } else {
175         $result.= "<option value='".$value['key']."'$selected>".$value['set']."</option>";
176       }
177     }
179     // Use autocompleter for additional data
180     if (isset($element['autocomplete'])) {
181       $list= $this->getCompletitionList($element['autocomplete'], $element['tag']);
182       foreach ($list as $value) {
183         $selected= "";
184         if ($this->elementValues[$element['tag']] == $value) {
185           $selected= " selected";
186         }
187         $result.= "<option value='$value'$selected>$value</option>";
188       }
189     }
191     $result.= "</select>";
193     return $result;
194   }
197   function getCurrentBase()
198   {
199     if (isset($this->search->base) && (string)$this->search->scope != "auto") {
200       return false;
201     }
203     return $this->base;
204   }
207   function getCurrentScope()
208   {
209     if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
210       return (string)$this->search->scope;
211     }
213     return $this->scope;
214   }
217   function setBases($bases) {
218     $this->bases= $bases;    
219   }
222   function setObjectStorage($storage) {
223     $this->objectStorage= $storage;    
224   }
227   function setObjectBase($base) {
228     $this->objectBase= $base;    
229   }
232   function setCategory($category) {
233     $this->category= $category;    
234   }
237   function setCurrentBase($base) {
238     $this->base= $base;
239   }
242   function setCurrentScope($scope) {
243     $this->scope= $scope;
244   }
247   function renderBase()
248   {
249     $result= "<select name='currentMainBase' onChange='mainform.submit()' size='1'>";
251     foreach ($this->bases as $key=>$value) {
252       $selected= "";
253       if ($key == $this->base) {
254         $selected= " selected";
255       }
256       $result.= "<option value='".$key."'$selected>".$value."</option>";
257     }
258     $result.= "</select>";
260     return $result;
261   }
264   function renderAlphabet($columns= 10)
265   {
266     // Return pre-rendered alphabet if available
267     if ($this->alphabet) {
268       return ($this->alphabet);
269     }
271     $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
272     $alphabet= "";
273     $c= 0;
275     /* Fill cells with charaters */
276     for ($i= 0, $l= mb_strlen($characters, 'UTF8'); $i<$l; $i++){
277       if ($c == 0){
278         $alphabet.= "<tr>";
279       }
281       $ch = mb_substr($characters, $i, 1, "UTF8");
282       $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
283         validate($_GET['plug'])."&amp;filter=".$ch."\">&nbsp;".$ch."&nbsp;</a></td>";
285       if ($c++ == $columns){
286         $alphabet.= "</tr>";
287         $c= 0;
288       }
289     }
291     /* Fill remaining cells */
292     while ($c++ <= $columns){
293       $alphabet.= "<td>&nbsp;</td>";
294     }
296     /* Save alphabet */
297     $this->alphabet= "<table width='100%'>$alphabet</table>";
299     return ($this->alphabet);
300   }
303   function renderApply()
304   {
305     return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
306   }
309   function renderScope()
310   {
311     $checked= $this->scope == "sub"?" checked":"";
312     return "<input type='checkbox' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked>&nbsp;"._("Search in subtrees");
313   }
316   function renderFilter()
317   {
318     $smarty= get_smarty();
319     $smarty->assign("ALPHABET", $this->renderAlphabet());
320     $smarty->assign("APPLY", $this->renderApply());
321     $smarty->assign("SCOPE", $this->renderScope());
322     $smarty->assign("BASE", $this->renderBase());
324     // Load template and replace elementsHtml[]
325     foreach ($this->elements as $tag => $element) {
326       $htmlCode= "";
327       switch ($element['type']) {
328         case "textfield":
329           $htmlCode = $this->getTextfield($element);
330           break;
332         case "checkbox":
333           $htmlCode = $this->getCheckbox($element);
334           break;
336         case "combobox":
337           $htmlCode = $this->getCombobox($element);
338           break;
340         default:
341           die ("Unknown element type specified!");
342       }
343       $smarty->assign("$tag", $htmlCode);
344     }
346     // Load template
347     return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
348   }
351   function query()
352   {
353     global $class_mapping;
354     $result= array();
356     // Go thru all queries and merge results
357     foreach ($this->query as $query) {
358       if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
359         die("No backend specified in search config.");
360       }
362       // Is backend available?
363       $backend= "filter".$query['backend'];
364       if (!isset($class_mapping["$backend"])) {
365         die("Invalid backend specified in search config.");
366       }
368       // Load filter and attributes
369       $filter= $query['filter'];
370       $attributes= $query['attribute'];
372       // Generate final filter
373       foreach ($this->elements as $tag => $element) {
374         if (!isset($element['set']) || !isset($element['unset'])) {
375           continue;
376         }
377         $e_set= is_array($element['set'])?"":$element['set'];
378         $e_unset= is_array($element['unset'])?"":$element['unset'];
380         if ($this->elementValues[$tag] == "") {
381           $e_unset= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_unset);
382           $filter= preg_replace("/\\$$tag/", $e_unset, $filter);
383         } else {
384           $e_set= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_set);
385           $filter= preg_replace("/\\$$tag/", $e_set, $filter);
386         }
387       }
389       $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
390                                $this->category, $this->objectStorage, $this->objectBase));
391     }
392     
394     return ($result);
395   }
398   function isValid()
399   {
400     foreach ($this->elements as $tag => $element) {
401       if (isset($element->regex)){
402         if (!preg_match('/'.(string)$element->regex.'/', $this->elementValues[$tag])){
403           return false;
404         }
405       }
406     }
407     return true;
408   }
411   function update()
412   {
414     /* React on alphabet links if needed */
415     if (isset($_GET['filter'])){
416       $s= mb_substr(validate($_GET['filter']), 0, 1, "UTF8")."*";
417       if ($s == "**"){
418         $s= "*";
419       }
420       foreach ($this->alphabetElements as $tag) {
421         $this->elementValues[$tag]= $s;
422       }
423     }
425     if (isset($_POST['FILTER_LOADED'])) {
426       // Load post values and adapt filter, base and scope accordingly - but
427       // only if we didn't get a _GET
428       foreach ($this->elements as $tag => $element) {
429         if (isset($_POST[$tag])){
430           $this->elementValues[$tag]= validate($_POST[$tag]);
431         } else {
432           $this->elementValues[$tag]= "";
433         }
434       }
435     }
437     // Save base
438     if (isset($_POST['BASE']) && $this->baseMode == "true") {
439       $base= validate($_POST['BASE']);
440       if (isset($this->bases[$base])) {
441         $this->base= $base;
442       }
443     }
445     // Save scope if needed
446     if ($this->scopeMode == "auto") {
447       $this->scope= isset($_POST['SCOPE'])?"sub":"one";
448     }
449   }
452   function getCompletitionList($config, $tag, $value="*")
453   {
454     global $class_mapping;
455     $res= array();
457     // Is backend available?
458     $backend= "filter".$config['backend'];
459     if (!isset($class_mapping["$backend"])) {
460       die("Invalid backend specified in search config.");
461     }
463     // Load filter and attributes
464     $filter= $config['filter'];
465     $attributes= $config['attribute'];
466     if (!is_array($attributes)) {
467       $attributes= array($attributes);
468     }
470     // Make filter
471     $filter= preg_replace("/\\$$tag/", normalizeLDAP($value), $filter);
472     if (isset($config['base']) && isset($config['scope'])
473         && isset($config['category']) && isset($config['objectbase']) ) {
474       $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
475                            $config["category"], $config["objectbase"]);
476     } else {
477       $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
478                            $this->category, $this->objectStorage, $this->objectBase);
479     }
481     foreach ($result as $entry) {
482       foreach ($attributes as $attribute) {
483         if (is_array($entry[$attribute])) {
484           for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
485             $res[]= $entry[$attribute][$i];
486           }
487         } else {
488           $res[]= $entry[$attribute];
489         }
490       }
491     }
493     return $res;
494   }
497   function processAutocomplete()
498   {
499     global $class_mapping;
500     $result= array();
502     foreach ($this->autocompleters as $tag => $config) {
503       if(isset($_POST[$tag])){
504         $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
506         echo '<ul>';
507         foreach ($result as $entry) {
508           echo '<li>'.$entry.'</li>';
509         }
511         echo '</ul>';
512       }
514     }
515   }
519 ?>