Code

2afa3fe60685fe2e85029debd50dcb29552e9c1c
[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 $xmlData;
26   var $searches= array();
27   var $search;
29   #FIXME - Seems to be obsolete. Categories are defined in the listing.xml <objectType> 
30   #         and not in the filter.xml anymore.
31   var $category= "";
32   var $objectStorage= array();
33   var $base= "";
34   var $scope= "";
35   var $query;
36   var $value= "";
37   var $initial= false;
38   var $scopeMode= "auto";
39   var $converter= null;
40   var $pid;
42   /* An editor which allows to create user defined ldap-filter.
43    * Due to the fact that it requires additional ldap schemata 
44    *  (objectClasses=gosaProperties) this is currently optional.
45    */
46   var $filterEditor = NULL;
48   /* The categories this filter is made for (e.g. ['users'] or. ['server','workstation']). 
49    * Since this is set we are able to create user defined filters.
50    */
51   var $categories   = array();
53   function filter($filename)
54   {
55     global $config;
57     // Load eventually passed filename
58     if (!$this->load($filename)) {
59       die("Cannot parse $filename!");
60     }
62     $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE)); 
63   }
66   function load($filename)
67   {
68     $contents = file_get_contents($filename);
69     $this->xmlData= xml::xml2array($contents, 1);
71     if (!isset($this->xmlData['filterdef'])) {
72       return false;
73     }
75     $this->xmlData= $this->xmlData["filterdef"];
77     // Load filter
78     if (isset($this->xmlData['search'])) {
80       // Array conversion
81       if (!is_array($this->xmlData['search'])) {
82         $searches= array($this->xmlData['search']);
83       } else {
84         $searches= $this->xmlData['search'];
85       }
87       /* Store available searches */
88       foreach ($this->xmlData['search'] as $search) {
90         /* Do multi conversation */ 
91         if (!is_array($search['query'])){
92           $search['query']= array($search['query']);
93         }
95         /* Store search */
96         $this->searches[$search['label']]= $search;
98       }
99     } else {
100       return false;
101     }
103     // Transfer scope
104     $this->scopeMode= $this->xmlData['definition']['scope'];
105     if ($this->scopeMode == "auto") {
106       $this->scope= "one";
107     } else {
108       $this->scope= $this->scopeMode;
109     }
111     // Transfer initial value
112     if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
113       $this->initial= true;
114     }
116     // Transfer category
117     if (isset($this->xmlData['definition']['category'])){
118       $this->category= $this->xmlData['definition']['category'];
119     }
121     // Set default search mode
122     $this->setSearch($this->xmlData['definition']['default']);
124     return true;  
125   }
128   function setSearch($method)
129   {
130     // Move information
131     if (isset($this->searches[$method])) {
132       $this->query= $this->searches[$method]['query'];
133       if (!isset($this->query[0])) {
134         $this->query= array($this->query);
135       }
136       $this->search= $method;
137     } else {
138       die ("Invalid search module!");
139     }
140   }
143   function getTextfield($element)
144   {
145     $tag= $element['tag'];
146     $size= 30;
147     if (isset($element['size'])){
148       $size= $element['size'];
149     }
150     $maxlength= 30;
151     if (isset($element['maxlength'])){
152       $maxlength= $element['maxlength'];
153     }
154     $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='$size' maxlength='{$maxlength}' value='".$this->elementValues[$tag]."'>";
155     if (isset($element['autocomplete'])) {
156       $frequency= "0.5";
157       $characters= "1";
158       if (isset($element['autocomplete']['frequency'])) {
159         $frequency= $element['autocomplete']['frequency'];
160       }
161       if (isset($element['autocomplete']['characters'])) {
162         $characters= $element['autocomplete']['characters'];
163       }
164       $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
165         "<script type='text/javascript'>".
166         "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
167         "</script>";
169       $this->autocompleters[$tag]= $element['autocomplete'];
170     }
171     return $result;
172   }
175   function getCurrentBase()
176   {
177     if (isset($this->search->base) && (string)$this->search->scope != "auto") {
178       return false;
179     }
181     return $this->base;
182   }
185   function getCurrentScope()
186   {
187     if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
188       return (string)$this->search->scope;
189     }
191     return $this->scope;
192   }
195   function setConverter($hook)
196   {
197     $this->converter= $hook;
198   }
201   function setObjectStorage($storage)
202   {
203     $this->objectStorage= $storage;    
204   }
207   function setBase($base)
208   {
209     $this->base= $base;
210   }
213   function setCurrentScope($scope)
214   {
215     $this->scope= $scope;
216   }
219   function renderApply()
220   {
221     return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
222   }
225   function renderScope()
226   {
227     $checked= $this->scope == "sub"?" checked":"";
228     return "<input type='checkbox' id='SCOPE' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked>&nbsp;<LABEL for='SCOPE'>"._("Search in subtrees")."</LABEL>";
229   }
232   function render()
233   {
234     $content= "<table class='filter-wrapper'><tr><td>".$this->renderFilterMenu()."</td><td>";
235     $content.= "<div class='search-filter'><input type='text' name='search_filter' value='".$this->value."'></div>".
236       "&nbsp;<button class='search-filter' type='submit' title='"._("Search")."'>".image("images/find.png")."</button></td></tr></table>";
238     // Return meta data
239     return ("<input type='hidden' name='FILTER_PID' value='".$this->pid."'>".$content);
240   }
243   function query()
244   {
245     global $class_mapping;
246     $result= array();
248     // Return empty list if initial is not set
249     if (!$this->initial) {
250       $this->initial= true;
251       return $result;
252     }
254     // Go thru all queries and merge results
255     foreach ($this->query as $query) {
256       if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
257         die("No backend specified in search config.");
258       }
260       // Is backend available?
261       $backend= "filter".$query['backend'];
262       if (!isset($class_mapping["$backend"])) {
263         die("Invalid backend specified in search config.");
264       }
266       // Load filter and attributes
267       $filter= $query['filter'];
268       $attributes= $query['attribute'];
270       // Handle converters if present
271       if ($this->converter) {
272         preg_match('/([^:]+)::(.*)$/', $this->converter, $m);
273         $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->value, $filter));
274       }
276       // Do not replace escaped \$ - This is required to be able to search for e.g. windows machines.
277       if ($this->value == "") {
278         $filter= preg_replace("/\\$/", '*', $filter);
279       } else {
280         $filter= preg_replace("/\\$/", "*".normalizeLdap($this->value)."*", $filter);
281       }
283       $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes, $this->categories, $this->objectStorage));
284     }
286     return ($result);
287   }
290   function update()
291   {
292     if (isset($_POST['FILTER_PID']) && $_POST['FILTER_PID'] == $this->pid) {
294       // Save input field
295       if (isset($_POST['search_filter'])) {
296         $this->value= validate($_POST['search_filter']);
297       }
299       // Save scope if needed
300       if ($this->scopeMode == "auto") {
301         $this->scope= isset($_POST['SCOPE'])?"sub":"one";
302       }
303     }
305   }
308   function getCompletitionList($config, $value="*")
309   {
310     global $class_mapping;
311     $res= array();
313     // Is backend available?
314     $backend= "filter".$config['backend'];
315     if (!isset($class_mapping["$backend"])) {
316       die("Invalid backend specified in search config.");
317     }
319     // Load filter and attributes
320     $filter= $config['filter'];
321     $attributes= $config['attribute'];
322     if (!is_array($attributes)) {
323       $attributes= array($attributes);
324     }
326     // Make filter
327     $filter= preg_replace("/\\$/", normalizeLdap($value), $filter);
328     if (isset($config['base']) && isset($config['scope']) && isset($config['category'])) {
329       $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
330           $config["category"], $config["objectStorage"]);
331     } else {
332       $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
333           $this->categories, $this->objectStorage);
334     }
336     foreach ($result as $entry) {
337       foreach ($attributes as $attribute) {
338         if (is_array($entry[$attribute])) {
339           for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
340             if (mb_stristr($entry[$attribute][$i], $value)) {
341               $res[]= $entry[$attribute][$i];
342             }
343           }
344         } else {
345           $res[]= $entry[$attribute];
346         }
347       }
348     }
350     return $res;
351   }
354   function processAutocomplete()
355   {
356     global $class_mapping;
357     $result= array();
359     // Introduce maximum number of entries
360     $max= 25;
362     if(isset($this->searches[$this->search]['autocomplete'])){
363       $result= $this->getCompletitionList($this->searches[$this->search]['autocomplete'], $_POST['search_filter']);
364       $result= array_unique($result);
365       asort($result);
367       echo '<ul>';
368       foreach ($result as $entry) {
369         echo '<li>'.mark($_POST['search_filter'], $entry).'</li>';
370         if ($max-- == 0) {
371           break;
372         }
373       }
375       echo '</ul>';
376     }
377   }
380   function getObjectBase($dn)
381   {
382     global $config;
383     $base= "";
385     // Try every object storage
386     $storage= $this->objectStorage;
387     if (!is_array($storage)){
388       $storage= array($storage);
389     }
390     foreach ($storage as $location) {
391       $pattern= "/^[^,]+,".preg_quote($location, '/')."/i";
392       $base= preg_replace($pattern, '', $dn);
393     }
395     /* Set to base, if we're not on a correct subtree */
396     if (!isset($config->idepartments[$base])){
397       $base= $config->current['BASE'];
398     }
400     return $base;
401   }
405   function renderFilterMenu()
406   {
407     // Load shortcut
408     $result= "<input type='hidden' name='act' id='filter' value=''><div style='display:none'><input type='submit' name='exec_filter' id='exec_filter' value=''></div>".
409       "<ul class='level1' id='filter-root'><li><a href='#'>".image("images/filter.png")._("...")."&nbsp;".image("images/lists/sort-down.png")."</a>";
411     // Build ul/li list
412     $result.= "<ul class='level2'>";
413     $result.= "<li><a href='#'>Dummy placeholder</a></li>";
414     $result.= "<li><a href='#'>Dummy placeholder</a></li>";
415 #$result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"".$action['name']."\";mainform.submit();'>$img"._($action['label'])."</a></li>";
417 # AUTOCOMPLETER and getTextbox
419     $result.= "</ul>";
421     $script= '<script type="text/javascript" language="JavaScript">var menu2; menu2= new Menu("filter-root", "menu2", configMenu)</script>';
423     return "<div id='filtermenu'>".$result."</li></ul><div>$script";
424   }
427   
428   function setCategories($categories)
429   {
430     if(!is_array($categories) && !empty($categories)){
431       $categories = array($categories)  ;
432     }
433     $this->categories = $categories;
434   }
438 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
439 ?>