Code

Added base display to lists. Make it react on bases.
[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 $scope= "";
15   var $query;
16   var $initial= false;
17   var $scopeMode= "auto";
18   var $alphabet= null;
21   function filter($filename)
22   {
23     global $config;
25     // Load eventually passed filename
26     if (!$this->load($filename)) {
27       die("Cannot parse $filename!");
28     }
29   }
32   function load($filename)
33   {
34     $contents = file_get_contents($filename);
35     $this->xmlData= xml::xml2array($contents, 1);
37     if (!isset($this->xmlData['filter'])) {
38       return false;
39     }
41     $this->xmlData= $this->xmlData["filter"];
43     // Load filter
44     if (isset($this->xmlData['search'])) {
45       if (!isset($this->xmlData['search']['query'][0])){
46         $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
47       }
49       // Move information
50       $entry= $this->xmlData['search'];
51       $this->scopeMode= $entry['scope'];
52       if ($entry['scope'] == "auto") {
53         $this->scope= "one";
54       } else {
55         $this->scope= $entry['scope'];
56       }
57       $this->query= $entry['query'];
58     } else {
59       return false;
60     }
62     // Transfer initial value
63     if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
64       $this->initial= true;
65     }
67     // Transfer category
68     if (isset($this->xmlData['definition']['category'])){
69       $this->category= $this->xmlData['definition']['category'];
70     }
72     // Generate formular data
73     if (isset($this->xmlData['element'])) {
74       if (!isset($this->xmlData['element'][0])){
75         $this->xmlData['element']= array($this->xmlData['element']);
76       }
77       foreach ($this->xmlData['element'] as $element) {
79         // Ignore elements without type
80         if (!isset($element['type']) || !isset($element['tag'])) {
81           next;
82         }
84         $tag= $element['tag'];
86         // Fix arrays
87         if (isset($element['value']) && !isset($element['value'][0])) {
88           $element['value']= array($element['value']);
89         }
91         // Store element for quick access
92         $this->elements[$tag] = $element;
94         // Preset elementValues with default values if exist
95         if (isset($element['default']) && !is_array($element['default'])) {
96           $this->elementValues[$tag] = $element['default'];
97         } else {
98           $this->elementValues[$tag] = "";
99         }
101         // Does this element react on alphabet links?
102         if (isset($element['alphabet']) && $element['alphabet'] == "true") {
103           $this->alphabetElements[]= $tag;
104         }
105       }
106     }
108     return true;  
109   }
112   function getTextfield($element)
113   {
114     $tag= $element['tag'];
115     $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='30' maxlength='30' value='".$this->elementValues[$tag]."'>";
116     if (isset($element['autocomplete'])) {
117       $frequency= "0.5";
118       $characters= "1";
119       if (isset($element['autocomplete']['frequency'])) {
120         $frequency= $element['autocomplete']['frequency'];
121       }
122       if (isset($element['autocomplete']['characters'])) {
123         $characters= $element['autocomplete']['characters'];
124       }
125       $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
126                 "<script type='text/javascript'>".
127                 "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
128                 "</script>";
130        $this->autocompleters[$tag]= $element['autocomplete'];
131     }
132     return $result;
133   }
136   function getCheckbox($element)
137   {
138     $tag= $element['tag'];
139     $checked= "";
140     if ($this->elementValues[$tag] == "true") {
141       $checked= " checked";
142     }
144     $result= "<input class='filter_checkbox' name='$tag' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
145     return $result;
146   }
149   function getCombobox($element)
150   {
151     $result= "<select name='".$element['tag']."' size='1' onClick='document.mainform.submit();'>";
153     // Fill with presets
154     foreach ($element['value'] as $value) {
155       $selected= "";
156       if ($this->elementValues[$element['tag']] == $value['key']) {
157         $selected= " selected";
158       }
160       // Handle translations
161       $result.= "<option value='".$value['key']."'$selected>"._($value['label'])."</option>";
162     }
164     // Use autocompleter for additional data
165     if (isset($element['autocomplete'])) {
166       $list= $this->getCompletitionList($element['autocomplete'], $element['tag']);
167       foreach ($list as $value) {
168         $selected= "";
169         if ($this->elementValues[$element['tag']] == $value) {
170           $selected= " selected";
171         }
172         $result.= "<option value='$value'$selected>$value</option>";
173       }
174     }
176     $result.= "</select>";
178     return $result;
179   }
182   function getCurrentBase()
183   {
184     if (isset($this->search->base) && (string)$this->search->scope != "auto") {
185       return false;
186     }
188     return $this->base;
189   }
192   function getCurrentScope()
193   {
194     if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
195       return (string)$this->search->scope;
196     }
198     return $this->scope;
199   }
202   function setObjectStorage($storage) {
203     $this->objectStorage= $storage;    
204   }
207   function setObjectBase($base) {
208     $this->objectBase= $base;    
209   }
212   function setBase($base) {
213     $this->base= $base;
214   }
217   function setCurrentScope($scope) {
218     $this->scope= $scope;
219   }
222   function renderAlphabet($columns= 10)
223   {
224     // Return pre-rendered alphabet if available
225     if ($this->alphabet) {
226       return ($this->alphabet);
227     }
229     $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
230     $alphabet= "";
231     $c= 0;
233     /* Fill cells with charaters */
234     for ($i= 0, $l= mb_strlen($characters, 'UTF8'); $i<$l; $i++){
235       if ($c == 0){
236         $alphabet.= "<tr>";
237       }
239       $ch = mb_substr($characters, $i, 1, "UTF8");
240       $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
241         validate($_GET['plug'])."&amp;filter=".$ch."\">&nbsp;".$ch."&nbsp;</a></td>";
243       if ($c++ == $columns){
244         $alphabet.= "</tr>";
245         $c= 0;
246       }
247     }
249     /* Fill remaining cells */
250     while ($c++ <= $columns){
251       $alphabet.= "<td>&nbsp;</td>";
252     }
254     /* Save alphabet */
255     $this->alphabet= "<table width='100%'>$alphabet</table>";
257     return ($this->alphabet);
258   }
261   function renderApply()
262   {
263     return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
264   }
267   function renderScope()
268   {
269     $checked= $this->scope == "sub"?" checked":"";
270     return "<input type='checkbox' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked>&nbsp;"._("Search in subtrees");
271   }
274   function render()
275   {
276     $smarty= get_smarty();
277     $smarty->assign("ALPHABET", $this->renderAlphabet());
278     $smarty->assign("APPLY", $this->renderApply());
279     $smarty->assign("SCOPE", $this->renderScope());
281     // Load template and replace elementsHtml[]
282     foreach ($this->elements as $tag => $element) {
283       $htmlCode= "";
284       switch ($element['type']) {
285         case "textfield":
286           $htmlCode = $this->getTextfield($element);
287           break;
289         case "checkbox":
290           $htmlCode = $this->getCheckbox($element);
291           break;
293         case "combobox":
294           $htmlCode = $this->getCombobox($element);
295           break;
297         default:
298           die ("Unknown element type specified!");
299       }
300       $smarty->assign("$tag", $htmlCode);
301     }
303     // Load template
304     return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
305   }
308   function query()
309   {
310     global $class_mapping;
311     $result= array();
313     // Go thru all queries and merge results
314     foreach ($this->query as $query) {
315       if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
316         die("No backend specified in search config.");
317       }
319       // Is backend available?
320       $backend= "filter".$query['backend'];
321       if (!isset($class_mapping["$backend"])) {
322         die("Invalid backend specified in search config.");
323       }
325       // Load filter and attributes
326       $filter= $query['filter'];
327       $attributes= $query['attribute'];
329       // Generate final filter
330       foreach ($this->elements as $tag => $element) {
331         if (!isset($element['set']) || !isset($element['unset'])) {
332           continue;
333         }
334         $e_set= is_array($element['set'])?"":$element['set'];
335         $e_unset= is_array($element['unset'])?"":$element['unset'];
337         if ($this->elementValues[$tag] == "") {
338           $e_unset= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_unset);
339           $filter= preg_replace("/\\$$tag/", $e_unset, $filter);
340         } else {
341           $e_set= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_set);
342           $filter= preg_replace("/\\$$tag/", $e_set, $filter);
343         }
344       }
346       $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
347                                $this->category, $this->objectStorage, $this->objectBase));
348     }
349     
351     return ($result);
352   }
355   function isValid()
356   {
357     foreach ($this->elements as $tag => $element) {
358       if (isset($element->regex)){
359         if (!preg_match('/'.(string)$element->regex.'/', $this->elementValues[$tag])){
360           return false;
361         }
362       }
363     }
364     return true;
365   }
368   function update()
369   {
371     /* React on alphabet links if needed */
372     if (isset($_GET['filter'])){
373       $s= mb_substr(validate($_GET['filter']), 0, 1, "UTF8")."*";
374       if ($s == "**"){
375         $s= "*";
376       }
377       foreach ($this->alphabetElements as $tag) {
378         $this->elementValues[$tag]= $s;
379       }
380     }
382     if (isset($_POST['FILTER_LOADED'])) {
383       // Load post values and adapt filter, base and scope accordingly - but
384       // only if we didn't get a _GET
385       foreach ($this->elements as $tag => $element) {
386         if (isset($_POST[$tag])){
387           $this->elementValues[$tag]= validate($_POST[$tag]);
388         } else {
389           $this->elementValues[$tag]= "";
390         }
391       }
392     }
394     // Save scope if needed
395     if ($this->scopeMode == "auto") {
396       $this->scope= isset($_POST['SCOPE'])?"sub":"one";
397     }
398   }
401   function getCompletitionList($config, $tag, $value="*")
402   {
403     global $class_mapping;
404     $res= array();
406     // Is backend available?
407     $backend= "filter".$config['backend'];
408     if (!isset($class_mapping["$backend"])) {
409       die("Invalid backend specified in search config.");
410     }
412     // Load filter and attributes
413     $filter= $config['filter'];
414     $attributes= $config['attribute'];
415     if (!is_array($attributes)) {
416       $attributes= array($attributes);
417     }
419     // Make filter
420     $filter= preg_replace("/\\$$tag/", normalizeLDAP($value), $filter);
421     if (isset($config['base']) && isset($config['scope'])
422         && isset($config['category']) && isset($config['objectbase']) ) {
423       $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
424                            $config["category"], $config["objectbase"]);
425     } else {
426       $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
427                            $this->category, $this->objectStorage, $this->objectBase);
428     }
430     foreach ($result as $entry) {
431       foreach ($attributes as $attribute) {
432         if (is_array($entry[$attribute])) {
433           for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
434             $res[]= $entry[$attribute][$i];
435           }
436         } else {
437           $res[]= $entry[$attribute];
438         }
439       }
440     }
442     return $res;
443   }
446   function processAutocomplete()
447   {
448     global $class_mapping;
449     $result= array();
451     foreach ($this->autocompleters as $tag => $config) {
452       if(isset($_POST[$tag])){
453         $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
455         echo '<ul>';
456         foreach ($result as $entry) {
457           echo '<li>'.$entry.'</li>';
458         }
460         echo '</ul>';
461       }
463     }
464   }
469 ?>