Code

Fixed field naming
[gosa.git] / gosa-core / include / class_filter.inc
1 <?php
2 /*
3  * This code is part of GOsa (http://www.gosa-project.org)
4  * Copyright (C) 2003-2008 GONICUS GmbH
5  *
6  * ID: $$Id$$
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
23 class filter {
25   var $searches= array();
26   var $xmlSearches= array();
27   var $attributes= array();
28   var $search;
29   var $defaultSearch;
30   var $category= "";
31   var $objectStorage= array();
32   var $base= "";
33   var $scope= "";
34   var $query;
35   var $value= "";
36   var $initial= false;
37   var $scopeMode= "auto";
38   var $converter= null;
39   var $pid;
42   function filter($filename)
43   {
44     global $config;
46     // Load eventually passed filename
47     if (!$this->load($filename)) {
48       die("Cannot parse $filename!");
49     }
51     $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE)); 
52   }
55   function load($filename)
56   {
57     $contents = file_get_contents($filename);
58     $xmlData= xml::xml2array($contents, 1);
60     if (!isset($xmlData['filterdef'])) {
61       return false;
62     }
64     $xmlData= $xmlData["filterdef"];
66     // Load filter
67     if (isset($xmlData['search'])) {
69       // Array conversion
70       if (!isset($xmlData['search'][0])) {
71         $searches= array($xmlData['search']);
72       } else {
73         $searches= $xmlData['search'];
74       }
76       /* Store available searches */
77       foreach ($searches as $search) {
79         /* Do multi conversation */ 
80         if (!isset($search['query'][0])){
81           $search['query']= array($search['query']);
82         }
84         /* Store search */
85         $this->xmlSearches[$search['tag']]= $search;
87       }
88     } else {
89       return false;
90     }
92     // Transfer scope
93     $this->scopeMode= $xmlData['definition']['scope'];
94     if ($this->scopeMode == "auto") {
95       $this->scope= "one";
96     } else {
97       $this->scope= $this->scopeMode;
98     }
100     // Transfer attributes
101     $this->attributes= $xmlData['definition']['attribute'];
102     if (!is_array($this->attributes)) {
103       $this->attributes= array($this->attributes);
104     }
106     // Transfer initial value
107     if (isset($xmlData['definition']['initial']) && $xmlData['definition']['initial'] == "true"){
108       $this->initial= true;
109     }
111     // Transfer category
112     if (isset($xmlData['definition']['category'])){
113       $this->category= $xmlData['definition']['category'];
114     }
115     if (!is_array($this->category)) {
116       $this->category= array($this->category);
117     }
119     // Initialize searches and default search mode
120     $this->defaultSearch= $xmlData['definition']['default'];
121     $this->reloadFilters();
122     $this->setSearch($this->defaultSearch);
124     return true;  
125   }
128   function reloadFilters()
129   {
130     $this->searches= array_merge($this->xmlSearches, userFilter::getFilter($this->category));
131     $this->setSearch($this->search);
132   }
135   function setSearch($method= null)
136   {
137     $patch= null;
139     // Maybe our search method has gone?
140     if (!isset($this->searches[$method])) {
141       $method= $this->defaultSearch;
142     }
144     // Try to use it, but bail out if there's no help...
145     if (isset($this->searches[$method])) {
146       $this->query= $this->searches[$method]['query'];
147       $this->search= $method;
148     } else {
149       die ("Invalid search module!");
150     }
151   }
154   function getTextfield($tag, $value= "", $element= null)
155   {
156     $size= 30;
157     $maxlength= 30;
158     $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='$size' maxlength='{$maxlength}' value='".$value."'>";
159     if ($element && isset($element['autocomplete'])) {
160       $frequency= "0.5";
161       $characters= "1";
162       if (isset($element['autocomplete']['frequency'])) {
163         $frequency= $element['autocomplete']['frequency'];
164       }
165       if (isset($element['autocomplete']['characters'])) {
166         $characters= $element['autocomplete']['characters'];
167       }
168       $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
169         "<script type='text/javascript'>".
170         "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
171         "</script>";
173       $this->autocompleters[$tag]= $element;
174     }
175     return $result;
176   }
179   function getCurrentBase()
180   {
181     if (isset($this->search->base) && (string)$this->search->scope != "auto") {
182       return false;
183     }
185     return $this->base;
186   }
189   function getCurrentScope()
190   {
191     if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
192       return (string)$this->search->scope;
193     }
195     return $this->scope;
196   }
199   function setConverter($hook)
200   {
201     $this->converter= $hook;
202   }
205   function setObjectStorage($storage)
206   {
207     $this->objectStorage= $storage;    
208   }
211   function setBase($base)
212   {
213     $this->base= $base;
214   }
217   function setCurrentScope($scope)
218   {
219     $this->scope= $scope;
220   }
224   function render()
225   {
226     $content= "<table class='filter-wrapper'><tr><td>".$this->renderFilterMenu()."</td><td>";
227     $content.= "<div class='search-filter'>".$this->getTextfield('search_filter', $this->value, $this->searches[$this->search])."</div>".
228       "&nbsp;<button class='search-filter' type='submit' title='"._("Search")."'>".image("images/find.png")."</button></td></tr></table>";
230     // Return meta data
231     return ("<input type='hidden' name='FILTER_PID' value='".$this->pid."'>".$content);
232   }
235   function query()
236   {
237     global $class_mapping;
238     $result= array();
240     // Return empty list if initial is not set
241     if (!$this->initial) {
242       $this->initial= true;
243       return $result;
244     }
245     // Go thru all queries and merge results
246     foreach ($this->query as $query) {
247       if (!isset($query['backend']) || !isset($query['filter'])) {
248         die("No backend specified in search config.");
249       }
251       // Is backend available?
252       $backend= "filter".$query['backend'];
253       if (!isset($class_mapping["$backend"])) {
254         die("Invalid backend specified in search config.");
255       }
257       // Load filter and attributes
258       $filter= $query['filter'];
260       // Handle converters if present
261       if ($this->converter) {
262         preg_match('/([^:]+)::(.*)$/', $this->converter, $m);
263         if ($this->value == "") {
264           $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', "*", $filter));
265         } else {
266           $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->value, $filter));
267         }
268       }
270       // Do not replace escaped \$ - This is required to be able to search for e.g. windows machines.
271       if ($this->value == "") {
272         $filter= preg_replace("/\\$/", '*', $filter);
273       } else {
274         $filter= preg_replace("/\\$/", "*".normalizeLdap($this->value)."*", $filter);
275       }
277       $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $this->attributes, $this->category, $this->objectStorage));
278     }
280     return ($result);
281   }
284   function update()
285   {
286     if (isset($_POST['FILTER_PID']) && $_POST['FILTER_PID'] == $this->pid) {
287       // Save input field
288       if (isset($_POST['search_filter'])) {
289         $this->value= validate($_POST['search_filter']);
290       }
292       // Save scope if needed
293       if ($this->scopeMode == "auto" && isset($_POST['filter']) && $_POST['filter'] == "toggle-subtree") {
294         $this->scope= ($this->scope == "one")?"sub":"one";
295       }
297       // Switch filter?
298       if (isset($_POST['filter'])) {
299         foreach ($this->searches as $tag => $cfg) {
300           if ($_POST['filter'] == "filter-$tag") {
301             $this->setSearch($tag);
302             break;
303           }
304         }
305       }
306     }
308   }
311   function getCompletitionList($config, $value="*")
312   {
313     global $class_mapping;
314     $res= array();
316     // Load result attributes
317     $attributes= $config['autocomplete']['attribute'];
318     if (!is_array($attributes)) {
319       $attributes= array($attributes);
320     }
322     // Do the query
323     $result= array();
325     // Is backend available?
326     # FIXME
327     $queries= $config['query'];
328     if (!isset($queries[0])){
329       $queries= array($queries);
330     }
331     foreach ($queries as $query) {
332       $backend= "filter".$query['backend'];
333       if (!isset($class_mapping["$backend"])) {
334         die("Invalid backend specified in search config.");
335       }
336       $filter= preg_replace("/\\$/", "*".normalizeLdap($value)."*", $query['filter']);
338       $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
339           $this->category, $this->objectStorage));
340     }
342     foreach ($result as $entry) {
343       foreach ($attributes as $attribute) {
344         if (is_array($entry[$attribute])) {
345           for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
346             if (mb_stristr($entry[$attribute][$i], $value)) {
347               $res[]= $entry[$attribute][$i];
348             }
349           }
350         } else {
351           $res[]= $entry[$attribute];
352         }
353       }
354     }
356     return $res;
357   }
360   function processAutocomplete()
361   {
362     global $class_mapping;
363     $result= array();
365     // Introduce maximum number of entries
366     $max= 25;
368     if(isset($this->searches[$this->search]['autocomplete'])){
369       $result= $this->getCompletitionList($this->searches[$this->search], $_POST['search_filter']);
370       $result= array_unique($result);
371       asort($result);
373       echo '<ul>';
374       foreach ($result as $entry) {
375         echo '<li>'.mark($_POST['search_filter'], $entry).'</li>';
376         if ($max-- == 0) {
377           break;
378         }
379       }
381       echo '</ul>';
382     }
383   }
386   function getObjectBase($dn)
387   {
388     global $config;
389     $base= "";
391     // Try every object storage
392     $storage= $this->objectStorage;
393     if (!is_array($storage)){
394       $storage= array($storage);
395     }
396     foreach ($storage as $location) {
397       $pattern= "/^[^,]+,".preg_quote($location, '/')."/i";
398       $base= preg_replace($pattern, '', $dn);
399     }
401     /* Set to base, if we're not on a correct subtree */
402     if (!isset($config->idepartments[$base])){
403       $base= $config->current['BASE'];
404     }
406     return $base;
407   }
411   function renderFilterMenu()
412   {
413     // Load shortcut
414     $result= "<input type='hidden' name='filter' id='filter' value=''><div style='display:none'><input type='submit' name='exec_filter' id='exec_filter' value=''></div>".
415       "<ul class='level1' id='filter-root'><li><a href='#'>".image("images/filter.png").image("images/lists/sort-down.png")."</a>";
417     // Build ul/li list
418     $separator= " style='border-top:1px solid #AAA' ";
419     $result.= "<ul class='level2'>";
421     // Build in filters
422     foreach ($this->xmlSearches as $tag => $config) {
423       if ($tag == $this->search) {
424         $result.= "<li><a href='#'>".image("images/checked.png")."&nbsp;"._($config['label'])."</a></li>";
425       } else {
426         $result.= "<li><a href='#' onClick='document.getElementById(\"filter\").value= \"filter-$tag\";mainform.submit();'>".image("images/empty.png")."&nbsp;"._($config['label'])."</a></li>";
427       }
428     }
430     // User defined filters
431     $first= true;
432     foreach (userFilter::getFilter($this->category) as $tag => $config) {
433       if ($tag == $this->search) {
434         $result.= "<li".($first?$separator:"")."><a href='#'>".image("images/checked.png")."&nbsp;"._($config['description'])."</a></li>";
435       } else {
436         $result.= "<li".($first?$separator:"")."><a href='#' onClick='document.getElementById(\"filter\").value= \"filter-$tag\";mainform.submit();'>".image("images/empty.png")."&nbsp;"._($config['description'])."</a></li>";
437       }
439       $first= false;
440     }
442     // Render scope if set to auto
443     if ($this->scopeMode == "auto") {
444       $result.= "<li$separator><a href='#' onClick='document.getElementById(\"filter\").value= \"toggle-subtree\";mainform.submit();'>".($this->scope=="one"?image("images/empty.png"):image("images/checked.png"))."&nbsp;"._("Search in subtrees")."</a></li>";
445     }
448     // Edit filter menu
449     $result.= "<li$separator><a href='#' onClick='document.getElementById(\"filter\").value= \"config-filter\";mainform.submit();'>".image("images/configure.png")."&nbsp;"._("Edit filters")."...</a></li>";
451     $result.= "</ul>";
453     $script= '<script type="text/javascript" language="JavaScript">var menu2; menu2= new Menu("filter-root", "menu2", configMenu)</script>';
455     return "<div id='filtermenu'>".$result."</li></ul><div>$script";
456   }
459   function getFixedFilters()
460   {
461     return array_keys($this->searches);
462   }
467 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
468 ?>