Framework  3.9
search_form.inc
Go to the documentation of this file.
1 <?php
5 /**************************************************************
6 
7  Copyright (c) 2007-2010 Sonjara, Inc
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  Except as contained in this notice, the name(s) of the above
22  copyright holders shall not be used in advertising or otherwise
23  to promote the sale, use or other dealings in this Software
24  without prior written authorization.
25 
26  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  OTHER DEALINGS IN THE SOFTWARE.
34 
35 *****************************************************************/
36 
37 require_once realpath(dirname(__FILE__)."/auto_form.inc");
38 
51 {
58  function equal($name, $value)
59  {
60  }
61 
69  function like($name, $value)
70  {
71  }
72 
80  function startsWith($name, $value)
81  {
82 
83  }
84 
92  function from($name, $from)
93  {
94 
95  }
96 
104  function to($name, $to)
105  {
106 
107  }
108 
117  function range($name, $from, $to)
118  {
119  }
120 
121 
130  function member($name, $set)
131  {
132  }
133 
134 
143  function any($name, $value)
144  {
145  }
146 
156  function all($name, $value)
157  {
158  }
159 
169  function fullName($f_name, $l_name, $value)
170  {
171 
172  }
173 
180  function checked($name, $value)
181  {
182  }
183 }
184 
191 {
192  function equal($name, $value)
193  {
194  checkNumeric($value);
195 
196  return "$name=$value";
197  }
198 
199  function any($name, $value)
200  {
201  trace("NUMBER: ANY!!!", 3);
202 
203  if (strpos($value, ",") !== FALSE)
204  {
205  $value = explode(",", $value);
206  }
207 
208  checkNumeric($value);
209 
210  if (is_array($value))
211  {
212  if (count($value) == 0) return "";
213  return "$name in (".implode(",", array_values($value)).") ";
214  }
215  else return "$name=$value";
216  }
217 
218  function like($name, $value)
219  {
220  die("Inappropriate matching mode");
221  }
222 
223  function startsWith($name, $value)
224  {
225  die("Inappropriate matching mode");
226  }
227 
228  function from($name, $from)
229  {
230  checkNumeric($from);
231  return "$name >= $from";
232  }
233 
234  function to($name, $to)
235  {
236  checkNumeric($to);
237  return "$name <= $to";
238  }
239 
240  function range($name, $from, $to)
241  {
242  checkNumeric($from);
243  checkNumeric($to);
244 
245  return "($name >= $from AND $name <= $to)";
246  }
247 
248  /*
249  * Use when checking if a number is a member of a set.
250  * For example, teachers_key in (8312, 5643, 9893) or
251  * public in (2,4,5). Set can must be comma delimited
252  * or an array where the keys are the values to
253  * be included in the set.
254  *
255  */
256  function member($name, $set)
257  {
258  trace("## NUMBERSEARCHPARAMETERHANDLER", 1);
259 
260  $values = $set;
261  if(is_array($set))
262  $values = implode(",", array_keys($set));
263  return "$name IN ($set)";
264  }
265 
266 }
267 
274 {
275  function equal($name, $value)
276  {
277  $txt = ConnectionManager::quote($value);
278  return "$name=$txt";
279  }
280 
281  function like($name, $value)
282  {
283  $txt = ConnectionManager::quote("%{$value}%");
284  return "$name LIKE $txt";
285  }
286 
287  function startsWith($name, $value)
288  {
289  $txt = ConnectionManager::quote("{$value}%");
290  return "$name LIKE $txt";
291  }
292 
293  function from($name, $from)
294  {
295  $txt = ConnectionManager::quote($from);
296  return "$name >= $txt";
297  }
298 
299  function to($name, $to)
300  {
301  $txt = ConnectionManager::quote($to);
302  return "$name <= $txt";
303  }
304 
305  function range($name, $from, $to)
306  {
307  $from = ConnectionManager::quote($from);
308  $to = ConnectionManager::quote($to);
309 
310  return "($name >= $from AND $name <= $to)";
311  }
312 
313  function any($name, $value)
314  {
315  $value = preg_replace("/\\s+/", " ", $value);
316  $words = explode(" ", $value);
317 
318  if (count($words) == 0) return;
319 
320  $query .= " (";
321  $first = true;
322  foreach($words as $word)
323  {
324  $txt = ConnectionManager::quote("%{$word}%");
325  if (!$first) $query .= " OR ";
326  $query .= "$name LIKE $txt";
327  $first = false;
328  }
329  $query .= ")";
330 
331  return $query;
332  }
333 
334  function all($name, $value)
335  {
336  $value = preg_replace("/\\s+/", " ", $value);
337 
338  $words = explode(" ", $value);
339 
340  if (count($words) == 0) return;
341 
342  $query .= " (";
343  $first = true;
344  foreach($words as $word)
345  {
346  $txt = ConnectionManager::quote("%{$word}%");
347  if (!$first) $query .= " AND ";
348  $query .= "$name LIKE $txt";
349  $first = false;
350  }
351  $query .= ")";
352 
353  return $query;
354  }
355 
356 
357  function fullName($f_name, $l_name, $value)
358  {
359  $value = preg_replace("/\\s+/", " ", $value);
360  $words = explode(" ", $value);
361 
362  if(count($words) < 2) return;
363 
364  $idx = 0;
365  $query = " (";
366  $first = true;
367 
368  while($idx < count($words)-1)
369  {
370  if (!$first) $query .= " OR (";
371 
372  $txt1 = ConnectionManager::quote("%{$words[$idx]}%");
373  $txt2 = ConnectionManager::quote("%{$words[$idx+1]}%");
374  $query .= "{$f_name} LIKE $txt1 AND {$l_name} LIKE $txt2";
375 
376  $idx += 1;
377  $query .= ") ";
378  $first = false;
379  }
380 
381  return $query;
382  }
383 
384  /*
385  * Use when checking if a number is a member of a set.
386  * For example, status in ('in_progress', 'submitted')
387  * Set must be comma delimited.
388  */
389  function member($name, $set)
390  {
391  trace("## STRINGSEARCHPARAMETERHANDLER", 1);
392  if(!$set || !isset($set)) return "";
393 
394  $values = $set;
395  if(is_array($set))
396  {
397  $values = "'". implode("','", array_keys($set)) . "'";
398  }
399  else if($set)
400  {
401  $values = "'".implode("','", explode(",", $set))."'";
402  $values = preg_replace("/''/", "'", $values);
403  }
404 
405  return "$name IN ($values)";
406  }
407 }
408 
409 
416 {
417  function reformatToSQLDate($date)
418  {
419  trace($date, 3);
420  $fields = array();
421  if (preg_match("|^(\\d+)[\-/](\\d+)[\-/](\\d{4})$|", $date, $fields))
422  {
423  $date = $fields[3]."-".$fields[1]."-".$fields[2];
424  // JDG 5/2012 - need month and day to have "0" if single digit
425  $date = date('Y-m-d', strtotime($date));
426  }
427  // datetime
428  else if (preg_match("|^(\\d+)/(\\d+)/(\\d{4})\\s+(\\d+:\\d+:\\d+)|", $date, $fields))
429  {
430  // JDG 5/2012 - need month and day to have "0" if single digit
431  $date = date('Y-m-d', strtotime($date));
432  $date = $fields[3]."-".$fields[1]."-".$fields[2]." ".$fields[4];
433  }
434 
435  return ConnectionManager::escape($date);
436  }
437 
438 
439  function equal($name, $value)
440  {
441  $date = $this->reformatToSQLDate($value);
442  return "$name='$date'";
443  }
444 
445  function like($name, $value)
446  {
447  //TODO: Fuzzy Date Matching Logic
448  die("Inappropriate matching mode");
449  }
450 
451  function startsWith($name, $value)
452  {
453  die("Inappropriate matching mode");
454  }
455 
456  function from($name, $from)
457  {
458 
459  $from = $this->reformatToSQLDate($from);
460  return "$name >= '$from'";
461  }
462 
463  function to($name, $to)
464  {
465  $to = $this->reformatToSQLDate($to);
466  return "$name <= '$to'";
467  }
468 
469  function range($name, $from, $to)
470  {
471  $from = $this->reformatToSQLDate($from);
472  $to = $this->reformatToSQLDate($to);
473 
474  if ($from > $to)
475  {
476  $tmp = $from;
477  $from = $to;
478  $to = $tmp;
479  }
480 
481  return "($name BETWEEN '$from' AND '$to')";
482  }
483 }
484 
485 
487 {
488  var $cl;
489  var $xref;
491 
492  function __construct($class, $xref, $foreignKey)
493  {
494  $this->cl = $class;
495  $this->xref = $xref;
496  $this->foreignKey = $foreignKey;
497  }
498 
499  function member($name, $set)
500  {
501  $values = $set;
502  if(is_array($set))
503  $values = implode(",", array_keys($set));
504 
505  if (!$set) return "";
506 
507  trace("## Generating cross reference terms for $name using values ($values)", 3);
508 
509  $xref = new $this->xref;
510  $obj = new $this->cl;
511  $pk = $obj->getPrimaryKey();
512 
513  return "$pk IN (SELECT {$pk} FROM {$xref->table} WHERE {$this->foreignKey} IN ($set))";
514  }
515 }
516 
518 {
519  function equal($name, $value)
520  {
521  trace("FILTER: equal $name $value", 3);
522  checkNumeric($value);
523 
524  return "$name=$value";
525  }
526 
527  function checked($name, $value)
528  {
529  trace("FILTER: checked $name $value", 3);
530  checkNumeric($value);
531  $out = ($value) ? "$name=$value" : "";
532  trace("FILTER: out $out", 3);
533  return $out;
534  }
535 }
536 
538 {
539  var $mode;
540  var $value;
541 
543  {
544  $this->mode = $mode;
545  $this->value = $value;
546  }
547 }
548 
557 {
558  var $form;
559  var $target;
560  var $params;
562  var $joinWith = "AND"; // AND or OR
563  var $paramHandlers = array(); // custom search handlers
564  var $secondaryFields = array();
565  var $additional = array();
566  var $empty = true;
567 
568  private static $serializedFields = array("params", "handlers", "joinWith", "secondaryFields", "additional", "empty");
569  function __sleep()
570  {
571  return SearchParameters::$serializedFields;
572  }
573 
574  function copy($src)
575  {
576  $this->params = $src->params;
577  foreach(SearchParameters::$serializedFields as $field)
578  {
579  $this->$field = $src->$field;
580  }
581  }
582 
583  function SearchParameters($target, $form = null)
584  {
585  $this->target = $target;
586  $this->form = $form;
587  $this->params = array();
588 
589  $this->handlers = array();
590 
591  $this->handlers[String] = new StringSearchParameterHandler();
592  $this->handlers[HTML] = new StringSearchParameterHandler();
593  $this->handlers[Date] = new DateSearchParameterHandler();
594  $this->handlers[DateTime] = new DateSearchParameterHandler();
595  $this->handlers[Timestamp] = new DateSearchParameterHandler();
596  $this->handlers[Number] = new NumberSearchParameterHandler();
597  $this->handlers[Currency] = new NumberSearchParameterHandler();
598  $this->handlers[Boolean] = new BooleanSearchParameterHandler();
599  }
600 
601  function get($field, $mode = null)
602  {
603  if (!isset($this->params[$field])) return null;
604 
605  $val = $this->params[$field];
606  if ($val->mode == "range")
607  {
608  if ($mode == "from")
609  {
610  $value = $val->from;
611  }
612  else if ($mode == "to")
613  {
614  $value = $val->to;
615  }
616  else return null;
617  }
618  else
619  {
620  if ($mode !== null && $val->mode != $mode) return null;
621  }
622 
623  $value = $val->value;
624  trace("SearchParameters::get({$field}:$mode): $value", 3);
625  return $value;
626  }
627 
640  function setHandler($field, $handler)
641  {
642  $this->paramHandlers[$field] = $handler;
643  if (!$this->target->hasField($field))
644  {
645  $this->additional[] = $field;
646  }
647  }
648 
649  function fromArray($array)
650  {
651  $this->empty = true;
652  $this->isDefaultState = true;
653 
654  $fields = array_keys($this->target->getFields());
655  foreach($array as $field => $value)
656  {
657  list($fieldname, $mode) = explode(":", $field);
658 
659  $skip = false;
660 
661  if ($this->target->filter && $this->target->filter->isExcluded($fieldname))
662  {
663  trace("## Skipping $fieldname", 4);
664  continue;
665  }
666 
667  if (!$this->target->hasField($fieldname) &&
668  (!$this->form || !$this->form->hasAdditional($fieldname)))
669  {
670  trace("### Skipping $fieldname", 4);
671  continue;
672  }
673 
674  $this->isDefaultState = false;
675  //if (!$mode) continue;
676  if ($value != "")
677  {
678  $this->empty = false;
679 
680  $this->setParam($fieldname, $mode, $value);
681  }
682  }
683  }
684 
685  /*
686  * Set additional parameters that don't come from search
687  * form input.
688  */
689  function setParam($fieldname, $mode, $value)
690  {
691  if (is_array($value)) $value = implode(",", array_values($value));
692 
693  if (isset($this->params[$fieldname]))
694  {
695  $p = $this->params[$fieldname];
696  if ($mode)
697  {
698  if ($mode == "from" && $p->mode == "to")
699  {
700  $p->mode = "range";
701  $p->to = $p->value;
702  $p->from = $value;
703  $p->value = null;
704  }
705  else if ($mode == "to" && $p->mode == "from")
706  {
707  $p->mode = "range";
708  $p->to = $value;
709  $p->from = $p->value;
710  $p->value = null;
711  }
712  else
713  {
714  $p->mode = $mode;
715  $p->value = $value;
716  }
717  }
718  else
719  {
720  $p->value = $value;
721  }
722  }
723  else
724  {
725  $this->params[$fieldname] = new SearchParameterValue($mode, $value);
726  }
727  }
728 
733  function clearParam($field)
734  {
735  foreach($this->params as $name => $value)
736  {
737  list($f, $mode) = explode(":", $name);
738  if ($f == $field) unset($this->params["$f:$mode"]);
739  }
740  }
741 
742  function set($field, $mode, $value)
743  {
744  $this->setParam($field, $mode, $value);
745  }
746 
747  function fromGET()
748  {
749  $this->fromArray($_GET);
750  }
751 
752  function fromPOST()
753  {
754  $this->fromArray($_POST);
755  }
756 
757  function remapField($old, $new)
758  {
759  foreach($this->params as $key => $value)
760  {
761  list($field, $mode) = explode(":", $key);
762  if ($field == $old)
763  {
764  $this->params["$new:$mode"] = $value;
765  unset($this->params["$old:$mode"]);
766  }
767  }
768  }
769 
770  function copyField($old, $new)
771  {
772  $this->params[$new] = $this->params[$old];
773  }
774 
781  function secondaryFields($src)
782  {
783  if (!isset($this->secondaryFields[$src]))
784  {
785  $this->secondaryFields[$src] = array();
786  }
787 
788  for($i = 1; $i < func_num_args(); ++$i)
789  {
790  $this->secondaryFields[$src][] = func_get_arg($i);
791  }
792  }
793 
794  function toQueryString()
795  {
796  $qs = "";
797 
798  foreach($this->params as $name => $value)
799  {
800  if ($value == "") continue;
801 
802  $qs .= ($qs == "") ? "?" : "&";
803 
804  $qs .= urlencode($name);
805  $qs .= "=";
806  $qs .= urlencode($value);
807  }
808 
809  return $qs;
810  }
811 
820  function generateConstraint($first = true, $firstText = "WHERE")
821  {
822  $constraint = "";
823 
824  trace(print_r($this->params, true), 3);
825 
826  foreach($this->params as $field => $param)
827  {
828  $joinWith = (!$first) ? $this->joinWith : "";
829 
830  $modifier = $param->mode;
831  $value = $param->value;
832 
833 // if (strpos($param, ':') > 0)
834 // {
835 // list($field, $modifier) = explode(":", $param);
836 // }
837 // else
838 // {
839 // $field = $param;
840 // $modifier = "equal";
841 // }
842 
843  // JDG 10/25/2011 - allow callback function for clauses
844  if(!array_key_exists($field, $this->paramHandlers))
845  {
846  $fields = $this->target->getFields();
847  $handler = $this->handlers[$fields[$field]];
848 
849  //AJG: Default to String if field type is not known
850  if (!$handler) $handler = new StringSearchParameterHandler();
851  $clause = $this->getClause($handler, $modifier, $field, $value);
852  }
853  else
854  {
855  $handler = $this->paramHandlers[$field];
856 
857  if(is_callable($handler))
858  $clause = call_user_func($handler, $field, $value);
859  elseif(method_exists($handler, $modifier))
860  $clause = $handler->$modifier($field, $value);
861  }
862 
863  $constraint .= $this->joinClauses($first, $clause, $joinWith, $firstText);
864  }
865 
866  $this->closeClause($constraint, $firstText);
867 
868  return $constraint;
869  }
870 
871  function getClause($handler, $modifier, $field, $value)
872  {
873  $clause = array();
874 
875  $clause[] = $this->_getClause($handler, $modifier, $field, $value);
876 
877  if (isset($this->secondaryFields[$field]))
878  {
879  $secondaries = $this->secondaryFields[$field];
880 
881  foreach($secondaries as $secondary)
882  {
883  $clause[] = $this->_getClause($handler, $modifier, $secondary, $value);
884  }
885 
886  return "(".implode(" OR ", $clause).") ";
887  }
888  else
889  {
890  return $clause[0];
891  }
892  }
893 
894  function _getClause($handler, $modifier, $field, $value)
895  {
896  $clause = "";
897 
898  switch($modifier)
899  {
900  case "equal":
901 
902  $clause = $handler->equal($field, $value);
903  break;
904 
905  case "like":
906 
907  $clause = $handler->like($field, $value);
908  break;
909 
910  case "startsWith":
911 
912  $clause = $handler->startsWith($field, $value);
913  break;
914 
915  case "from":
916 
917  if (array_key_exists("{$field}:to", $this->params))
918  {
919  trace("date range", 3);
920  }
921  else
922  {
923  $clause = $handler->from($field, $value);
924  }
925  break;
926 
927  case "to":
928 
929  $clause = $handler->to($field, $value);
930  break;
931 
932  case "range":
933 
934  $param = $this->params[$field];
935  $clause = $handler->range($field, $param->from, $param->to);
936  break;
937 
938  case "member":
939 
940  $clause = $handler->member($field, $value);
941  break;
942 
943  case "any":
944 
945  $clause = $handler->any($field, $value);
946  break;
947 
948  case "all":
949 
950  $clause = $handler->all($field, $value);
951  break;
952 
953  case "fullName":
954 
955  $clause = $handler->fullName($field, $value);
956  break;
957 
958  case "checked":
959 
960  $clause = $handler->checked($field, $value);
961  break;
962 
963  default:
964  break;
965 
966  } // end case statement
967 
968  return $clause;
969  }
970 
983  static function joinClauses(&$first, $clause, $joinWith = "AND", $firstText)
984  {
985  if ($clause != "")
986  {
987  if ($first)
988  {
989  $constraint = "{$firstText} $clause";
990  $first = false;
991  }
992  else
993  {
994  $constraint .= " $joinWith $clause";
995  }
996  }
997 
998  return $constraint;
999  }
1000 
1001  static function closeClause(&$constraint, $firstText)
1002  {
1003  /*
1004  * If no clauses were created, remove the
1005  * $firstText if "AND (" or "OR (".
1006  * Close out an opened group of clauses, by
1007  * adding the ")";
1008  */
1009  if($constraint == "") return;
1010 
1011  if(strpos($firstText, "(") !== false)
1012  {
1013  $constraint .= ") ";
1014  }
1015  }
1016 }
1017 
1018 
1019 
1073 class SearchForm extends AutoForm
1074 {
1076  var $params;
1077  var $hasSearchCriteria = false;
1078  var $emptyMessage = "No search criteria was provided.";
1080 
1081  var $searchModeTypes = array("like" => "exact phrase match",
1082  "all" => "match all words in any order",
1083  "any" => "match any words");
1092  function SearchForm($target, $method="POST", $action="", $id="")
1093  {
1094  $this->AutoForm($target, $method, $action, $id);
1095  $this->modifiers = array();
1096  $this->params = new SearchParameters($target, $this);
1097 
1098  $this->validator = new ValidationEngine();
1099  $this->validator->id = $this->id;
1100  }
1101 
1106  function setMatchingMode($mode)
1107  {
1108  $fields = func_get_args();
1109  for($i = 1; $i < count($fields); ++$i)
1110  {
1111  $this->modifiers[$fields[$i]] = $mode;
1112  }
1113 
1114  }
1115 
1121  function getMatchingMode($field)
1122  {
1123  $mode = (array_key_exists($field, $this->modifiers)) ? $this->modifiers[$field] : "equal";
1124  return $mode;
1125  }
1126 
1130  function populateFromGET()
1131  {
1132  $this->params->fromGET();
1133  }
1134 
1138  function populateFromPOST()
1139  {
1140  $this->params->fromPOST();
1141  }
1142 
1144  {
1145  $this->params->fromArray($_REQUEST);
1146  }
1147 
1156  function setHandler($field, $handler)
1157  {
1158  $this->params->paramHandlers[$field] = $handler;
1159  }
1160 
1165  function writeScript()
1166  {
1167  ob_start();
1168 
1169  $this->configureValidators();
1170 
1171  $obj =& $this->data;
1172  $script = "";
1173  foreach(array_keys($obj->getFields()) as $field)
1174  {
1175  trace("SearchForm writeScript field $field", 3);
1176  if ($field != $pk&&
1177  !($obj->filter && $obj->filter->isExcluded($field)))
1178  {
1179  $mode = $this->getMatchingMode($field);
1180 
1181  $renderer = $this->getRenderer($field);
1182  if ($renderer)
1183  {
1184  $renderer->renderSearchScript($field, $mode);
1185  }
1186  }
1187  }
1188 
1189  // JDG 7/15/2011 - need scripts for additional fields
1190  foreach($this->additional as $r)
1191  {
1192  $renderer = $r['renderer'];
1193  $field = $r['field'];
1194  if(!$field)
1195  $field = $renderer->field;
1196 
1197  $mode = $this->getMatchingMode($field);
1198  $renderer->renderSearchScript($field, $mode);
1199  }
1200 
1201  echo "<script type='text/javascript'>\n";
1202  echo $this->validator->writeScript();
1203  echo "\n\n";
1204  echo "function onSubmit{$this->id}(form)\n{\n";
1205 
1206  echo "\tif (validate_{$this->id} != null && !validate_{$this->id}(form)) return false;\n";
1207 
1208 
1209  foreach(array_keys($this->fields) as $field)
1210  {
1211  if ($field != $pk && !($filter && $filter->isExcluded($field)))
1212  {
1213  $renderer = $this->getRenderer($field);
1214  if ($renderer)
1215  {
1216  $renderer->renderOnSubmitHandler($field);
1217  }
1218  }
1219  }
1220 
1221  foreach($this->additional as $r)
1222  {
1223  $r['renderer']->renderOnSubmitHandler($r['field']);
1224  }
1225 
1226  if ($this->onSubmitHandler)
1227  {
1228  echo "\t if (!{$this->onSubmitHandler}(form)) return false;\n;";
1229  }
1230 
1231  if ($this->interstitialMessage)
1232  {
1233  echo "\tinterstitial('".jsSafe($this->interstitialMessage)."');\n;";
1234  }
1235 
1236  echo "\treturn true;\n}\n\n";
1237 
1238 
1239  echo "\twindow.addEvent('domready', function() {\n";
1240 
1241  if ($this->allowPartialSave)
1242  {
1243  $managerOptions = "{partialSaveContainer: '{$this->partialSaveContainerID}', partialSaveLabel: '{$this->partialSaveLabel}'}";
1244  }
1245  else
1246  {
1247  $managerOptions = "{}";
1248  }
1249 
1250  echo "\tnew AutoFormManager('{$this->id}', {$managerOptions});\n";
1251  echo "});\n";
1252 
1253  echo "</script>\n";
1254 
1255  $script = ob_get_contents();
1256  ob_end_clean();
1257  return $script;
1258  }
1259 
1268  {
1269  $filter = $this->data->getFilter();
1270 
1271  foreach(array_keys($this->fields) as $field)
1272  {
1273  if ($filter && $filter->isExcluded($field)) continue;
1274  if ($this->readonly[$field]) continue; // No need to validate readonly fields
1275 
1276  $renderer = $this->getRenderer($field);
1277  if ($renderer)
1278  {
1279  // JDG 9/19/2010 - let each renderer supply its own validator
1280  $required = (array_search($field, $this->required) === FALSE) ? false : true;
1281  $mode = $this->getMatchingMode($field);
1282  $renderer->addSearchValidatorsToForm($field, $mode, $required);
1283  }
1284  }
1285 
1286  foreach($this->additional as $r)
1287  {
1288  // JDG 5/2012 - check if additional field is required
1289  $required = (array_search($r['field'], $this->required) === FALSE) ? false : true;
1290  $mode = $this->getMatchingMode($field);
1291  $r['renderer']->addSearchValidatorsToForm($r['field'], $mode, $required);
1292  }
1293  }
1294 
1295 
1306  function setSearchValidator($renderer, $field, $mode)
1307  {
1308  foreach($this->validator->validators as $v)
1309  {
1310  if($v->field != $field) continue;
1311  if($mode != "range")
1312  {
1313  $v->field = "{$v->field}:{$mode}";
1314  }
1315  else
1316  {
1317  $v->field = "{$v->field}:from";
1318  $toLabel = preg_replace("/between|to/i", "To", $v->title);
1319  $toV = new DateValidator("{$field}:to", $toLabel);
1320  $this->validator->add($toV);
1321  }
1322  }
1323  }
1324 
1325 
1330  function drawForm()
1331  {
1332  if ($this->readOnlyForm) return $this->drawReadOnly();
1333 
1334  $obj =& $this->data;
1335  $pk = $obj->primary_key;
1336 
1337  if ($this->preserveQueryString)
1338  {
1339  $obj->fromREQUEST();
1340  }
1341 
1343  if ($submitLabel == "")
1344  {
1345  $submitLabel = "Search ".pluralize($obj->prettifyClassName(true));
1346  }
1347 
1348  if (!$this->subordinate)
1349  {
1350  echo "<form id='{$this->id}' method='{$this->method}' action='{$this->action}' enctype='multipart/form-data'";
1351  if (!$this->ajaxSubmitHandler) echo " onsubmit='return onSubmit{$this->id}(this);'";
1352  echo ">\n";
1353  }
1354 
1355  if ($this->id)
1356  {
1357  echo "<input type='hidden' name='#FORMID#' value='{$this->id}'/>";
1358  }
1359 
1360  foreach(array_keys($this->hidden) as $hidden)
1361  {
1362  echo "<input id='{$hidden}' type='hidden' name='$hidden' value='".htmlSafe($obj->get($hidden))."'/>\n";
1363  }
1364 
1365  if ($this->preserveQueryString)
1366  {
1367  foreach($_GET as $key => $value)
1368  {
1369  if ($key == "identifier" || $key == "section" || $key == "submit" || array_key_exists($this->hidden, $key) || $obj->hasField($key)) continue;
1370  echo "<input id='{$this->id}_{$key}' type='hidden' name='$key' value='".htmlSafe($value)."'/>\n";
1371  }
1372  }
1373 
1374 
1375  $this->layout->startUngrouped();
1376 
1377  if ($this->buttons_at_top && !$this->subordinate)
1378  {
1379  $this->layout->startButtonLine();
1380 
1381  $this->drawSubmitButtons($obj, $pk, $submitLabel);
1382 
1383  $this->drawButtons();
1384 
1385  $this->layout->endButtonLine();
1386  }
1387 
1388  $this->layout->errorBox();
1389 
1390  if ($this->markRequiredFields && $this->validator->hasRequiredFields())
1391  {
1392  $this->layout->requiredFields($this->requiredFieldsText);
1393  }
1394 
1395  $this->renderSearchFields();
1396 
1397  if (!$this->subordinate)
1398  {
1399  $this->layout->startButtonLine();
1400 
1401  $this->drawSubmitButtons($obj, $pk, $submitLabel);
1402  $this->drawButtons();
1403 
1404  $this->layout->endButtonLine();
1405  }
1406 
1407  $this->layout->endUngrouped();
1408 
1409  if (!$this->subordinate)
1410  {
1411  echo "</form>\n";
1412  }
1413  }
1414 
1416  {
1417  $obj =& $this->data;
1418  $filter = $obj->getFilter();
1419 
1420  if (count($this->groups) > 0)
1421  {
1422  $this->layout->endUngrouped();
1423 
1424  foreach($this->groups as $legend => $fields)
1425  {
1426  $collapsible = array_key_exists($legend, $this->collapsibleGroups);
1427  if ($collapsible)
1428  {
1429  $cf = $this->collapsibleGroups[$legend];
1430  $collapsed = !$this->data->$cf;
1431  }
1432 
1433  $this->layout->startGroup($legend, $collapsible, $collapsed);
1434 
1435  foreach($fields as $field)
1436  {
1437  if ($field != $pk && !array_key_exists($field, $this->hidden) && !array_key_exists($field, $this->renderedFields) &&
1438  ($this->hasAdditional($field) || !($filter && $filter->isExcluded($field))))
1439  {
1440  $this->renderOneSearchField($field);
1441  }
1442  }
1443 
1444  $this->layout->endGroup();
1445  }
1446 
1447  $this->layout->startUngrouped();
1448 
1449  }
1450 
1451  foreach(array_keys($this->fields) as $field)
1452  {
1453  if ($field != $pk && !array_key_exists($field, $this->hidden) && !array_key_exists($field, $this->renderedFields) &&
1454  ($this->hasAdditional($field) || !($filter && $filter->isExcluded($field))))
1455  {
1456  $this->renderOneSearchField($field);
1457  }
1458  }
1459 
1460  foreach($this->additional as $r)
1461  {
1462  $renderer = $r['renderer'];
1463  $field = $r['field'];
1464  if(!$field)
1465  $field = $renderer->field;
1466 
1467  trace("Rendering additional field $field", 3);
1468 
1469  if (!array_key_exists($field, $this->renderedFields))
1470  {
1471  $this->renderOneSearchField($field);
1472  }
1473  }
1474  }
1475 
1476  /*
1477  * 3/12/10, JG, make separate function from drawForm
1478  * so that inheriting classes can create a customized
1479  * form layout and call this function from its own
1480  * drawForm.
1481  */
1482  function renderOneSearchField($field)
1483  {
1484  $mode = $this->getMatchingMode($field);
1485  $renderer = $this->getRenderer($field);
1486 
1487  if(!$renderer && !$this->data->hasField($field) && $this->data->getType($field) != "Timestamp")
1488  {
1489  foreach($this->additional as $r)
1490  {
1491  $renderer = $r['renderer'];
1492  $field = $r['field'];
1493  if(!$field)
1494  $field = $renderer->field;
1495  }
1496  }
1497 
1498  if ($renderer)
1499  {
1500  if(!$this->readOnlyForm)
1501  {
1502  $renderer->renderSearchField($field, $mode);
1503  }
1504  else if($this->readOnlyForm && (get_class($renderer) != DateFieldRenderer || $mode != "range"))
1505  {
1506  $value = $this->params->get($field, $mode);
1507  if($value)
1508  {
1509  // Set the value into the form's data obj so that the
1510  // renderReadOnly function works the same as with AutoForm
1511  $this->data->set($field, $value);
1512  $renderer->renderReadOnly($field);
1513  $this->hasSearchCriteria = true;
1514  }
1515  }
1516  else if($this->readOnlyForm)
1517  {
1518  $date_from = $this->params->get($field, "from");
1519  $date_to = $this->params->get($field, "to");
1520  if($date_from || $date_to)
1521  {
1522  $renderer->renderDateRangeReadOnly($field, $date_from, $date_to);
1523  $this->hasSearchCriteria = true;
1524  }
1525  }
1526  // count as rendered even if we didn't render because readonly and
1527  // no value so that we don't try to render again
1528  $this->renderedFields[$field] = true;
1529  }
1530  }
1531 
1532  function renderAdditionalFields($obj)
1533  {
1534  foreach($this->additional as $r)
1535  {
1536  $renderer = $r['renderer'];
1537  $field = $r['field'];
1538  if(!$field)
1539  $field = $renderer->field;
1540 
1541  $mode = $this->getMatchingMode($field);
1542 
1543  if(!array_key_exists($field, $this->renderedFields))
1544  {
1545  $renderer->renderSearchField($field, $mode);
1546  }
1547  $this->renderedFields[$field] = true;
1548  }
1549  }
1550 
1555  function drawReadOnly()
1556  {
1557  echo "<table";
1558  if ($this->formCSS) echo " class='{$this->formCSS}'";
1559  if ($this->style) echo " style='{$this->style}'";
1560  echo ">\n";
1561 
1562  $obj =& $this->data;
1563  $pk = $obj->primary_key;
1564  $filter = $obj->getFilter();
1565 
1566  foreach($this->params->params as $param => $value)
1567  {
1568  list($field, $modifier) = explode(":", $param);
1569  if(!array_key_exists($field, $this->modifiers))
1570  $this->setMatchingMode($modifier, $field);
1571  }
1572 
1573  if (count($this->groups) > 0)
1574  {
1575  foreach($this->groups as $legend => $fields)
1576  {
1577  foreach($fields as $field)
1578  {
1579  if ($field != $pk && !array_key_exists($field, $this->hidden) &&
1580  !array_key_exists($field, $this->renderedFields) &&
1581  !($filter && $filter->isExcluded($field)))
1582  {
1583  $this->renderOneSearchField($field);
1584  }
1585  }
1586  }
1587  }
1588 
1589  foreach(array_keys($this->fields) as $field)
1590  {
1591  if ($field != $pk && !array_key_exists($field, $this->hidden) && !array_key_exists($field, $this->renderedFields) && !($filter && $filter->isExcluded($field)))
1592  {
1593  $this->renderOneSearchField($field);
1594  }
1595  }
1596 
1597  foreach($this->additional as $r)
1598  {
1599  $renderer = $r['renderer'];
1600  $field = $r['field'];
1601  if(!$field)
1602  $field = $renderer->field;
1603  if (!array_key_exists($field, $this->renderedFields) && !($filter && $filter->isExcluded($field)))
1604  {
1605  $this->renderOneSearchField($field);
1606  }
1607  }
1608 
1609  if(!$this->hasSearchCriteria)
1610  {
1611  echo "<tr>\n<td style='padding-top: 10px; padding-bottom: 10px'><i>{$this->emptyMessage}</i></td>\n</tr>\n";
1612  }
1613 
1614  ob_start();
1615  $this->drawButtons();
1616  $buttons .= ob_get_contents();
1617  ob_end_clean();
1618 
1619  if($buttons)
1620  echo "<tr><td>". preg_replace("/^(&nbsp;)+/", "", $buttons) . "</td>\n<tr>\n";
1621 
1622  echo "</table>";
1623  }
1624 }
1625 ?>
AutoForm automatically creates a form based on an underlying DataItem.
Definition: auto_form.inc:46
configureValidators()
Definition: auto_form.inc:353
hasAdditional($field)
Check if this field exists as an additional field.
Definition: auto_form.inc:947
AutoForm($target, $method="POST", $action="", $id="")
Creates a new AutoForm, based on the supplied target DataItem.
Definition: auto_form.inc:166
$action
Action URL for submitting the form. Generally this can be left blank to submit back to the same page.
Definition: auto_form.inc:68
$fields
Local field cache.
Definition: auto_form.inc:111
drawButtons()
Draws any additional buttons specified in the calling script.
Definition: auto_form.inc:1459
readonly()
Call this method to make one or more fields read-only in the form's user interface.
Definition: auto_form.inc:910
required()
Call this method to mark one or more fields as being required fields.
Definition: auto_form.inc:933
$hidden
The hidden fields collection.
Definition: auto_form.inc:72
getRenderer($field)
Retrieves the FieldRenderer object for the specified field.
Definition: auto_form.inc:512
$method
HTTP method that will be used to submit the form.
Definition: auto_form.inc:67
$submitLabel
Text to display on the form's submit button. If not specified defaut text will be generated based on ...
Definition: auto_form.inc:62
$buttons
The custom buttons collection.
Definition: auto_form.inc:77
$required
List of required fields.
Definition: auto_form.inc:106
drawSubmitButtons($obj, $pk, $submitLabel)
Definition: auto_form.inc:1306
equal($name, $value)
Generates the constraint expression for equality matching parameters.
checked($name, $value)
Generate the constraint expresssion for matching boolean only when the UI element is selected.
static quote($str)
Quote a string value based on the character set of the global connection.
static escape($str)
Escapes a string based on the character set of the global connection.
member($name, $set)
Generate the constraint expression for set membership matching paramters, matching values in a comma ...
__construct($class, $xref, $foreignKey)
Field renderer for date data fields.
DateSearchParameterHandler is a SearchParameterHandler for date database types.
equal($name, $value)
Generates the constraint expression for equality matching parameters.
range($name, $from, $to)
Generates the constraint expression for 'range' matching parameters, i.e.
to($name, $to)
Generates the constraint expression for 'to' matching parameters, i.e.
startsWith($name, $value)
Generates the constraint expression for 'startsWith' matching parameters, i.e.
like($name, $value)
Generates the constraint expression for 'like' matching parameters, i.e.
from($name, $from)
Generates the constraint expression for 'from' matching parameters, i.e.
Date Validator.
Definition: validation.inc:338
NumberSearchParameterHandler is a SearchParameterHandler for numeric database types.
from($name, $from)
Generates the constraint expression for 'from' matching parameters, i.e.
member($name, $set)
Generate the constraint expression for set membership matching paramters, matching values in a comma ...
to($name, $to)
Generates the constraint expression for 'to' matching parameters, i.e.
range($name, $from, $to)
Generates the constraint expression for 'range' matching parameters, i.e.
startsWith($name, $value)
Generates the constraint expression for 'startsWith' matching parameters, i.e.
any($name, $value)
Generate the constraint expression for matching any word in a group of words.
equal($name, $value)
Generates the constraint expression for equality matching parameters.
like($name, $value)
Generates the constraint expression for 'like' matching parameters, i.e.
SearchForm generates forms for searching based on a supplied DataItem.
addDefaultValidators()
Creates default validators for fields in the form.
renderOneSearchField($field)
renderAdditionalFields($obj)
setHandler($field, $handler)
Override an existing SearchParameter constraint clause handler or add one.
writeScript()
Generate any javascript required by the search form.
getMatchingMode($field)
Retrieve the matching mode that was set for the specified field.
drawReadOnly()
Draws the form in read-only mode.
populateFromPOST()
Populate the search parameters from an HTTP POST request.
setMatchingMode($mode)
Sets the matching mode for the specified fields.
SearchForm($target, $method="POST", $action="", $id="")
Create a new Search Form.
setSearchValidator($renderer, $field, $mode)
After AutoForm configures the validators, modify the field name to include the mode with which the ta...
drawForm()
Write out the HTML for the search form.
populateFromGET()
Populate the search parameters from an HTTP GET request.
Base class for SearchParameterHandlers.
Definition: search_form.inc:51
member($name, $set)
Generate the constraint expression for set membership matching paramters, matching values in a comma ...
any($name, $value)
Generate the constraint expression for matching any word in a group of words.
to($name, $to)
Generates the constraint expression for 'to' matching parameters, i.e.
startsWith($name, $value)
Generates the constraint expression for 'startsWith' matching parameters, i.e.
Definition: search_form.inc:80
from($name, $from)
Generates the constraint expression for 'from' matching parameters, i.e.
Definition: search_form.inc:92
range($name, $from, $to)
Generates the constraint expression for 'range' matching parameters, i.e.
like($name, $value)
Generates the constraint expression for 'like' matching parameters, i.e.
Definition: search_form.inc:69
equal($name, $value)
Generates the constraint expression for equality matching parameters.
Definition: search_form.inc:58
all($name, $value)
Generate the constraint expression for matching all words in a group of words but allowing other word...
checked($name, $value)
Generate the constraint expresssion for matching boolean only when the UI element is selected.
fullName($f_name, $l_name, $value)
Generate the constraint expression for matching the f_name and l_name fields to a given value.
__construct($mode, $value)
The SearchParameters class interprets the set of input parameters for a search and generates the corr...
copyField($old, $new)
$empty
true if no search parameters were specified, false if any parameter was found
SearchParameters($target, $form=null)
setParam($fieldname, $mode, $value)
static closeClause(&$constraint, $firstText)
clearParam($field)
Clear any parameters set for the specified field.
_getClause($handler, $modifier, $field, $value)
generateConstraint($first=true, $firstText="WHERE")
generateConstraint
remapField($old, $new)
static joinClauses(&$first, $clause, $joinWith="AND", $firstText)
joinClauses
getClause($handler, $modifier, $field, $value)
setHandler($field, $handler)
Override default handling by setting a custom callback to generate the constraint for a field.
secondaryFields($src)
Specifies additional data fields to search when querying for the given source field.
StringSearchParameterHandler is a SearchParameterHandler for text database types.
equal($name, $value)
Generates the constraint expression for equality matching parameters.
from($name, $from)
Generates the constraint expression for 'from' matching parameters, i.e.
range($name, $from, $to)
Generates the constraint expression for 'range' matching parameters, i.e.
any($name, $value)
Generate the constraint expression for matching any word in a group of words.
startsWith($name, $value)
Generates the constraint expression for 'startsWith' matching parameters, i.e.
like($name, $value)
Generates the constraint expression for 'like' matching parameters, i.e.
to($name, $to)
Generates the constraint expression for 'to' matching parameters, i.e.
member($name, $set)
Generate the constraint expression for set membership matching paramters, matching values in a comma ...
all($name, $value)
Generate the constraint expression for matching all words in a group of words but allowing other word...
fullName($f_name, $l_name, $value)
Generate the constraint expression for matching the f_name and l_name fields to a given value.
The ValidationEngine takes an array of validator objects in its constructor, and is then able to gene...
checkNumeric($p)
Security helper function.
Definition: functions.inc:630
trace($msg, $lvl=3, $callStack=null)
Send output to the trace log.
Definition: functions.inc:1010