Code

Prepared statistics to print password changes over time
[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' placeholder='"._("Search")."...' 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' summary='"._("Search filter")."'><tr><td>".$this->renderFilterMenu()."</td><td>";
227         $content.= "<div class='search-filter'>".$this->getTextfield('search_filter', set_post($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= get_post('search_filter');
290             }
292             // Save scope if needed
293             if ($this->scopeMode == "auto" && isset($_POST['act']) && $_POST['act'] == "toggle-subtree") {
294                 $this->scope= ($this->scope == "one")?"sub":"one";
295             }
297             // Switch filter?
298             if (isset($_POST['act'])) {
299                 foreach ($this->searches as $tag => $cfg) {
300                     if ($_POST['act'] == "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], get_post('search_filter'));
370             $result= array_unique($result);
371             asort($result);
373             echo '<ul>';
374             foreach ($result as $entry) {
375                 echo '<li>'.mark(get_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= "<ul class='level1' id='filter-root'><li><a href='#'>".image("images/filter.png").image("images/lists/sort-down.png")."</a>";
416         // Build ul/li list
417         $separator= " style='border-top:1px solid #AAA' ";
418         $result.= "<ul class='level2'>";
420         // Build in filters
421         foreach ($this->xmlSearches as $tag => $config) {
422             $label = htmlentities(_($config['label']),ENT_COMPAT,'UTF-8');
423             if ($tag == $this->search) {
424                 $result.= "<li><a href='#'>".image("images/checked.png")."&nbsp;".$label."</a></li>";
425             } else {
426                 $result.= "<li><a href='#' onClick='\$(\"act\").value= \"filter-$tag\";\$(\"exec_act\").click();'>".image("images/empty.png")."&nbsp;".$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='\$(\"act\").value= \"filter-$tag\";\$(\"exec_act\").click();'>".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='\$(\"act\").value= \"toggle-subtree\";\$(\"exec_act\").click();'>".($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='\$(\"act\").value= \"config-filter\";\$(\"exec_act\").click();'>".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 ?>