<?php
+/*
+ * This code is part of GOsa (http://www.gosa-project.org)
+ * Copyright (C) 2003-2008 GONICUS GmbH
+ *
+ * ID: $$Id$$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
class filter {
var $elements= array();
var $elementValues= array();
var $alphabetElements= array();
- var $search;
- var $definition;
+ var $autocompleter= array();
var $category= "";
var $objectStorage= array();
- var $objectBase= "";
var $base= "";
- var $bases= array();
var $scope= "";
var $query;
- var $baseMode= false;
+ var $initial= false;
var $scopeMode= "auto";
var $alphabet= null;
- var $templatePath= "";
- var $target= "";
+ var $converter= array();
+ var $pid;
+
function filter($filename)
{
+ global $config;
+
+ // Load eventually passed filename
if (!$this->load($filename)) {
die("Cannot parse $filename!");
}
+
+ $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE));
}
+
function load($filename)
{
- // Load data into array
- $xmlData= simplexml_load_file($filename);
- if ($xmlData === false) {
+ $contents = file_get_contents($filename);
+ $this->xmlData= xml::xml2array($contents, 1);
+
+ if (!isset($this->xmlData['filterdef'])) {
return false;
}
- // Load definition
- if (isset($xmlData->definition)) {
- foreach ($xmlData->definition as $entry) {
- if (!isset($entry->target) || !isset($entry->template)) {
- return false;
- }
+ $this->xmlData= $this->xmlData["filterdef"];
- // Move information
- $this->templatePath= (string)$entry->template;
- $this->target= (string)$entry->target;
+ // Load filter
+ if (isset($this->xmlData['search'])) {
+ if (!isset($this->xmlData['search']['query'][0])){
+ $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
+ }
- // One is enough
- break;
+ // Move information
+ $entry= $this->xmlData['search'];
+ $this->scopeMode= $entry['scope'];
+ if ($entry['scope'] == "auto") {
+ $this->scope= "one";
+ } else {
+ $this->scope= $entry['scope'];
}
+ $this->query= $entry['query'];
+ } else {
+ return false;
}
- // Load filter
- if (isset($xmlData->search)) {
- foreach ($xmlData->search as $entry) {
- if (!isset($entry->query) || !isset($entry->base) || !isset($entry->scope)) {
- return false;
- }
-
- // Move information
- $this->baseMode= (string)$entry->base;
- $this->scopeMode= (string)$entry->scope;
- $this->query= $entry->query;
+ // Transfer initial value
+ if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
+ $this->initial= true;
+ }
- // One is enough
- break;
- }
+ // Transfer category
+ if (isset($this->xmlData['definition']['category'])){
+ $this->category= $this->xmlData['definition']['category'];
}
// Generate formular data
- if (isset($xmlData->element)) {
- foreach ($xmlData->element as $element) {
+ if (isset($this->xmlData['element'])) {
+ if (!isset($this->xmlData['element'][0])){
+ $this->xmlData['element']= array($this->xmlData['element']);
+ }
+ foreach ($this->xmlData['element'] as $element) {
// Ignore elements without type
- if (!isset($element->type)) {
+ if (!isset($element['type']) || !isset($element['tag'])) {
next;
}
- $tag= (string)$element->tag;
+ $tag= $element['tag'];
+
+ // Fix arrays
+ if (isset($element['value']) && !isset($element['value'][0])) {
+ $element['value']= array($element['value']);
+ }
// Store element for quick access
$this->elements[$tag] = $element;
// Preset elementValues with default values if exist
- if (isset($element->default)) {
- $this->elementValues[$tag] = (string)$element->default;
+ if (isset($element['default']) && !is_array($element['default'])) {
+ $this->elementValues[$tag] = $element['default'];
} else {
$this->elementValues[$tag] = "";
}
// Does this element react on alphabet links?
- if (isset($element->alphabet) && (string)$element->alphabet == "true") {
+ if (isset($element['alphabet']) && $element['alphabet'] == "true") {
$this->alphabetElements[]= $tag;
}
}
- }
- // Save definition
- if (isset($xmlData->definition)) {
- $this->definition = $xmlData->definition;
- }
+ uasort($this->elements, 'strlenSort');
+ $this->elements= array_reverse($this->elements);
- // Save search
- if (isset($xmlData->search)) {
- $this->search = $xmlData->search;
}
return true;
function getTextfield($element)
{
- $result= "<input class='filter_textfield' name='$element' type='text' size='30' maxlength='30' value='".$this->elementValues[$element]."'>";
+ $tag= $element['tag'];
+ $size= 30;
+ if (isset($element['size'])){
+ $size= $element['size'];
+ }
+ $maxlength= 30;
+ if (isset($element['maxlength'])){
+ $maxlength= $element['maxlength'];
+ }
+ $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='$size' maxlength='maxlength' value='".$this->elementValues[$tag]."'>";
+ if (isset($element['autocomplete'])) {
+ $frequency= "0.5";
+ $characters= "1";
+ if (isset($element['autocomplete']['frequency'])) {
+ $frequency= $element['autocomplete']['frequency'];
+ }
+ if (isset($element['autocomplete']['characters'])) {
+ $characters= $element['autocomplete']['characters'];
+ }
+ $result.= "<div id='autocomplete$tag' class='autocomplete'></div>".
+ "<script type='text/javascript'>".
+ "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
+ "</script>";
+
+ $this->autocompleters[$tag]= $element['autocomplete'];
+ }
return $result;
}
function getCheckbox($element)
{
+ $tag= $element['tag'];
$checked= "";
- if ($this->elementValues[$element] == "true") {
+ if ($this->elementValues[$tag] == "true") {
$checked= " checked";
}
- $result= "<input class='filter_checkbox' name='$element' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
+ $result= "<input class='filter_checkbox' name='$tag' type='checkbox' onClick='document.mainform.submit();' value='true'$checked>";
return $result;
}
function getCombobox($element)
{
- $result= "<select name='".$element->tag."' size='1' onClick='document.mainform.submit();'>";
- foreach ($element->value as $key=>$value) {
+ $result= "<select name='".$element['tag']."' size='1' onClick='document.mainform.submit();'>";
+
+ // Fill with presets
+ foreach ($element['value'] as $value) {
$selected= "";
- if ($this->elementValues[(string)$element->tag] == $value->key) {
+ if ($this->elementValues[$element['tag']] == $value['key']) {
$selected= " selected";
}
- $result.= "<option value='".$value->key."'$selected>{t}".$value->set."{/t}</option>";
+
+ // Handle translations
+ $result.= "<option value='".$value['key']."'$selected>"._($value['label'])."</option>";
+ }
+
+ // Use autocompleter for additional data
+ if (isset($element['autocomplete'])) {
+ $list= $this->getCompletitionList($element['autocomplete'], $element['tag']);
+ foreach ($list as $value) {
+ $selected= "";
+ if ($this->elementValues[$element['tag']] == $value) {
+ $selected= " selected";
+ }
+ $result.= "<option value='$value'$selected>$value</option>";
+ }
}
+
$result.= "</select>";
return $result;
}
- function setBases($bases) {
- $this->bases= $bases;
+ function setConverter($field, $hook)
+ {
+ $this->converter[$field]= $hook;
}
- function setObjectStorage($storage) {
+ function setObjectStorage($storage)
+ {
$this->objectStorage= $storage;
}
- function setObjectBase($base) {
- $this->objectBase= $base;
- }
-
-
- function setCategory($category) {
- $this->category= $category;
- }
-
-
- function setCurrentBase($base) {
+ function setBase($base)
+ {
$this->base= $base;
}
- function setCurrentScope($scope) {
- $this->scope= $scope;
- }
-
-
- function renderBase()
+ function setCurrentScope($scope)
{
- $result= "<select name='currentMainBase' onChange='mainform.submit()' size='1'>";
-
- foreach ($this->bases as $key=>$value) {
- $selected= "";
- if ($key == $this->base) {
- $selected= " selected";
- }
- $result.= "<option value='".$key."'$selected>".$value."</option>";
- }
- $result.= "</select>";
-
- return $result;
+ $this->scope= $scope;
}
}
- function renderFilter()
+ function render()
{
$smarty= get_smarty();
$smarty->assign("ALPHABET", $this->renderAlphabet());
$smarty->assign("APPLY", $this->renderApply());
$smarty->assign("SCOPE", $this->renderScope());
- $smarty->assign("BASE", $this->renderBase());
// Load template and replace elementsHtml[]
foreach ($this->elements as $tag => $element) {
$htmlCode= "";
- switch ($element->type) {
+ switch ($element['type']) {
case "textfield":
- $htmlCode = $this->getTextfield($tag);
+ $htmlCode = $this->getTextfield($element);
break;
case "checkbox":
- $htmlCode = $this->getCheckbox($tag);
+ $htmlCode = $this->getCheckbox($element);
break;
case "combobox":
}
// Load template
- return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path("filter/$this->templatePath")));
+ return ("<input type='hidden' name='FILTER_PID' value='".$this->pid."'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
}
global $class_mapping;
$result= array();
+ // Return empty list if initial is not set
+ if (!$this->initial) {
+ $this->initial= true;
+ return $result;
+ }
+
// Go thru all queries and merge results
foreach ($this->query as $query) {
- if (!isset($query->backend) || !isset($query->filter) || !isset($query->attribute)) {
+ if (!isset($query['backend']) || !isset($query['filter']) || !isset($query['attribute'])) {
die("No backend specified in search config.");
}
// Is backend available?
- $backend= "filter".(string)$query->backend;
+ $backend= "filter".$query['backend'];
if (!isset($class_mapping["$backend"])) {
die("Invalid backend specified in search config.");
}
// Load filter and attributes
- $filter= $query->filter;
- $attributes= array();
- foreach($query->attribute as $attr) {
- $attributes[]= (string)$attr;
- }
+ $filter= $query['filter'];
+ $attributes= $query['attribute'];
// Generate final filter
foreach ($this->elements as $tag => $element) {
- $e_set= (string)$element->set;
- $e_unset= (string)$element->unset;
+ if (!isset($element['set']) || !isset($element['unset'])) {
+ continue;
+ }
+
+ // Handle converters if present
+ if (isset($this->converter[$tag])) {
+ preg_match('/([^:]+)::(.*)$/', $this->converter[$tag], $m);
+ $e_set= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->elementValues[$tag], is_array($element['set'])?"":$element['set']));
+ $e_unset= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->elementValues[$tag], is_array($element['unset'])?"":$element['unset']));
+ } else {
+ $e_set= is_array($element['set'])?"":$element['set'];
+ $e_unset= is_array($element['unset'])?"":$element['unset'];
+ }
if ($this->elementValues[$tag] == "") {
$e_unset= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_unset);
}
}
- $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
- $this->category, $this->objectStorage, $this->objectBase));
+ $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes, $this->category, $this->objectStorage));
}
-
return ($result);
}
}
}
- if (isset($_POST['FILTER_LOADED'])) {
+ if (isset($_POST['FILTER_PID']) && $_POST['FILTER_PID'] == $this->pid) {
// Load post values and adapt filter, base and scope accordingly - but
// only if we didn't get a _GET
foreach ($this->elements as $tag => $element) {
$this->elementValues[$tag]= "";
}
}
+
+ // Save scope if needed
+ if ($this->scopeMode == "auto") {
+ $this->scope= isset($_POST['SCOPE'])?"sub":"one";
+ }
+ }
+
+ }
+
+
+ function getCompletitionList($config, $tag, $value="*")
+ {
+ global $class_mapping;
+ $res= array();
+
+ // Is backend available?
+ $backend= "filter".$config['backend'];
+ if (!isset($class_mapping["$backend"])) {
+ die("Invalid backend specified in search config.");
+ }
+
+ // Load filter and attributes
+ $filter= $config['filter'];
+ $attributes= $config['attribute'];
+ if (!is_array($attributes)) {
+ $attributes= array($attributes);
+ }
+
+ // Make filter
+ $filter= preg_replace("/\\$$tag/", normalizeLDAP($value), $filter);
+ if (isset($config['base']) && isset($config['scope']) && isset($config['category'])) {
+ $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
+ $config["category"], $config["objectStorage"]);
+ } else {
+ $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
+ $this->category, $this->objectStorage);
}
- // Save base
- if (isset($_POST['BASE']) && $this->baseMode == "true") {
- $base= validate($_POST['BASE']);
- if (isset($this->bases[$base])) {
- $this->base= $base;
+ foreach ($result as $entry) {
+ foreach ($attributes as $attribute) {
+ if (is_array($entry[$attribute])) {
+ for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
+ if (mb_stristr($entry[$attribute][$i], $value)) {
+ $res[]= $entry[$attribute][$i];
+ }
+ }
+ } else {
+ $res[]= $entry[$attribute];
+ }
}
}
- // Save scope if needed
- if ($this->scopeMode == "auto") {
- $this->scope= isset($_POST['SCOPE'])?"sub":"one";
+ return $res;
+ }
+
+
+ function processAutocomplete()
+ {
+ global $class_mapping;
+ $result= array();
+
+ // Introduce maximum number of entries
+ $max= 25;
+
+ foreach ($this->autocompleters as $tag => $config) {
+ if(isset($_POST[$tag])){
+ $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
+ $result= array_unique($result);
+ asort($result);
+
+ echo '<ul>';
+ foreach ($result as $entry) {
+ echo '<li>'.$entry.'</li>';
+ if ($max-- == 0) {
+ break;
+ }
+ }
+
+ echo '</ul>';
+ }
}
}
+
+ function getObjectBase($dn)
+ {
+ global $config;
+ $base= "";
+
+ // Try every object storage
+ $storage= $this->objectStorage;
+ if (!is_array($storage)){
+ $storage= array($storage);
+ }
+ foreach ($storage as $location) {
+ $pattern= "/^[^,]+,".preg_quote($location, '/')."/i";
+ $base= preg_replace($pattern, '', $dn);
+ }
+
+ /* Set to base, if we're not on a correct subtree */
+ if (!isset($config->idepartments[$base])){
+ $base= $config->current['BASE'];
+ }
+
+ return $base;
+ }
+
+
}
+// Sort elements for element length to allow proper replacing later on
+function strlenSort($a, $b) {
+ if (strlen($a['tag']) == strlen($b['tag'])) {
+ return 0;
+ }
+ return (strlen($a['tag']) < strlen($b['tag']) ? -1 : 1);
+}
+
?>