Platform  3.1
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.DocSearch.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
5  * @package FDL
6 */
7 /**
8  * Document searches classes
9  *
10  * @author Anakeen 2000
11  * @version $Id: Class.DocSearch.php,v 1.56 2008/11/19 08:47:46 eric Exp $
12  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
13  * @package FDL
14  */
15 /**
16  */
17 
18 include_once ("FDL/Class.PDocSearch.php");
19 include_once ("FDL/Lib.Dir.php");
20 
21 class DocSearch extends PDocSearch
22 {
23 
24  public $defDoctype = 'S';
25  public $defaultedit = "FREEDOM:EDITSEARCH";
26 
27  public $tol = array(
28  "and" => "and", #N_("and")
29  "or" => "or"
30  ); #N_("or")
31 
32 
33  /**
34  * max recursive level
35  * @public int
36  */
38 
39  function DocSearch($dbaccess = '', $id = '', $res = '', $dbid = 0)
40  {
41 
42  PDocSearch::__construct($dbaccess, $id, $res, $dbid);
43  if (((!isset($this->fromid))) || ($this->fromid == "")) $this->fromid = FAM_SEARCH;
44  }
45  /**
46  * to affect a special query to a SEARCH document
47  * must be call after the add method When use this method others filter parameters are ignored.
48  * @param string $tquery the sql query
49  * @return string error message (empty if no error)
50  */
51  function addStaticQuery($tquery)
52  {
53  $this->setValue("se_static", "1");
54  $err = $this->addQuery($tquery);
55  return $err;
56  }
57 
58  function AddQuery($tquery)
59  {
60  // insert query in search document
61  if (is_array($tquery)) $query = implode(";\n", $tquery);
62  else $query = $tquery;
63 
64  if ($query == "") return "";
65  if ($this->id == "") return "";
66 
67  if (substr($query, 0, 6) != "select") {
68  AddWarningMsg(sprintf(_("query [%s] not valid for select document") , $query));
69  return sprintf(_("query [%s] not valid for select document") , $query);
70  }
71  $oqd = new QueryDir($this->dbaccess);
72  $oqd->dirid = $this->id;
73  $oqd->qtype = "M"; // multiple
74  $oqd->query = $query;
75 
76  if ($this->id > 0) $this->exec_query("delete from fld where dirid=" . intval($this->id) . " and qtype='M'");
77  $err = $oqd->Add();
78  if ($err == "") {
79  $this->setValue("SE_SQLSELECT", $query);
80  $err = $this->modify();
81  }
82 
83  return $err;
84  }
85  /**
86  * Test if current user can add or delete document in this folder
87  * always false for a search
88  * @return string error message, if no error empty string
89  */
90  function canModify()
91  {
92  return _("containt of searches cannot be modified");
93  }
94  /**
95  * return true if the search has parameters
96  */
97  function isParameterizable()
98  {
99  return false;
100  }
101 
102  function GetQueryOld()
103  {
104  $query = new QueryDb($this->dbaccess, "QueryDir");
105  $query->AddQuery("dirid=" . $this->id);
106  $query->AddQuery("qtype != 'S'");
107  $tq = $query->Query(0, 0, "TABLE");
108 
109  if ($query->nb > 0) {
110  return $tq[0]["query"];
111  }
112  return "";
113  }
114  /**
115  * return SQL query(ies) needed to search documents
116  * @return array string
117  */
118  function getQuery()
119  {
120  if (!$this->isStaticSql()) {
121  $query = $this->ComputeQuery($this->getValue("se_key") , $this->getValue("se_famid") , $this->getValue("se_latest") , $this->getValue("se_case") == "yes", $this->getValue("se_idfld") , $this->getValue("se_sublevel") === "", $this->getValue("se_case") == "full");
122  // print "<HR>getQuery1:[$query]";
123 
124  } else {
125  $query[] = $this->getValue("SE_SQLSELECT");
126  // print "<BR><HR>".$this->getValue("se_latest")."/".$this->getValue("se_case")."/".$this->getValue("se_key");
127  // print "getQuery2:[$query]";
128 
129  }
130 
131  return $query;
132  }
133  /**
134  * @param bool $full set to true if wan't use full text indexing
135  */
136  function getSqlGeneralFilters($keyword, $latest, $sensitive, $full = false)
137  {
138  $filters = array();
139 
140  $acls = $this->getTValue("se_acl");
141  if (count($acls) > 0) {
142  // print_r2($acls);
143  foreach ($acls as $acl) {
144  $dacl = $this->dacls[$acl];
145  if ($dacl) {
146  $posacl = $dacl["pos"];
147  $filters[] = "hasdocprivilege(" . $this->userid . ",profid," . (1 << intval($posacl)) . ")";
148  }
149  }
150  }
151 
152  if ($latest == "fixed") {
153  $filters[] = "locked = -1";
154  $filters[] = "lmodify = 'L'";
155  } else if ($latest == "allfixed") {
156  $filters[] = "locked = -1";
157  }
158  if ($latest == "lastfixed") {
159  $filters[] = "locked = -1";
160  }
161 
162  if ($this->getValue("se_archive") > 0) {
163  $filters[] = sprintf("archiveid = %d", $this->getValue("se_archive"));
164  }
165  if ($keyword[0] == '~') {
166  $full = false; // force REGEXP
167  $keyword = substr($keyword, 1);
168  } else if ($keyword[0] == '*') {
169  $full = true; // force FULLSEARCH
170  $keyword = substr($keyword, 1);
171  }
172  if ($full) {
173  $this->getFullSqlFilters($keyword, $sqlfilters, $order, $tkeys);
174  $filters = array_merge($filters, $sqlfilters);
175  $this->setValue("se_orderby", $order);
176  } else {
177  $op = ($sensitive) ? '~' : '~*';
178  // $filters[] = "usefor != 'D'";
179  $keyword = pg_escape_string($keyword);
180  $keyword = str_replace("^", "£", $keyword);
181  $keyword = str_replace("$", "\0", $keyword);
182  if (strtolower(substr($keyword, 0, 5)) == "::get") { // only get method allowed
183  // it's method call
184  $keyword = $this->ApplyMethod($keyword);
185  $filters[] = "svalues $op '$keyword' ";
186  } else if ($keyword != "") {
187  // transform conjonction
188  $tkey = explode(" ", $keyword);
189  $ing = false;
190  foreach ($tkey as $k => $v) {
191  if ($ing) {
192  if ($v[strlen($v) - 1] == '"') {
193  $ing = false;
194  $ckey.= " " . substr($v, 0, -1);
195  $filters[] = "svalues $op '$ckey' ";
196  } else {
197  $ckey.= " " . $v;
198  }
199  } else if ($v[0] == '"') {
200  if ($v[strlen($v) - 1] == '"') {
201  $ckey = substr($v, 1, -1);
202  $filters[] = "svalues $op '$ckey' ";
203  } else {
204  $ing = true;
205  $ckey = substr($v, 1);
206  }
207  } else {
208  $filters[] = "svalues $op '$v' ";
209  }
210  }
211  }
212  $this->setValue("se_orderby", " ");
213  }
214  return $filters;
215  }
216  /**
217  * return sqlfilters for a simple query in fulltext mode
218  * @param string $keyword the word(s) searched
219  * @param array &$sqlfilters return array of sql conditions
220  * @param string &$sqlorder return sql order by
221  * @param string &$fullkeys return tsearch2 keys for use it in headline sql function
222  */
223  static function getFullSqlFilters($keyword, &$sqlfilters, &$sqlorder, &$fullkeys)
224  {
225  $fullkeys = "";
226  $sqlorder = "";
227  $sqlfilters = array(
228  "true"
229  );
230  if ($keyword == "") return;
231  $pspell_link = false;
232  if (function_exists('pspell_new')) {
233  $pspell_link = pspell_new("fr", "", "", "utf-8", PSPELL_FAST);
234  }
235  $tkeys = array();
236  $sqlfilters = array();
237  if (count($tstatickeys) > 2) {
238  //each odd
239  $keyword = "";
240  foreach ($tstatickeys as $k => $v) {
241  if (($k % 2) == 1) {
242  $tkeybrut[] = $v;
243 
244  $keyword.= " (\"" . str_replace(" ", "&", trim($v)) . "\")";
245  } else {
246  $keyword.= " " . trim($v);
247  }
248  }
249  }
250 
251  $keyword = preg_replace('/\s+(OR)\s+/', '|', $keyword);
252  $tkeys = explode(" ", $keyword);
253  $sqlfiltersbrut = array();
254  foreach ($tkeys as $k => $key) {
255  $key = trim($key);
256  if ($key) {
257  $tsearchkeys[$k] = $key;
258  if ($pspell_link !== false) {
259  if ((!is_numeric($key)) && (strstr($key, '|') === false) && (strstr($key, '&') === false) && (ord($key[0]) > 47) && (!pspell_check($pspell_link, $key))) {
260  $suggestions = pspell_suggest($pspell_link, $key);
261  $sug = $suggestions[0];
262  //foreach ($suggestions as $k=>$suggestion) { echo "$k : $suggestion\n"; }
263  if ($sug && (unaccent($sug) != $key) && (!strstr($sug, ' '))) $tsearchkeys[$k] = "$key|$sug";
264  }
265  }
266  if (strstr($key, '"') !== false) {
267  // add more filter for search complete and exact expression
268  if (strstr($key, '|') === false) {
269  $sqlfiltersbrut[] = "svalues ~* '\\\\y" . pg_escape_string(str_replace(array(
270  '"',
271  '&',
272  '(',
273  ')'
274  ) , array(
275  "",
276  ' ',
277  '',
278  ''
279  ) , $key)) . "\\\\y' ";
280  } else {
281  list($left, $right) = explode("|", $key);
282  if (strstr($left, '"') !== false) $q1 = "svalues ~* '\\\\y" . pg_escape_string(str_replace(array(
283  '"',
284  '&',
285  '(',
286  ')'
287  ) , array(
288  "",
289  ' ',
290  '',
291  ''
292  ) , $left)) . "\\\\y' ";
293  else $q1 = "";
294  if (strstr($right, '"') !== false) $q2 = "svalues ~* '\\\\y" . pg_escape_string(str_replace(array(
295  '"',
296  '&',
297  '(',
298  ')'
299  ) , array(
300  "",
301  ' ',
302  '',
303  ''
304  ) , $right)) . "\\\\y' ";
305  else $q2 = "";
306  $q3 = "fulltext @@ to_tsquery('french','" . pg_escape_string(unaccent($left)) . "') ";
307  $q4 = "fulltext @@ to_tsquery('french','" . pg_escape_string(unaccent($right)) . "') ";
308 
309  if ((!$q1) && $q2) $sqlfiltersbrut[] = "($q4 and $q2) or $q3";
310  elseif ((!$q2) && $q1) $sqlfiltersbrut[] = "($q3 and $q1) or $q4";
311  elseif ($q2 && $q1) $sqlfiltersbrut[] = "($q3 and $q1) or ($q4 and $q2)";
312  }
313  }
314  }
315  }
316 
317  if (count($tsearchkeys) > 0) {
318  $fullkeys = '(' . implode(")&(", $tsearchkeys) . ')';
319  $fullkeys = unaccent($fullkeys);
320  $fullkeys = pg_escape_string($fullkeys);
321  $sqlfilters[] = "fulltext @@ to_tsquery('french','$fullkeys') ";
322  }
323  if (count($sqlfiltersbrut) > 0) $sqlfilters = array_merge($sqlfilters, $sqlfiltersbrut);
324  $sqlorder = "ts_rank(fulltext,to_tsquery('french','$fullkeys')) desc";
325  }
326 
327  function ComputeQuery($keyword = "", $famid = - 1, $latest = "yes", $sensitive = false, $dirid = - 1, $subfolder = true, $full = false)
328  {
329  if ($dirid > 0) {
330  if ($subfolder) $cdirid = getRChildDirId($this->dbaccess, $dirid, array() , 0, $this->folderRecursiveLevel);
331  else $cdirid = $dirid;
332  } else $cdirid = 0;
333 
334  if ($keyword[0] == '~') {
335  $full = false;
336  $keyword = substr($keyword, 1);
337  } else if ($keyword[0] == '*') {
338  $full = true;
339  $keyword = substr($keyword, 1);
340  }
341  $filters = $this->getSqlGeneralFilters($keyword, $latest, $sensitive, $full);
342 
343  if ($this->getValue("se_famonly") == "yes") {
344  if (!is_numeric($famid)) $famid = getFamIdFromName($this->dbaccess, $famid);
345  $famid = - abs($famid);
346  }
347 
348  $query = getSqlSearchDoc($this->dbaccess, $cdirid, $famid, $filters, false, $latest == "yes", $this->getValue("se_trash"));
349 
350  return $query;
351  }
352  /**
353  * return true if the sqlselect is writted by hand
354  * @return bool
355  */
356  function isStaticSql()
357  {
358  return ($this->getValue("se_static") != "") || (($this->getValue("se_latest") == "") && ($this->getValue("se_case") == "") && ($this->getValue("se_key") == ""));
359  }
360  /**
361  * return error if query filters are not compatibles
362  * @return string error message , empty if no errors
363  */
364  function getSqlParseError()
365  {
366  return "";
367  }
368 
369  function SpecRefresh()
370  {
371  $err = "";
372 
373  if (!$this->isStaticSql()) {
374  if (!$this->isParameterizable()) $query = $this->getQuery();
375  else $query = 'select id from only doc where false';
376  $err = $this->AddQuery($query);
377  }
378  if ($err == "") $err = $this->getSqlParseError();
379  return $err;
380  }
381  function editsearch()
382  {
383  global $action;
384 
385  $rtarget = getHttpVars("rtarget");
386  $this->lay->set("rtarget", $rtarget);
387  $this->lay->set("restrict", false);
388  $this->lay->set("archive", false);
389 
390  $farch = new_doc($this->dbaccess, "ARCHIVING");
391  if ($farch) $this->lay->set("archive", ($farch->control("view") == ""));
392  $this->lay->set("thekey", $this->getValue("se_key"));
393  $dirid = GetHttpVars("dirid"); // to set restriction family
394  $action->parent->AddJsRef($action->GetParam("CORE_PUBURL") . "/FDL/Layout/edittable.js");
395  $action->parent->AddJsRef($action->GetParam("CORE_PUBURL") . "/FREEDOM/Layout/editdsearch.js");
396  $famid = $this->getValue("se_famid");
397  $classid = 0;
398  if ($dirid > 0) {
399  $dir = new_Doc($this->dbaccess, $dirid);
400  if (method_exists($dir, "isAuthorized")) {
401  if ($dir->isAuthorized($classid)) {
402  // verify if classid is possible
403  if ($dir->hasNoRestriction()) $tclassdoc = GetClassesDoc($this->dbaccess, $action->user->id, $classid, "TABLE");
404  else {
405  $tclassdoc = $dir->getAuthorizedFamilies();
406  $this->lay->set("restrict", true);
407  }
408  } else {
409  $tclassdoc = $dir->getAuthorizedFamilies();
410  $first = current($tclassdoc);
411  $famid = abs($first["id"]);
412  $this->lay->set("restrict", true);
413  }
414  } else {
415  $tclassdoc = GetClassesDoc($this->dbaccess, $action->user->id, $classid, "TABLE");
416  }
417  } else {
418  $tclassdoc = GetClassesDoc($this->dbaccess, $action->user->id, $classid, "TABLE");
419  }
420 
421  $this->lay->set("selfam", _("no family"));
422 
423  foreach ($tclassdoc as $k => $cdoc) {
424  $selectclass[$k]["idcdoc"] = $cdoc["id"];
425  $selectclass[$k]["classname"] = $cdoc["title"];
426  if (abs($cdoc["initid"]) == abs($famid)) {
427  $selectclass[$k]["selected"] = "selected";
428  if ($famid < 0) $this->lay->set("selfam", $cdoc["title"] . " " . !!_("(only)"));
429  else $this->lay->set("selfam", $cdoc["title"]);
430  } else $selectclass[$k]["selected"] = "";
431  }
432 
433  $this->lay->SetBlockData("SELECTCLASS", $selectclass);
434 
435  $this->editattr();
436  }
437 
438  function editspeedsearch()
439  {
440  return $this->editsearch();
441  }
442  /**
443  * return document includes in search folder
444  * @param bool $controlview if false all document are returned else only visible for current user document are return
445  * @param array $filter to add list sql filter for selected document
446  * @param int $famid family identificator to restrict search
447  * @return array array of document array
448  */
449  function getContent($controlview = true, $filter = array() , $famid = "")
450  {
451  if ($controlview) $uid = $this->userid;
452  else $uid = 1;
453  $orderby = $this->getValue("se_orderby", "title");
454  $tdoc = getChildDoc($this->dbaccess, $this->initid, 0, "ALL", $filter, $uid, "TABLE", $famid, false, $orderby, true, $this->getValue("se_trash"));
455  return $tdoc;
456  }
457 }
458 ?>
← centre documentaire © anakeen - published under CC License - Dynacase