2afa3fe60685fe2e85029debd50dcb29552e9c1c
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> <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 " <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")._("...")." ".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 }
428 function setCategories($categories)
429 {
430 if(!is_array($categories) && !empty($categories)){
431 $categories = array($categories) ;
432 }
433 $this->categories = $categories;
434 }
435 }
438 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
439 ?>