index e1b16a58bf6e7e943a13f5157855c218af29393a..d1c7bfb97f39ff6b4c5283320537add4269e9c4f 100644 (file)
<?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 $xmlData;
- var $elements= array();
- var $elementValues= array();
- var $alphabetElements= array();
- var $autocompleter= array();
+ var $searches= array();
+ var $xmlSearches= array();
+ var $attributes= array();
+ var $search;
+ var $defaultSearch;
var $category= "";
var $objectStorage= array();
- var $objectBase= "";
var $base= "";
- var $bases= array();
var $scope= "";
var $query;
+ var $value= "";
var $initial= false;
- var $baseMode= false;
var $scopeMode= "auto";
- var $alphabet= null;
+ var $converter= null;
+ 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)
{
$contents = file_get_contents($filename);
- $this->xmlData= xml::xml2array($contents, 1);
+ $xmlData= xml::xml2array($contents, 1);
- if (!isset($this->xmlData['filter'])) {
+ if (!isset($xmlData['filterdef'])) {
return false;
}
- $this->xmlData= $this->xmlData["filter"];
+ $xmlData= $xmlData["filterdef"];
// Load filter
- if (isset($this->xmlData['search'])) {
- if (!isset($this->xmlData['search']['query'][0])){
- $this->xmlData['search']['query']= array($this->xmlData['search']['query']);
- }
+ if (isset($xmlData['search'])) {
- // Move information
- $entry= $this->xmlData['search'];
- $this->baseMode= $entry['base'];
- $this->scopeMode= $entry['scope'];
- if ($entry['scope'] == "auto") {
- $this->scope= "one";
+ // Array conversion
+ if (!isset($xmlData['search'][0])) {
+ $searches= array($xmlData['search']);
} else {
- $this->scope= $entry['scope'];
+ $searches= $xmlData['search'];
+ }
+
+ /* Store available searches */
+ foreach ($searches as $search) {
+
+ /* Do multi conversation */
+ if (!isset($search['query'][0])){
+ $search['query']= array($search['query']);
+ }
+
+ /* Store search */
+ $this->xmlSearches[$search['tag']]= $search;
+
}
- $this->query= $entry['query'];
} else {
return false;
}
+ // Transfer scope
+ $this->scopeMode= $xmlData['definition']['scope'];
+ if ($this->scopeMode == "auto") {
+ $this->scope= "one";
+ } else {
+ $this->scope= $this->scopeMode;
+ }
+
+ // Transfer attributes
+ $this->attributes= $xmlData['definition']['attribute'];
+ if (!is_array($this->attributes)) {
+ $this->attributes= array($this->attributes);
+ }
+
// Transfer initial value
- if (isset($this->xmlData['definition']['initial']) && $this->xmlData['definition']['initial'] == "true"){
+ if (isset($xmlData['definition']['initial']) && $xmlData['definition']['initial'] == "true"){
$this->initial= true;
}
// Transfer category
- if (isset($this->xmlData['definition']['category'])){
- $this->category= $this->xmlData['definition']['category'];
+ if (isset($xmlData['definition']['category'])){
+ $this->category= $xmlData['definition']['category'];
+ }
+ if (!is_array($this->category)) {
+ $this->category= array($this->category);
}
- // Generate formular data
- if (isset($this->xmlData['element'])) {
- if (!isset($this->xmlData['element'][0])){
- $this->xmlData['element']= array($this->xmlData['element']);
- }
- foreach ($this->xmlData['element'] as $element) {
+ // Initialize searches and default search mode
+ $this->defaultSearch= $xmlData['definition']['default'];
+ $this->reloadFilters();
+ $this->setSearch($this->defaultSearch);
- // Ignore elements without type
- if (!isset($element['type']) || !isset($element['tag'])) {
- next;
- }
+ return true;
+ }
- $tag= $element['tag'];
- // Fix arrays
- if (isset($element['value']) && !isset($element['value'][0])) {
- $element['value']= array($element['value']);
- }
+ function reloadFilters()
+ {
+ $this->searches= array_merge($this->xmlSearches, userFilter::getFilter($this->category));
+ $this->setSearch($this->search);
+ }
- // Store element for quick access
- $this->elements[$tag] = $element;
- // Preset elementValues with default values if exist
- if (isset($element['default']) && !is_array($element['default'])) {
- $this->elementValues[$tag] = $element['default'];
- } else {
- $this->elementValues[$tag] = "";
- }
+ function setSearch($method= null)
+ {
+ $patch= null;
- // Does this element react on alphabet links?
- if (isset($element['alphabet']) && $element['alphabet'] == "true") {
- $this->alphabetElements[]= $tag;
- }
- }
+ // Maybe our search method has gone?
+ if (!isset($this->searches[$method])) {
+ $method= $this->defaultSearch;
}
- return true;
+ // Try to use it, but bail out if there's no help...
+ if (isset($this->searches[$method])) {
+ $this->query= $this->searches[$method]['query'];
+ $this->search= $method;
+ } else {
+ die ("Invalid search module!");
+ }
}
- function getTextfield($element)
+ function getTextfield($tag, $value= "", $element= null)
{
- $tag= $element['tag'];
- $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='30' maxlength='30' value='".$this->elementValues[$tag]."'>";
- if (isset($element['autocomplete'])) {
+ $size= 30;
+ $maxlength= 30;
+ $result= "<input class='filter_textfield' id='$tag' name='$tag' type='text' size='$size' maxlength='{$maxlength}' value='".$value."'>";
+ if ($element && isset($element['autocomplete'])) {
$frequency= "0.5";
$characters= "1";
if (isset($element['autocomplete']['frequency'])) {
$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;
- }
-
+ "<script type='text/javascript'>".
+ "new Ajax.Autocompleter('$tag', 'autocomplete$tag', 'autocomplete.php', { minChars: $characters, frequency: $frequency });".
+ "</script>";
- function getCheckbox($element)
- {
- $tag= $element['tag'];
- $checked= "";
- if ($this->elementValues[$tag] == "true") {
- $checked= " checked";
+ $this->autocompleters[$tag]= $element;
}
-
- $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();'>";
-
- // Fill with presets
- foreach ($element['value'] as $value) {
- $selected= "";
- if ($this->elementValues[$element['tag']] == $value['key']) {
- $selected= " selected";
- }
-
- // 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 setObjectStorage($storage) {
- $this->objectStorage= $storage;
- }
-
-
- function setObjectBase($base) {
- $this->objectBase= $base;
- }
-
-
- function setCurrentBase($base) {
- $this->base= $base;
- }
-
-
- function setCurrentScope($scope) {
- $this->scope= $scope;
- }
-
-
- function renderBase()
+ function setConverter($hook)
{
- $result= "<select name='base' 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->converter= $hook;
}
- function renderAlphabet($columns= 10)
+ function setObjectStorage($storage)
{
- // Return pre-rendered alphabet if available
- if ($this->alphabet) {
- return ($this->alphabet);
- }
-
- $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
- $alphabet= "";
- $c= 0;
-
- /* Fill cells with charaters */
- for ($i= 0, $l= mb_strlen($characters, 'UTF8'); $i<$l; $i++){
- if ($c == 0){
- $alphabet.= "<tr>";
- }
-
- $ch = mb_substr($characters, $i, 1, "UTF8");
- $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
- validate($_GET['plug'])."&filter=".$ch."\"> ".$ch." </a></td>";
-
- if ($c++ == $columns){
- $alphabet.= "</tr>";
- $c= 0;
- }
- }
-
- /* Fill remaining cells */
- while ($c++ <= $columns){
- $alphabet.= "<td> </td>";
- }
-
- /* Save alphabet */
- $this->alphabet= "<table width='100%'>$alphabet</table>";
-
- return ($this->alphabet);
+ $this->objectStorage= $storage;
}
- function renderApply()
+ function setBase($base)
{
- return ("<input type='submit' name='apply' value='"._("Apply filter")."'>");
+ $this->base= $base;
}
- function renderScope()
+ function setCurrentScope($scope)
{
- $checked= $this->scope == "sub"?" checked":"";
- return "<input type='checkbox' name='SCOPE' value='1' onClick='document.mainform.submit();'$checked> "._("Search in subtrees");
+ $this->scope= $scope;
}
+
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']) {
- case "textfield":
- $htmlCode = $this->getTextfield($element);
- break;
-
- case "checkbox":
- $htmlCode = $this->getCheckbox($element);
- break;
+ $content= "<table class='filter-wrapper' summary='"._("Search filter")."'><tr><td>".$this->renderFilterMenu()."</td><td>";
+ $content.= "<div class='search-filter'>".$this->getTextfield('search_filter', $this->value, $this->searches[$this->search])."</div>".
+ " <button class='search-filter' type='submit' title='"._("Search")."'>".image("images/find.png")."</button></td></tr></table>";
- case "combobox":
- $htmlCode = $this->getCombobox($element);
- break;
-
- default:
- die ("Unknown element type specified!");
- }
- $smarty->assign("$tag", $htmlCode);
- }
-
- // Load template
- return ("<input type='hidden' name='FILTER_LOADED' value='1'>".$smarty->fetch(get_template_path($this->xmlData['definition']['template'], true)));
+ // Return meta data
+ return ("<input type='hidden' name='FILTER_PID' value='".$this->pid."'>".$content);
}
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'])) {
die("No backend specified in search config.");
}
// Load filter and attributes
$filter= $query['filter'];
- $attributes= $query['attribute'];
-
- // Generate final filter
- foreach ($this->elements as $tag => $element) {
- if (!isset($element['set']) || !isset($element['unset'])) {
- continue;
- }
- $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);
- $filter= preg_replace("/\\$$tag/", $e_unset, $filter);
+ // Handle converters if present
+ if ($this->converter) {
+ preg_match('/([^:]+)::(.*)$/', $this->converter, $m);
+ if ($this->value == "") {
+ $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', "*", $filter));
} else {
- $e_set= preg_replace('/\$/', normalizeLdap($this->elementValues[$tag]), $e_set);
- $filter= preg_replace("/\\$$tag/", $e_set, $filter);
+ $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->value, $filter));
}
}
- $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
- $this->category, $this->objectStorage, $this->objectBase));
+ // Do not replace escaped \$ - This is required to be able to search for e.g. windows machines.
+ if ($this->value == "") {
+ $filter= preg_replace("/\\$/", '*', $filter);
+ } else {
+ $filter= preg_replace("/\\$/", "*".normalizeLdap($this->value)."*", $filter);
+ }
+
+ $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $this->attributes, $this->category, $this->objectStorage));
}
-
return ($result);
}
- function isValid()
- {
- foreach ($this->elements as $tag => $element) {
- if (isset($element->regex)){
- if (!preg_match('/'.(string)$element->regex.'/', $this->elementValues[$tag])){
- return false;
- }
- }
- }
- return true;
- }
-
-
function update()
{
-
- /* React on alphabet links if needed */
- if (isset($_GET['filter'])){
- $s= mb_substr(validate($_GET['filter']), 0, 1, "UTF8")."*";
- if ($s == "**"){
- $s= "*";
- }
- foreach ($this->alphabetElements as $tag) {
- $this->elementValues[$tag]= $s;
+ if (isset($_POST['FILTER_PID']) && $_POST['FILTER_PID'] == $this->pid) {
+ // Save input field
+ if (isset($_POST['search_filter'])) {
+ $this->value= validate($_POST['search_filter']);
}
- }
- if (isset($_POST['FILTER_LOADED'])) {
- // 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) {
- if (isset($_POST[$tag])){
- $this->elementValues[$tag]= validate($_POST[$tag]);
- } else {
- $this->elementValues[$tag]= "";
- }
+ // Save scope if needed
+ if ($this->scopeMode == "auto" && isset($_POST['act']) && $_POST['act'] == "toggle-subtree") {
+ $this->scope= ($this->scope == "one")?"sub":"one";
}
- }
- // Save base
- if (isset($_POST['BASE']) && $this->baseMode == "true") {
- $base= validate($_POST['BASE']);
- if (isset($this->bases[$base])) {
- $this->base= $base;
+ // Switch filter?
+ if (isset($_POST['act'])) {
+ foreach ($this->searches as $tag => $cfg) {
+ if ($_POST['act'] == "filter-$tag") {
+ $this->setSearch($tag);
+ break;
+ }
+ }
}
}
- // Save scope if needed
- if ($this->scopeMode == "auto") {
- $this->scope= isset($_POST['SCOPE'])?"sub":"one";
- }
}
- function getCompletitionList($config, $tag, $value="*")
+ function getCompletitionList($config, $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'];
+ // Load result attributes
+ $attributes= $config['autocomplete']['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']) && isset($config['objectbase']) ) {
- $result= call_user_func(array($backend, 'query'), $config['base'], $config['scope'], $filter, $attributes,
- $config["category"], $config["objectbase"]);
- } else {
- $result= call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
- $this->category, $this->objectStorage, $this->objectBase);
+ // Do the query
+ $result= array();
+
+ // Is backend available?
+ # FIXME
+ $queries= $config['query'];
+ if (!isset($queries[0])){
+ $queries= array($queries);
+ }
+ foreach ($queries as $query) {
+ $backend= "filter".$query['backend'];
+ if (!isset($class_mapping["$backend"])) {
+ die("Invalid backend specified in search config.");
+ }
+ $filter= preg_replace("/\\$/", "*".normalizeLdap($value)."*", $query['filter']);
+
+ $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes,
+ $this->category, $this->objectStorage));
}
foreach ($result as $entry) {
foreach ($attributes as $attribute) {
if (is_array($entry[$attribute])) {
for ($i= 0; $i<$entry[$attribute]['count']; $i++) {
- $res[]= $entry[$attribute][$i];
+ if (mb_stristr($entry[$attribute][$i], $value)) {
+ $res[]= $entry[$attribute][$i];
+ }
}
} else {
$res[]= $entry[$attribute];
global $class_mapping;
$result= array();
- foreach ($this->autocompleters as $tag => $config) {
- if(isset($_POST[$tag])){
- $result= $this->getCompletitionList($config, $tag, $_POST[$tag]);
+ // Introduce maximum number of entries
+ $max= 25;
+
+ if(isset($this->searches[$this->search]['autocomplete'])){
+ $result= $this->getCompletitionList($this->searches[$this->search], $_POST['search_filter']);
+ $result= array_unique($result);
+ asort($result);
- echo '<ul>';
- foreach ($result as $entry) {
- echo '<li>'.$entry.'</li>';
+ echo '<ul>';
+ foreach ($result as $entry) {
+ echo '<li>'.mark($_POST['search_filter'], $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;
+ }
+
- echo '</ul>';
+
+ function renderFilterMenu()
+ {
+ // Load shortcut
+ $result= "<ul class='level1' id='filter-root'><li><a href='#'>".image("images/filter.png").image("images/lists/sort-down.png")."</a>";
+
+ // Build ul/li list
+ $separator= " style='border-top:1px solid #AAA' ";
+ $result.= "<ul class='level2'>";
+
+ // Build in filters
+ foreach ($this->xmlSearches as $tag => $config) {
+ if ($tag == $this->search) {
+ $result.= "<li><a href='#'>".image("images/checked.png")." "._($config['label'])."</a></li>";
+ } else {
+ $result.= "<li><a href='#' onClick='\$(\"act\").value= \"filter-$tag\";\$(\"exec_act\").click();'>".image("images/empty.png")." "._($config['label'])."</a></li>";
}
+ }
+
+ // User defined filters
+ $first= true;
+ foreach (userFilter::getFilter($this->category) as $tag => $config) {
+ if ($tag == $this->search) {
+ $result.= "<li".($first?$separator:"")."><a href='#'>".image("images/checked.png")." "._($config['description'])."</a></li>";
+ } else {
+ $result.= "<li".($first?$separator:"")."><a href='#' onClick='\$(\"act\").value= \"filter-$tag\";\$(\"exec_act\").click();'>".image("images/empty.png")." "._($config['description'])."</a></li>";
+ }
+
+ $first= false;
+ }
+ // Render scope if set to auto
+ if ($this->scopeMode == "auto") {
+ $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"toggle-subtree\";\$(\"exec_act\").click();'>".($this->scope=="one"?image("images/empty.png"):image("images/checked.png"))." "._("Search in subtrees")."</a></li>";
}
+
+
+ // Edit filter menu
+ $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"config-filter\";\$(\"exec_act\").click();'>".image("images/configure.png")." "._("Edit filters")."...</a></li>";
+
+ $result.= "</ul>";
+
+ $script= '<script type="text/javascript" language="JavaScript">var menu2; menu2= new Menu("filter-root", "menu2", configMenu)</script>';
+
+ return "<div id='filtermenu'>".$result."</li></ul></div>$script";
+ }
+
+
+ function getFixedFilters()
+ {
+ return array_keys($this->searches);
}
}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
?>