Platform  3.1
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.SearchDoc.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  * Search Document
9  *
10  * @author Anakeen 2008
11  * @version $Id: Class.SearchDoc.php,v 1.8 2008/08/14 14:20:25 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/Lib.Dir.php");
19 
20 class SearchDoc
21 {
22  /**
23  * family identificator filter
24  * @public string
25  */
26  public $fromid;
27  /**
28  * folder identificator filter
29  * @public int
30  */
31  public $dirid = 0;
32  /**
33  * recursive search for folders
34  * @public boolean
35  */
36  public $recursiveSearch = false;
37  /**
38  * max recursive level
39  * @public int
40  */
42  /**
43  * number of results : set "ALL" if no limit
44  * @public int
45  */
46  public $slice = "ALL";
47  /**
48  * index of results begins
49  * @public int
50  */
51  public $start = 0;
52  /**
53  * sql filters
54  * @public array
55  */
56  public $filters = array();
57  /**
58  * search in sub-families set false if restriction to top family
59  * @public bool
60  */
61  public $only = false;
62  /**
63  *
64  * @public bool
65  */
66  public $distinct = false;
67  /**
68  * order of result : like sql order
69  * @public string
70  */
71  public $orderby = "title";
72  /**
73  * to search in trash : [no|also|only]
74  * @public string
75  */
76  public $trash = "";
77  /**
78  * restriction to latest revision
79  * @public bool
80  */
81  public $latest = true;
82  /**
83  * user identificator : set to current user by default
84  * @public int
85  */
86  public $userid = 0;
87  /**
88  * debug mode : to view query and delay
89  * @public bool
90  */
91  private $debug = false;
92  private $debuginfo = "";
93  private $join = "";
94  /**
95  * sql filter not return confidential document if current user cannot see it
96  * @var string
97  */
98  private $excludeFilter = "";
99  /**
100  *
101  * Iterator document
102  * @var Doc
103  */
104  private $iDoc = null;
105  /**
106  *
107  * Iterator document
108  * @var Array of doc
109  */
110  private $cacheDocuments = array();
111  /**
112  * result type [ITEM|TABLE]
113  * @private string
114  */
115  private $mode = "TABLE";
116  private $count = - 1;
117  private $index = 0;
118  private $result;
119  /**
120  * initialize with family
121  *
122  * @param string $dbaccess database coordinate
123  * @param string $fromid family identificator to filter
124  *
125  */
126  public function __construct($dbaccess, $fromid = 0)
127  {
128  if ($dbaccess == "") $dbaccess = getDbAccess();
129  $this->dbaccess = $dbaccess;
130  $this->fromid = $fromid;
131  $this->orderby = 'title';
132  $this->userid = getUserId();
133  }
134  /**
135  * count results without return data
136  *
137  * @return int the number of results
138  */
139  public function onlyCount()
140  {
141  if (!$this->result) {
142  $fld = new_Doc($this->dbaccess, $this->dirid);
143  $userid = $fld->userid;
144  if ($fld->fromid != getFamIdFromName($this->dbaccess, "SSEARCH")) {
145  $this->mode = "ITEM";
146  if ($this->debug) $debuginfo = array();
147  else $debuginfo = null;
148  $tqsql = getSqlSearchDoc($this->dbaccess, $this->dirid, $this->fromid, $this->getFilters() , $this->distinct, $this->latest, $this->trash, false, $this->folderRecursiveLevel, $this->join);
149  $this->debuginfo["query"] = $tqsql[0];
150  $count = 0;
151  if (!is_array($tqsql)) {
152  $this->debuginfo["err"] = _("cannot produce sql request");
153  return 0;
154  }
155  foreach ($tqsql as $sql) {
156  if ($sql) {
157  if (preg_match('/from\s+([a-z0-9_\-]*)/', $sql, $reg)) $maintable = $reg[1];
158  else $maintable = '';
159  $maintabledot = ($maintable) ? $maintable . '.' : '';
160 
161  $mainid = ($maintable) ? "$maintable.id" : "id";
162  $sql = preg_replace('/select\s+(.*)\s+from\s/', "select count($mainid) from ", $sql);
163 
164  if ($userid != 1) $sql.= " and (${maintabledot}profid <= 0 or hasviewprivilege($userid, ${maintabledot}profid))";
165  $dbid = getDbid($this->dbaccess);
166  $mb = microtime(true);
167  $q = @pg_query($dbid, $sql);
168  if (!$q) {
169  $this->debuginfo["query"] = $sql;
170  $this->debuginfo["error"] = pg_last_error($dbid);
171  } else {
172  $result = pg_fetch_array($q, 0, PGSQL_ASSOC);
173  $count+= $result["count"];
174  $this->debuginfo["delay"] = sprintf("%.03fs", microtime(true) - $mb);
175  }
176  }
177  }
178  $this->count = $count;
179  return $count;
180  } else {
181  $this->count = count($fld->getContent());
182  }
183  } else $this->count();
184  return $this->count;
185  }
186  /**
187  * return original sql query before test permissions
188  *
189  * @return string
190  */
191  public function getOriginalQuery()
192  {
193  $tqsql = getSqlSearchDoc($this->dbaccess, $this->dirid, $this->fromid, $this->getFilters() , $this->distinct, $this->latest, $this->trash, false, $this->folderRecursiveLevel, $this->join);
194 
195  return $tqsql[0];
196  }
197  public function join($jointure)
198  {
199  $this->join = $jointure;
200  }
201  /**
202  * count results
203  * ::search must be call before
204  *
205  * @return int
206  *
207  */
208  public function count()
209  {
210  if ($this->count == - 1) {
211  if ($this->searchmode == "ITEM") {
212  $this->count = countDocs($this->result);
213  } else {
214  $this->count = count($this->result);
215  }
216  }
217  return $this->count;
218  }
219  /**
220  *reset results to use another search
221  * @return void
222  */
223  public function reset()
224  {
225  $this->result = false;
226  $this->debuginfo = "";
227  }
228  /**
229  * Verify if query is already sended to database
230  * @return boolean
231  */
232  public function isExecuted()
233  {
234  return ($this->result != false);
235  }
236  /**
237  * Return sql filters used for request
238  * @return array of string
239  */
240  public function getFilters()
241  {
242  if (!$this->excludeFilter) {
243  return $this->filters;
244  } else {
245  return array_merge(array(
246  $this->excludeFilter
247  ) , $this->filters);
248  }
249  }
250  /**
251  * send search
252  *
253  * @return array of documents
254  *
255  */
256  public function search()
257  {
258  if ($this->getError()) return array();
259  if ($this->fromid) {
260  if (!is_numeric($this->fromid)) {
261  $fromid = getFamIdFromName($this->dbaccess, $this->fromid);
262  } else {
263  if ($this->fromid != - 1) {
264  // test if it is a family
265  if ($this->fromid < - 1) {
266  $this->only = true;
267  }
268  $err = simpleQuery($this->dbaccess, sprintf("select doctype from docfam where id=%d", abs($this->fromid)) , $doctype, true, true);
269  if ($doctype != 'C') $fromid = 0;
270  else $fromid = $this->fromid;
271  } else $fromid = $this->fromid;
272  }
273  if ($fromid == 0) {
274  $error = sprintf(_("%s is not a family") , $this->fromid);
275  $this->debuginfo["error"] = $error;
276  error_log("ERROR SearchDoc: " . $error);
277  if ($this->mode == "ITEM") return null;
278  else return array();
279  }
280  if ($this->only) $this->fromid = - (abs($fromid));
281  else $this->fromid = $fromid;
282  }
283  if ($this->recursiveSearch && $this->dirid) {
284  $tmps = createTmpDoc($this->dbaccess, "SEARCH");
285  $tmps->setValue("se_idfld", $this->dirid);
286  $tmps->setValue("se_latest", "yes");
287  $err = $tmps->add();
288  if ($err == "") {
289  $tmps->addQuery($tmps->getQuery()); // compute internal sql query
290  $this->dirid = $tmps->id;
291  }
292  }
293  $this->index = 0;
294  $this->searchmode = $this->mode;
295  if ($this->mode == "ITEM") {
296  // change search mode because ITEM mode not supported for Specailized searches
297  $fld = new_Doc($this->dbaccess, $this->dirid);
298  if ($fld->fromid == getFamIdFromName($this->dbaccess, "SSEARCH")) $this->searchmode = "TABLE";
299  }
300  $debuginfo = array();
301 
302  $this->result = getChildDoc($this->dbaccess, $this->dirid, $this->start, $this->slice, $this->getFilters() , $this->userid, $this->searchmode, $this->fromid, $this->distinct, $this->orderby, $this->latest, $this->trash, $debuginfo, $this->folderRecursiveLevel, $this->join);
303  if ($this->searchmode == "TABLE") $this->count = count($this->result); // memo cause array is unset by shift
304  $this->debuginfo = $debuginfo;
305  if (($this->searchmode == "TABLE") && ($this->mode == "ITEM")) $this->mode = "TABLEITEM";
306 
307  if ($this->mode == "ITEM") return $this;
308 
309  return $this->result;
310  }
311 
312  public function getDocumentList()
313  {
314  include_once ("FDL/Class.DocumentList.php");
315  return new DocumentList($this);
316  }
317  /**
318  *
319  */
320  public function searchError()
321  {
322  return ($this->debuginfo["error"]);
323  }
324  /**
325  * Return error message
326  * @return string
327  */
328  public function getError()
329  {
330  if ($this->debuginfo) return $this->debuginfo["error"];
331  return "";
332  }
333  /**
334  * do the search in debug mode, you can after the search get infrrmation with getDebugIndo()
335  * @param boolean $debug set to true search in debug mode
336  * @deprecated
337  * @return void
338  */
339  public function setDebugMode($debug = true)
340  {
342  $this->debug = $debug;
343  }
344  /**
345  * set recursive mode for folder searches
346  *
347  * @return void
348  */
349  public function setRecursiveSearch($b = true)
350  {
351  $this->recursiveSearch = $b;
352  }
353  /**
354  * return debug info if debug mode enabled
355  * @deprecated
356  *
357  * @return array of info
358  */
359  public function getDebugInfo()
360  {
362  return $this->debuginfo;
363  }
364  /**
365  * return information about query after search is call
366  *
367  * @return array of info
368  */
369  public function getSearchInfo()
370  {
371  return $this->debuginfo;
372  }
373  /**
374  * set maximum number of document to return
375  * @param int $slice the limit ('ALL' means no limit)
376  *
377  * @return Boolean
378  */
379  public function setSlice($slice)
380  {
381  if ((!is_numeric($slice)) && ($slice != 'ALL')) return false;
382  $this->slice = $slice;
383  return true;
384  }
385  /**
386  * use different order , default is title
387  * @param string $order the new order, empty means no order
388  *
389  * @return Boolean
390  */
391  public function setOrder($order)
392  {
393  $this->orderby = $order;
394  return true;
395  }
396  /**
397  * use folder or search document to apply restrict the search
398  * @param int $dirid identificator of the collection
399  *
400  * @return Boolean true if set
401  */
402  public function useCollection($dirid)
403  {
404  $dir = new_doc($this->dbaccess, $dirid);
405  if ($dir->isAlive()) {
406  $this->dirid = $dir->initid;
407  return true;
408  }
409  $this->debuginfo["error"] = sprintf(_("collection %s not exists") , $dirid);
410 
411  return false;
412  }
413  /**
414  * set offset where start the result window
415  * @param int $start the offset (0 is the begin)
416  *
417  * @return Boolean true if set
418  */
419  public function setStart($start)
420  {
421  if (!(is_numeric($start))) return false;
422  $this->start = intval($start);
423  return true;
424  }
425  /**
426  * can, be use in
427  * ::search must be call before
428  *
429  * @return Doc or null if this is the end
430  */
431  public function nextDoc()
432  {
433  if ($this->mode == "ITEM") {
434  $n = current($this->result);
435  if ($n === false) return false;
436  $tdoc = pg_fetch_array($n, NULL, PGSQL_ASSOC);
437  if ($tdoc === false) {
438  $n = next($this->result);
439  if ($n === false) return false;
440  $tdoc = pg_fetch_array($n, NULL, PGSQL_ASSOC);
441  if ($tdoc === false) return false;
442  }
443  return $this->iDoc = $this->getNextDocument($tdoc);
444  } elseif ($this->mode == "TABLEITEM") {
445  $tdoc = array_shift($this->result);
446  if (!is_array($tdoc)) return false;
447  return $this->iDoc = $this->getNextDocument($tdoc);
448  } else return array_shift($this->result);
449  }
450  /**
451  * Return an object document from array of values
452  *
453  * @param array $v the values of documents
454  * @return Doc the document object
455  */
456  protected function getNextDocument(Array $v)
457  {
458  $fromid = $v["fromid"];
459  if ($v["doctype"] == "C") {
460  if (!isset($this->cacheDocuments["family"])) $this->cacheDocuments["family"] = new DocFam($this->dbaccess);
461  $this->cacheDocuments["family"]->Affect($v, true);
462  $fromid = "family";
463  } else {
464  if (!isset($this->cacheDocuments[$fromid])) {
465  $this->cacheDocuments[$fromid] = createDoc($this->dbaccess, $fromid, false, false);
466  }
467  }
468  $this->cacheDocuments[$fromid]->Affect($v, true);
469  $this->cacheDocuments[$fromid]->nocache = true;
470  return $this->cacheDocuments[$fromid];
471  }
472  /**
473  * add a condition in filters
474  * @param string $filter the filter string
475  * @param string $args arguments of the filter string (arguments are escaped to avoid sql injection)
476  * @return void
477  */
478  public function addFilter($filter)
479  {
480 
481  if ($filter != "") {
482  $args = func_get_args();
483  if (count($args) > 1) {
484  $fs[0] = $args[0];
485  for ($i = 1; $i < count($args); $i++) {
486  $fs[] = pg_escape_string($args[$i]);
487  }
488  $filter = call_user_func_array("sprintf", $fs);
489  }
490  if (preg_match('/^([a-z0-9_\-]+)\./', $filter, $reg)) {
491  // when use join filter like "zoo_espece.es_classe='Boo'"
492  $famid = getFamIdFromName($this->dbaccess, $reg[1]);
493  if ($famid > 0) $filter = preg_replace('/^([a-z0-9_\-]+)\./', "doc" . $famid . '.', $filter);
494  }
495  $this->filters[] = $filter;
496  }
497  }
498 
499  static function sqlcond($values, $column, $integer = false)
500  {
501  $sql_cond = "true";
502  if (count($values) > 0) {
503  if ($integer) { // for integer type
504  $sql_cond = "$column in (";
505  $sql_cond.= implode(",", $values);
506  $sql_cond.= ")";
507  } else { // for text type
508  foreach ($values as & $v) $v = pg_escape_string($v);
509  $sql_cond = "$column in ('";
510  $sql_cond.= implode("','", $values);
511  $sql_cond.= "')";
512  }
513  }
514 
515  return $sql_cond;
516  }
517  /**
518  * add a condition in filters
519  *
520  * @return void
521  */
522  public function noViewControl()
523  {
524  $this->userid = 1;
525  }
526  /**
527  * the return of ::search will be array of document's object
528  *
529  * @return void
530  */
531  public function setObjectReturn($returnobject = true)
532  {
533  if ($returnobject) $this->mode = "ITEM";
534  else $this->mode = "TABLE";
535  }
536  /**
537  * the return of ::search will be array of values
538  * @deprecated
539  * @return void
540  */
541  public function setValueReturn()
542  {
544  $this->mode = "TABLE";
545  }
546  /**
547  * add a filter to not return confidential document if current user cannot see it
548  * @param boolean $exclude set to true to exclude confidential
549  * @return void
550  */
551  function excludeConfidential($exclude = true)
552  {
553  if ($exclude) {
554  if ($this->userid != 1) $this->excludeFilter = sprintf("confidential is null or hasdocprivilege(%d, profid,%d)", $this->userid, 1 << POS_CONF);
555  } else {
556  $this->excludeFilter = '';
557  }
558  }
559 }
560 ?>
← centre documentaire © anakeen - published under CC License - Dynacase