9d4d9384e81ada3a402ad0fa91573df6a4e5cfa4
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 $bases= array();
15 var $scope= "";
16 var $query;
17 var $initial= false;
18 var $baseMode= false;
19 var $scopeMode= "auto";
20 var $alphabet= null;
23 function filter($filename)
24 {
25 if (!$this->load($filename)) {
26 die("Cannot parse $filename!");
27 }
28 }
31 function load($filename)
32 {
33 $contents = file_get_contents($filename);
34 $this->xmlData= xml::xml2array($contents, 1);
36 if (!isset($this->xmlData['filter'])) {
37 return false;
38 }
40 $this->xmlData= $this->xmlData["filter"];
42 // Load filter
43 if (isset($this->xmlData['search'])) {
44 if (!isset($this->xmlData['search']['query'][0])){
45 $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
46 }
48 // Move information
49 $entry= $this->xmlData['search'];
50 $this->baseMode= $entry['base'];
51 $this->scopeMode= $entry['scope'];
52 $this->query= $entry['query'];
53 } else {
54 return false;
55 }
57 // Transfer initial value
58 if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
59 $this->initial= true;
60 }
62 // Transfer category
63 if (isset($this->xmlData['definition']['category'])){
64 $this->category= $this->xmlData['definition']['category'];
65 }
67 // Generate formular data
68 if (isset($this->xmlData['element'])) {
69 if (!isset($this->xmlData['element'][0])){
70 $this->xmlData['element']= array($this->xmlData['element']);
71 }
72 foreach ($this->xmlData['element'] as $element) {
74 // Ignore elements without type
75 if (!isset($element['type']) || !isset($element['tag'])) {
76 next;
77 }
79 $tag= $element['tag'];
81 // Fix arrays
82 if (isset($element['value']) && !isset($element['value'][0])) {
83 $element['value']= array($element['value']);
84 }
86 // Store element for quick access
87 $this->elements[$tag] = $element;
89 // Preset elementValues with default values if exist
90 if (isset($element['default']) && !is_array($element['default'])) {
91 $this->elementValues[$tag] = $element['default'];
92 } else {
93 $this->elementValues[$tag] = "";
94 }
96 // Does this element react on alphabet links?
97 if (isset($element['alphabet']) && $element['alphabet'] == "true") {
98 $this->alphabetElements[]= $tag;
99 }
100 }
101 }
103 return true;
104 }
107 function getTextfield($element)
108 {
109 $tag= $element['tag'];
110 $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='30' maxlength='30' value='".$this->elementValues[$tag]."'>";
111 if (isset($element['autocomplete'])) {
112 $frequency= "0.5";
113 $characters= "1";
114 if (isset($element['autocomplete']['frequency'])) {
115 $frequency= $element['autocomplete']['frequency'];
116 }
117 if (isset($element['autocomplete']['characters'])) {
118 $characters= $element['autocomplete']['characters'];
119 }
120 $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
121 "<script type='text/javascript'>".
122 "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
123 "</script>";
125 $this->autocompleters[$tag]= $element['autocomplete'];
126 }
127 return $result;
128 }
131 function getCheckbox($element)
132 {
133 $tag= $element['tag'];
134 $checked= "";
135 if ($this->elementValues[$tag] == "true") {
136 $checked= " checked";
137 }
139 $result= "<input class='filter_checkbox' name='$tag' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
140 return $result;
141 }
144 function getCombobox($element)
145 {
146 $result= "<select name='".$element['tag']."' size='1' onClick='document.mainform.submit();'>";
148 // Fill with presets
149 foreach ($element['value'] as $value) {
150 $selected= "";
151 if ($this->elementValues[$element['tag']] == $value['key']) {
152 $selected= " selected";
153 }
155 // Handle translations
156 if (is_array($value['set'])) {
157 $result.= "<option value='".$value['key']."'$selected>".xml::getLocalizedAttribute($value['set'], $GLOBALS['t_language'])."</option>";
158 } else {
159 $result.= "<option value='".$value['key']."'$selected>".$value['set']."</option>";
160 }
161 }
163 // Use autocompleter for additional data
164 if (isset($element['autocomplete'])) {
165 $list= $this->getCompletitionList($element['autocomplete'], $element['tag']);
166 foreach ($list as $value) {
167 $selected= "";
168 if ($this->elementValues[$element['tag']] == $value) {
169 $selected= " selected";
170 }
171 $result.= "<option value='$value'$selected>$value</option>";
172 }
173 }
175 $result.= "</select>";
177 return $result;
178 }
181 function getCurrentBase()
182 {
183 if (isset($this->search->base) && (string)$this->search->scope != "auto") {
184 return false;
185 }
187 return $this->base;
188 }
191 function getCurrentScope()
192 {
193 if (isset($this->search->scope) && (string)$this->search->scope != "auto") {
194 return (string)$this->search->scope;
195 }
197 return $this->scope;
198 }
201 function setBases($bases) {
202 $this->bases= $bases;
203 }
206 function setObjectStorage($storage) {
207 $this->objectStorage= $storage;
208 }
211 function setObjectBase($base) {
212 $this->objectBase= $base;
213 }
216 function setCurrentBase($base) {
217 $this->base= $base;
218 }
221 function setCurrentScope($scope) {
222 $this->scope= $scope;
223 }
226 function renderBase()
227 {
228 $result= "<select name='currentMainBase' onChange='mainform.submit()' size='1'>";
230 foreach ($this->bases as $key=>$value) {
231 $selected= "";
232 if ($key == $this->base) {
233 $selected= " selected";
234 }
235 $result.= "<option value='".$key."'$selected>".$value."</option>";
236 }
237 $result.= "</select>";
239 return $result;
240 }
243 function renderAlphabet($columns= 10)
244 {
245 // Return pre-rendered alphabet if available
246 if ($this->alphabet) {
247 return ($this->alphabet);
248 }
250 $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
251 $alphabet= "";
252 $c= 0;
254 /* Fill cells with charaters */
255 for ($i= 0, $l= mb_strlen($characters, 'UTF8'); $i<$l; $i++){
256 if ($c == 0){
257 $alphabet.= "<tr>";
258 }
260 $ch = mb_substr($characters, $i, 1, "UTF8");
261 $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
262 validate($_GET['plug'])."&filter=".$ch."\"> ".$ch." </a></td>";
264 if ($c++ == $columns){
265 $alphabet.= "</tr>";
266 $c= 0;
267 }
268 }
270 /* Fill remaining cells */
271 while ($c++ <= $columns){
272 $alphabet.= "<td> </td>";
273 }
275 /* Save alphabet */
276 $this->alphabet= "<table width='100%'>$alphabet</table>";
278 return ($this->alphabet);
279 }
282 function renderApply()
283 {
284 return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
285 }
288 function renderScope()
289 {
290 $checked= $this->scope == "sub"?" checked":"";
291 return "<input type='checkbox' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked> "._("Search in subtrees");
292 }
295 function render()
296 {
297 $smarty= get_smarty();
298 $smarty->assign("ALPHABET", $this->renderAlphabet());
299 $smarty->assign("APPLY", $this->renderApply());
300 $smarty->assign("SCOPE", $this->renderScope());
301 $smarty->assign("BASE", $this->renderBase());
303 // Load template and replace elementsHtml[]
304 foreach ($this->elements as $tag => $element) {
305 $htmlCode= "";
306 switch ($element['type']) {
307 case "textfield":
308 $htmlCode = $this->getTextfield($element);
309 break;
311 case "checkbox":
312 $htmlCode = $this->getCheckbox($element);
313 break;
315 case "combobox":
316 $htmlCode = $this->getCombobox($element);
317 break;
319 default:
320 die ("Unknown element type specified!");
321 }
322 $smarty->assign("$tag", $htmlCode);
323 }
325 // Load template
326 return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
327 }
330 function query()
331 {
332 global $class_mapping;
333 $result= array();
335 // Go thru all queries and merge results
336 foreach ($this->query as $query) {
337 if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
338 die("No backend specified in search config.");
339 }
341 // Is backend available?
342 $backend= "filter".$query['backend'];
343 if (!isset($class_mapping["$backend"])) {
344 die("Invalid backend specified in search config.");
345 }
347 // Load filter and attributes
348 $filter= $query['filter'];
349 $attributes= $query['attribute'];
351 // Generate final filter
352 foreach ($this->elements as $tag => $element) {
353 if (!isset($element['set']) || !isset($element['unset'])) {
354 continue;
355 }
356 $e_set= is_array($element['set'])?"":$element['set'];
357 $e_unset= is_array($element['unset'])?"":$element['unset'];
359 if ($this->elementValues[$tag] == "") {
360 $e_unset= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_unset);
361 $filter= preg_replace("/\\$$tag/", $e_unset, $filter);
362 } else {
363 $e_set= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_set);
364 $filter= preg_replace("/\\$$tag/", $e_set, $filter);
365 }
366 }
368 $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
369 $this->category, $this->objectStorage, $this->objectBase));
370 }
373 return ($result);
374 }
377 function isValid()
378 {
379 foreach ($this->elements as $tag => $element) {
380 if (isset($element->regex)){
381 if (!preg_match('/'.(string)$element->regex.'/', $this->elementValues[$tag])){
382 return false;
383 }
384 }
385 }
386 return true;
387 }
390 function update()
391 {
393 /* React on alphabet links if needed */
394 if (isset($_GET['filter'])){
395 $s= mb_substr(validate($_GET['filter']), 0, 1, "UTF8")."*";
396 if ($s == "**"){
397 $s= "*";
398 }
399 foreach ($this->alphabetElements as $tag) {
400 $this->elementValues[$tag]= $s;
401 }
402 }
404 if (isset($_POST['FILTER_LOADED'])) {
405 // Load post values and adapt filter, base and scope accordingly - but
406 // only if we didn't get a _GET
407 foreach ($this->elements as $tag => $element) {
408 if (isset($_POST[$tag])){
409 $this->elementValues[$tag]= validate($_POST[$tag]);
410 } else {
411 $this->elementValues[$tag]= "";
412 }
413 }
414 }
416 // Save base
417 if (isset($_POST['BASE']) && $this->baseMode == "true") {
418 $base= validate($_POST['BASE']);
419 if (isset($this->bases[$base])) {
420 $this->base= $base;
421 }
422 }
424 // Save scope if needed
425 if ($this->scopeMode == "auto") {
426 $this->scope= isset($_POST['SCOPE'])?"sub":"one";
427 }
428 }
431 function getCompletitionList($config, $tag, $value="*")
432 {
433 global $class_mapping;
434 $res= array();
436 // Is backend available?
437 $backend= "filter".$config['backend'];
438 if (!isset($class_mapping["$backend"])) {
439 die("Invalid backend specified in search config.");
440 }
442 // Load filter and attributes
443 $filter= $config['filter'];
444 $attributes= $config['attribute'];
445 if (!is_array($attributes)) {
446 $attributes= array($attributes);
447 }
449 // Make filter
450 $filter= preg_replace("/\\$$tag/", normalizeLDAP($value), $filter);
451 if (isset($config['base']) && isset($config['scope'])
452 && isset($config['category']) && isset($config['objectbase']) ) {
453 $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
454 $config["category"], $config["objectbase"]);
455 } else {
456 $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
457 $this->category, $this->objectStorage, $this->objectBase);
458 }
460 foreach ($result as $entry) {
461 foreach ($attributes as $attribute) {
462 if (is_array($entry[$attribute])) {
463 for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
464 $res[]= $entry[$attribute][$i];
465 }
466 } else {
467 $res[]= $entry[$attribute];
468 }
469 }
470 }
472 return $res;
473 }
476 function processAutocomplete()
477 {
478 global $class_mapping;
479 $result= array();
481 foreach ($this->autocompleters as $tag => $config) {
482 if(isset($_POST[$tag])){
483 $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
485 echo '<ul>';
486 foreach ($result as $entry) {
487 echo '<li>'.$entry.'</li>';
488 }
490 echo '</ul>';
491 }
493 }
494 }
496 }
498 ?>