1<?php 2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4 5include_once './Services/Search/classes/class.ilQueryParser.php'; 6 7/** 8* search 9* 10* @author Stefan Meyer <meyer@leifos.com> 11* @version Id$ 12* 13*/ 14class ilSearch 15{ 16 protected $qp = null; 17 18 /** 19 * ilias object 20 * @var object DB 21 * @access public 22 */ 23 public $ilias; 24 public $lng; 25 public $rbacsystem; 26 public $user_id; // INTEGER USED FOR SAVED RESULTS 27 public $search_string; // INPUT FROM SEARCH FORM 28 public $parsed_str; // PARSED INPUT 29 public $combination; // STRING 'and' or 'or' 30 public $min_word_length = 3; // Define minimum character length for queries 31 public $search_for; // OBJECT TYPE 'usr','grp','lm','dbk' 32 public $search_in; // STRING SEARCH IN 'content' OR 'meta' 33 public $search_type; // STRING 'new' or 'result' 34 public $result; // RESULT SET array['object_type']['counter'] 35 public $perform_update; // UPDATE USER SEARCH HISTORY default is true SEE function setPerformUpdate() 36 public $read_db_result; // READ db result true/false 37 38 public $allow_empty_search; // ALLOW EMPTY SEARCH TERM use setEmtySearch(true | false) TO SET THIS VALUE DEFAULT (FALSE) 39 /** 40 * Constructor 41 * @access public 42 */ 43 public function __construct($a_user_id = 0, $a_read = false) 44 { 45 global $DIC; 46 47 $ilias = $DIC['ilias']; 48 $rbacsystem = $DIC['rbacsystem']; 49 $lng = $DIC['lng']; 50 51 // Initiate variables 52 $this->ilias = &$ilias; 53 $this->lng = &$lng; 54 $this->lng->loadLanguageModule("search"); 55 $this->rbacsystem = &$rbacsystem; 56 $this->user_id = $a_user_id; 57 58 $this->setPerformUpdate(true); 59 $this->setEmptySearch(false); 60 $this->read_db_result = $a_read; 61 62 // READ OLD SEARCH RESULTS FROM DATABASE 63 #$this->__readDBResult(); 64 } 65 66 // SET METHODS 67 public function setSearchString($a_search_str) 68 { 69 $this->search_string = trim($a_search_str); 70 } 71 public function setCombination($a_combination) 72 { 73 // 'and' or 'or' 74 $this->combination = $a_combination; 75 } 76 public function setSearchFor($a_search_for) 77 { 78 $this->search_for = $a_search_for; 79 } 80 public function setSearchIn($a_search_in) 81 { 82 $this->search_in = $a_search_in; 83 } 84 public function setResult($a_result) 85 { 86 $this->result = $a_result; 87 } 88 public function setSearchType($a_type) 89 { 90 $this->search_type = $a_type; 91 } 92 public function setPerformUpdate($a_value) 93 { 94 $this->perform_update = $a_value; 95 } 96 public function setEmptySearch($a_value) 97 { 98 $this->allow_empty_search = $a_value; 99 } 100 101 public function setMinWordLength($a_min_word_length) 102 { 103 $this->min_word_length = $a_min_word_length; 104 } 105 public function getMinWordLength() 106 { 107 return $this->min_word_length; 108 } 109 110 // GET MEHODS 111 public function getUserId() 112 { 113 return $this->user_id; 114 } 115 public function getSearchString() 116 { 117 return $this->search_string; 118 } 119 public function getCombination() 120 { 121 return $this->combination ? $this->combination : "or"; 122 } 123 public function getSearchFor() 124 { 125 return $this->search_for ? $this->search_for : array(); 126 } 127 public function getSearchIn() 128 { 129 return $this->search_in ? $this->search_in : array(); 130 } 131 public function getSearchInByType($a_type) 132 { 133 if ($a_type == 'lm' or $a_type == 'dbk') { 134 return $this->search_in[$a_type]; 135 } else { 136 return false; 137 } 138 } 139 public function getResults() 140 { 141 return $this->result ? $this->result : array(); 142 } 143 public function getResultByType($a_type) 144 { 145 return $this->result[$a_type] ? $this->result[$a_type] : array(); 146 } 147 public function getSearchType() 148 { 149 return $this->search_type; 150 } 151 public function getPerformUpdate() 152 { 153 return $this->perform_update; 154 } 155 public function getEmptySearch() 156 { 157 return $this->allow_empty_search; 158 } 159 160 161 // PUBLIC 162 public function getNumberOfResults() 163 { 164 $number = count($this->getResultByType("usr")) + count($this->getResultByType("grp")) + count($this->getResultByType("role")); 165 166 $tmp_res = $this->getResultByType("dbk"); 167 $number += count($tmp_res["meta"]) + count($tmp_res["content"]); 168 169 $tmp_res = $this->getResultByType("lm"); 170 $number += count($tmp_res["meta"]) + count($tmp_res["content"]); 171 172 return $number; 173 } 174 175 public function validate(&$message) 176 { 177 $this->initQueryParser(); 178 179 if (!$this->qp->validate()) { 180 $message = $this->qp->getMessage(); 181 return false; 182 } 183 return true; 184 } 185 186 public function performSearch() 187 { 188 global $DIC; 189 190 $objDefinition = $DIC['objDefinition']; 191 $ilBench = $DIC['ilBench']; 192 193 $ilBench->start("Search", "performSearch"); 194 195 $this->initQueryParser(); 196 197 $result = array("usr" => array(), 198 "grp" => array(), 199 "lm" => array(), 200 "dbk" => array(), 201 "role" => array()); 202 203 foreach ($this->getSearchFor() as $obj_type) { 204 switch ($obj_type) { 205 case "usr": 206 $result['usr'] = $this->performUserSearch(); 207 break; 208 209 case "grp": 210 $result['grp'] = $this->performObjectSearch('grp'); 211 break; 212 213 case "lm": 214 $result['lm'] = $this->performObjectSearch('lm'); 215 break; 216 217 case "dbk": 218 $result['dbk'] = $this->performObjectSearch('dbk'); 219 break; 220 221 case "role": 222 $result['role'] = $this->performRoleSearch(); 223 break; 224 } 225 } 226 227 $this->setResult($result); 228 $this->__validateResults(); 229 230 if ($this->getPerformUpdate()) { 231 $this->__updateDBResult(); 232 } 233 234 $ilBench->stop("Search", "performSearch"); 235 236 return true; 237 } 238 239 240 // PRIVATE METHODS 241 242 public function __parseSearchString() 243 { 244 $tmp_arr = explode(" ", $this->getSearchString()); 245 $this->parsed_str["and"] = $this->parsed_str["or"] = $this->parsed_str["not"] = array(); 246 247 foreach ($tmp_arr as $word) { 248 #$word = trim($word); 249 $word = $this->__prepareWord($word); 250 if ($word) { 251 if (substr($word, 0, 1) == '+') { 252 $this->parsed_str["all"][] = substr($word, 1); 253 $this->parsed_str["and"][] = substr($word, 1); 254 continue; 255 } 256 257 if (substr($word, 0, 1) == '-') { 258 // better parsed_str["allmost_all"] ;-) 259 #$this->parsed_str["all"][] = substr($word,1); 260 $this->parsed_str["not"][] = substr($word, 1); 261 continue; 262 } 263 264 if ($this->getCombination() == 'and') { 265 $this->parsed_str["all"][] = $word; 266 $this->parsed_str["and"][] = $word; 267 continue; 268 } 269 270 if ($this->getCombination() == 'or') { 271 $this->parsed_str["all"][] = $word; 272 $this->parsed_str["or"][] = $word; 273 continue; 274 } 275 } 276 } 277 } 278 279 public function __updateDBResult() 280 { 281 global $DIC; 282 283 $ilDB = $DIC['ilDB']; 284 285 if ($this->getUserId() != 0 and $this->getUserId() != ANONYMOUS_USER_ID) { 286 $ilDB->manipulate("DELETE FROM usr_search " . 287 "WHERE usr_id = " . $ilDB->quote($this->getUserId(), 'integer') . " " . 288 "AND search_type = 0 "); 289 290 $ilDB->insert('usr_search', array( 291 'usr_id' => array('integer',$this->getUserId()), 292 'search_result' => array('clob',serialize($this->getResults())), 293 'checked' => array('clob',serialize(array())), 294 'failed' => array('clob',serialize(array())), 295 'page' => array('integer',0), 296 'search_type' => array('integer',0), 297 'query' => array('text',''), 298 'root' => array('integer',ROOT_FOLDER_ID))); 299 300 return true; 301 } 302 303 return false; 304 } 305 306 public function __readDBResult() 307 { 308 global $DIC; 309 310 $ilDB = $DIC['ilDB']; 311 312 if ($this->getUserId() != 0 and $this->getUserId() != ANONYMOUS_USER_ID and $this->read_db_result) { 313 $query = "SELECT search_result FROM usr_search " . 314 "WHERE usr_id = " . $ilDB->quote($this->getUserId(), 'integer'); 315 316 317 $res = $ilDB->query($query); 318 if ($res->numRows()) { 319 $row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT); 320 $this->setResult(unserialize(stripslashes($row->search_result))); 321 } else { 322 $this->setResult(array("usr" => array(), 323 "grp" => array(), 324 "lm" => array(), 325 "dbk" => array())); 326 } 327 } else { 328 $this->setResult(array("usr" => array(), 329 "grp" => array(), 330 "lm" => array(), 331 "dbk" => array())); 332 } 333 334 $this->__validateResults(); 335 $this->__updateDBResult(); 336 return true; 337 } 338 339 340 public function __checkAccess($a_results, $a_type) 341 { 342 global $DIC; 343 344 $ilAccess = $DIC['ilAccess']; 345 346 if (is_array($a_results)) { 347 foreach ($a_results as $result) { 348 if ($ilAccess->checkAccess('read', '', $result['id'])) { 349 $checked_result[] = $result; 350 break; 351 } 352 } 353 } 354 return $checked_result ? $checked_result : array(); 355 } 356 357 358 public function __validateResults() 359 { 360 global $DIC; 361 362 $tree = $DIC['tree']; 363 364 $new_result = array(); 365 366 367 // check lm meta 368 369 $this->result['lm']['meta'] = $this->__checkAccess($this->result['lm']['meta'], 'lm'); 370 if (is_array($this->result['lm']['meta'])) { 371 foreach ($this->result['lm']['meta'] as $data) { 372 if ($tree->isInTree($data['id'])) { 373 $new_result['lm']['meta'][] = $data; 374 } 375 } 376 } 377 $this->result['lm']['content'] = $this->__checkAccess($this->result['lm']['content'], 'lm'); 378 if (is_array($this->result['lm']['content'])) { 379 foreach ($this->result['lm']['content'] as $data) { 380 if ($tree->isInTree($data['id'])) { 381 $new_result['lm']['content'][] = $data; 382 } 383 } 384 } 385 $this->result['dbk']['meta'] = $this->__checkAccess($this->result['dbk']['meta'], 'dbk'); 386 if (is_array($this->result['dbk']['meta'])) { 387 foreach ($this->result['dbk']['meta'] as $data) { 388 if ($tree->isInTree($data['id'])) { 389 $new_result['dbk']['meta'][] = $data; 390 } 391 } 392 } 393 $this->result['dbk']['content'] = $this->__checkAccess($this->result['dbk']['content'], 'dbk'); 394 if (is_array($this->result['dbk']['content'])) { 395 foreach ($this->result['dbk']['content'] as $data) { 396 if ($tree->isInTree($data['id'])) { 397 $new_result['dbk']['content'][] = $data; 398 } 399 } 400 } 401 $this->result['grp'] = $this->__checkAccess($this->result['grp'], 'grp'); 402 if (is_array($this->result['grp'])) { 403 foreach ($this->result['grp'] as $data) { 404 if ($tree->isInTree($data['id'])) { 405 $new_result['grp'][] = $data; 406 } 407 } 408 } 409 if (is_array($this->result['usr'])) { 410 foreach ($this->result['usr'] as $user) { 411 if ($tmp_obj = &ilObjectFactory::getInstanceByObjId($user['id'], false)) { 412 $new_result['usr'][] = $user; 413 } 414 } 415 } 416 if (is_array($this->result['role'])) { 417 foreach ($this->result['role'] as $user) { 418 if ($tmp_obj = &ilObjectFactory::getInstanceByObjId($user['id'], false)) { 419 $new_result['role'][] = $user; 420 } 421 } 422 } 423 $this->setResult($new_result); 424 425 return true; 426 } 427 428 public function __prepareWord($a_word) 429 { 430 $word = trim($a_word); 431 432 if (!preg_match('/\*/', $word)) { 433 return '%' . $word . '%'; 434 } 435 if (preg_match('/^\*/', $word)) { 436 return str_replace('*', '%', $word); 437 } else { 438 return '% ' . str_replace('*', '%', $word); 439 } 440 } 441 442 /** 443 * perform a search for users 444 * @return 445 */ 446 protected function performUserSearch() 447 { 448 include_once 'Services/Search/classes/class.ilObjectSearchFactory.php'; 449 450 $user_search = ilObjectSearchFactory::_getUserSearchInstance($this->qp); 451 $res = new ilSearchResult($this->getUserId()); 452 453 foreach (array("login","firstname","lastname","title", 454 "email","institution","street","city","zipcode","country","phone_home","fax") as $field) { 455 $user_search->setFields(array($field)); 456 $tmp_res = $user_search->performSearch(); 457 458 $res->mergeEntries($tmp_res); 459 } 460 461 foreach ($res->getEntries() as $id => $data) { 462 $tmp['id'] = $id; 463 $users[] = $tmp; 464 } 465 return $users ? $users : array(); 466 } 467 468 /** 469 * perform object search 470 * @return 471 */ 472 protected function performObjectSearch($a_type) 473 { 474 include_once 'Services/Search/classes/Like/class.ilLikeObjectSearch.php'; 475 $object_search = new ilLikeObjectSearch($this->qp); 476 $object_search->setFilter(array($a_type)); 477 $res = $object_search->performSearch(); 478 $res->filter(ROOT_FOLDER_ID, $this->getCombination()); 479 480 $counter = 0; 481 foreach ($res->getResultIds() as $id) { 482 $objs[$counter++]['id'] = $id; 483 } 484 return $objs ? $objs : array(); 485 } 486 487 /** 488 * 489 * @param 490 * @return 491 */ 492 protected function performRoleSearch() 493 { 494 // Perform like search 495 include_once 'Services/Search/classes/Like/class.ilLikeObjectSearch.php'; 496 $object_search = new ilLikeObjectSearch($this->qp); 497 $object_search->setFilter(array('role')); 498 499 $res = $object_search->performSearch(); 500 foreach ($res->getEntries() as $id => $data) { 501 $tmp['id'] = $id; 502 $roles[] = $tmp; 503 } 504 return $roles ? $roles : array(); 505 } 506 507 /** 508 * init query parser 509 * @return 510 */ 511 protected function initQueryParser() 512 { 513 if ($this->qp) { 514 return true; 515 } 516 517 $this->qp = new ilQueryParser($this->getSearchString()); 518 $this->qp->setCombination($this->getCombination() == 'and' ? QP_COMBINATION_AND : QP_COMBINATION_OR); 519 $this->qp->setMinWordLength($this->getMinWordLength()); 520 $this->qp->parse(); 521 } 522} // END class.ilSearch 523