Fakoli Framework
data_item.inc
Go to the documentation of this file.
1 <?php
2 /**************************************************************
3 
4  Copyright (c) 2007-2010 Sonjara, Inc
5 
6  Permission is hereby granted, free of charge, to any person
7  obtaining a copy of this software and associated documentation
8  files (the "Software"), to deal in the Software without
9  restriction, including without limitation the rights to use,
10  copy, modify, merge, publish, distribute, sublicense, and/or sell
11  copies of the Software, and to permit persons to whom the
12  Software is furnished to do so, subject to the following
13  conditions:
14 
15  The above copyright notice and this permission notice shall be
16  included in all copies or substantial portions of the Software.
17 
18  Except as contained in this notice, the name(s) of the above
19  copyright holders shall not be used in advertising or otherwise
20  to promote the sale, use or other dealings in this Software
21  without prior written authorization.
22 
23  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30  OTHER DEALINGS IN THE SOFTWARE.
31 
32 *****************************************************************/
33 
34 //require_once realpath(dirname(__FILE__)."/connection_manager.inc");
35 require_once realpath(dirname(__FILE__)."/abstract_data_item.inc");
36 require_once realpath(dirname(__FILE__)."/query.inc");
37 require_once realpath(dirname(__FILE__)."/indexed_query.inc");
38 require_once realpath(dirname(__FILE__)."/grouped_query.inc");
39 require_once realpath(dirname(__FILE__)."/iterated_query.inc");
40 
41 /*define("String", 1);
42 define("Number", 2);
43 define("Date", 3);
44 define("HTML", 4);
45 define("Currency", 5);
46 define("Boolean", 6);
47 define("Password", 7);
48 define("Timestamp", 8);
49 define("Text", 9);*/
50 
58 {
59  static $_eventMap = array();
60 
61  var $_tx = null;
62  var $_pkDisabled = false;
63 
64  // When adding new renderers, must also update
65  // AutoForm $fieldRendererMap
66  static $dataTypeRendererMap = array(
67  "Boolean" => BooleanTypeRenderer,
68  "Currency" => CurrencyTypeRenderer,
69  "Currency3" => CurrencyTypeRenderer,
70  "Date" => DateTypeRenderer,
71  "DateTime" => DateTimeTypeRenderer,
72  "Number" => NumberTypeRenderer,
73  "String" => StringTypeRenderer,
74  "Text" => TextTypeRenderer,
75  "HTML" => TextTypeRenderer,
76  "Timestamp" => TimestampTypeRenderer,
77  "Timezone" => TimezoneTypeRenderer,
78  "PhoneNumber" => PhoneNumberTypeRenderer,
79  "DateOfBirth" => DateTypeRenderer
80  );
81 
82 
92  function DataItem()
93  {
94  if (func_num_args() > 0)
95  {
96  $arg = func_get_arg(0);
97 
98  if (is_array($arg) )
99  {
100  if (count($arg) > 1)
101  {
102  $this->populate($arg);
103  }
104  else if (count($arg) > 0)
105  {
106  if (is_array($arg[0]))
107  {
108  $this->populate($arg[0]);
109  }
110  else
111  {
112  $this->load($arg[0]);
113  }
114  }
115  }
116  else
117  {
118  if (func_num_args() > 1)
119  {
120  $this->filter = func_get_arg(1);
121  }
122 
123  $this->load($arg);
124  }
125  }
126  }
127 
128  function __sleep()
129  {
130  // No need to persist class variables, such as field metadata
131 
132  $f = array_keys($this->getFields());
133  array_push($f, "primary_key", "table", "filter");
134  return $f;
135  }
136 
146  static function registerEventHandler($class, $event, $handler)
147  {
148  $eventKey = "{$class}_{$event}";
149 
150  if (!array_key_exists($eventKey, DataItem::$_eventMap))
151  {
152 
153  DataItem::$_eventMap[$eventKey]= array();
154  }
155 
156  array_push(DataItem::$_eventMap[$eventKey], $handler);
157  }
158 
164  function fireEvent($event)
165  {
166  $eventKey = get_class($this)."_{$event}";
167  if (!array_key_exists($eventKey, DataItem::$_eventMap))
168  {
169  return;
170  }
171 
172  trace("===== DataItem event key = $eventKey", 3);
173  $handlers = DataItem::$_eventMap[$eventKey];
174 
175  if (!is_array($handlers)) return;
176  foreach($handlers as $handler)
177  {
178  if (!is_callable($handler))
179  {
180  trace(get_class($this)." {$event} handler is invalid", 2);
181  }
182  else
183  {
184  call_user_func_array($handler, array($this));
185  }
186  }
187  }
188 
193  function joinTransaction($tx)
194  {
195  $this->_tx = $tx;
196  }
197 
201  function getTransaction()
202  {
203  return $this->_tx;
204  }
205 
214  function cast($class)
215  {
216  if (get_class($this) != $class)
217  {
218  throw new DataItemException("Cannot cast ".get_class($this)." to $class.");
219  }
220 
221  return $this;
222  }
223 
224  function disablePrimaryKey()
225  {
226  if (!$this->_disablePK)
227  {
228  $conn = $this->getConnection();
229  $conn->prepare("ALTER TABLE `{$this->table}` DISABLE KEYS")->execute();
230  $this->_disablePK = true;
231  }
232  }
233 
234  function enablePrimaryKey()
235  {
236  if ($this->_disablePK)
237  {
238  $conn = $this->getConnection();
239  $conn->prepare("ALTER TABLE `{$this->table}` ENABLE KEYS")->execute();
240  $this->_disablePK = false;
241  }
242  }
243 
244  function getHiddenFields()
245  {
246  return $this->hiddenFields;
247  }
248 
257  function populate($line, $alias = false)
258  {
259  global $config;
260 
261  // NOTE - structured for speed, since the general case is no aliasing
262  // therefore we want to reduce the number of tests of the alias
263 
264  $fields = $this->getFields();
265 
266  if ($alias)
267  {
268  $offset = strlen($alias) + 1;
269 
270  foreach ($line as $field => $value)
271  {
272  if (!startsWith($field, $alias)) continue;
273  $field = substr($field, $offset);
274 
275  if (!array_key_exists($field, $fields)) continue;
276  if ($this->filter && $this->filter->isExcluded($field)) continue;
277 
278  if ($config["no_charset_conversions"])
279  {
280  $this->$field = $value;
281  }
282  else
283  {
284  $this->$field = iconv("UTF-8", "CP1252//IGNORE", $value);
285  }
286  }
287  }
288  else
289  {
290  foreach ($line as $field => $value)
291  {
292  if (!array_key_exists($field, $fields)) continue;
293  if ($this->filter && $this->filter->isExcluded($field)) continue;
294 
295  if ($config["no_charset_conversions"])
296  {
297  $this->$field = $value;
298  }
299  else
300  {
301  $this->$field = iconv("UTF-8", "CP1252//IGNORE", $value);
302  }
303  }
304  }
305 
306  if (isset($this->calculatedFields))
307  {
308  foreach($this->calculatedFields as $field => $expr)
309  {
310  if ($alias)
311  {
312  $this->$field = $line[$alias.".".$field];
313  }
314  else
315  {
316  $this->$field = $line[$field];
317  }
318  }
319  }
320 
321  $this->fireEvent("onPopulate");
322  }
323 
327  function getFields()
328  {
329  if ($this->fields) return $this->fields;
330  $class = get_class($this);
331  if ($class::$fields) return $class::$fields;
332 
333  throw new FakoliException("DataItem does not contain any fields");
334  }
335 
341  function overrideFieldType($field, $type)
342  {
343  if (!is_array($this->fields))
344  {
345  throw new FakoliException("Cannot override field types for statically defined DataItems");
346  }
347 
348  $this->fields[$field] = $type;
349  }
350 
355  function getFieldList($alias = "")
356  {
357  $list = "";
358  $first = true;
359 
360  foreach($this->getFields() as $field => $type)
361  {
362  if ($this->filter && $this->filter->isExcluded($field)) continue;
363  if (!$first) $list .= ", ";
364  if ($alias)
365  {
366  $list .= "$alias.";
367  }
368  $list .= $field;
369  if ($alias)
370  {
371  $list .= " as `$alias.$field`";
372  }
373  $first = false;
374  }
375 
376  if (isset($this->calculatedFields))
377  {
378  foreach($this->calculatedFields as $field => $expr)
379  {
380  if ($this->filter && $this->filter->isExcluded($field)) continue;
381  if (!$first) $list .= ", ";
382 
383  if ($alias)
384  {
385  foreach($this->getFields() as $f => $type)
386  {
387  $expr = preg_replace('/([\s\(])('.$f.')\b/', "$1{$alias}.$2", $expr);
388  $expr = preg_replace('/\b'.$this->table.'\.'.$f.'\b/', "{$alias}.{$f}", $expr);
389  }
390  }
391 
392  $list .= $expr . " as `";
393  if ($alias)
394  {
395  $list .= $alias.".";
396  }
397  $list .= $field."`";
398 
399  }
400  }
401 
402  return $list;
403  }
404 
409  function getFieldArray()
410  {
411  $arr = array();
412  foreach($this->getFields() as $field => $type)
413  {
414  if ($this->filter && $this->filter->isExcluded($field)) continue;
415  $arr[] = $field;
416  }
417 
418  return $arr;
419  }
420 
428  function hasField($field)
429  {
430  if (!array_key_exists($field, $this->getFields())) return false;
431  if ($this->filter && $this->filter->isExcluded($field)) return false;
432  return true;
433  }
434 
441  function hasRelation($relation)
442  {
443  return (!array_key_exists($relation, $this->relations)) ? false : true;
444  }
445 
449  function getPrimaryKey()
450  {
451  return $this->primary_key;
452  }
453 
458  function getPrimaryKeyList()
459  {
460  return array($this->primary_key);
461  }
462 
468  function get($field)
469  {
470  if (!$field) throw new FakoliException("Cannot access empty field");
471  return $this->$field;
472  }
473 
479  function set($field, $value)
480  {
481  if (!$field) throw new FakoliException("Cannot access empty field");
482  $this->$field = $value;
483  }
484 
490  function getType($field)
491  {
492  $fields = $this->getFields();
493  return $fields[$field];
494  }
495 
499  function getFilter()
500  {
501  return $this->filter;
502  }
503 
508  function setFilter($filter)
509  {
510  $this->filter = $filter;
511  }
512 
517  function getFieldAliases()
518  {
519  return $this->fieldAliases;
520  }
521 
527  {
528  return $this->fieldAnnotations;
529  }
530 
536  function load($id)
537  {
538  if ($this->cacheLookup($id)) return;
539 
540  $fields = $this->getFieldList();
541  $query = "SELECT $fields FROM {$this->table} WHERE {$this->primary_key}=$id ".$this->getIdentityConstraint();
542  trace("DataItem::load($id): $query", 3);
543 
544  $db = $this->getConnection();
545 
546  try
547  {
548  $result = $db->prepare($query);
549  $result->execute();
550 
551  if ($line = $result->fetch())
552  {
553  $this->populate($line);
554  }
555 
556  unset($result);
557  }
558  catch(PDOException $e)
559  {
560  $err = "DataItem::load() failed - ".$e->getMessage();
561  trace($err, 2);
562  throw new DataItemException($err);
563  }
564  }
565 
566 
573  function loadComposite()
574  {
575  if (!$this->hasField("composite_class") || !$this->composite_class)
576  {
577  throw new DataItemException("Cannot create composite from ".get_class($this)." as required composite cannot be determined");
578  }
579 
580  $composite = new $this->composite_class;
581  $composite->loadFromBase($this->get($this->getPrimaryKey()));
582 
583  return $composite;
584  }
585 
589  function save()
590  {
591  if ($this->cacheLocal)
592  {
593  Cache::invalidate(get_class($this)."_cache");
594  }
595 
596  if ($this->exists())
597  {
598  return $this->update();
599  }
600  else
601  {
602  return $this->insert();
603  }
604  }
605 
609  function select()
610  {
611  $pk = $this->primary_key;
612  $this->load($this->$pk);
613  }
614 
618  function exists($constraint = "")
619  {
620 
621  $pk = $this->primary_key;
622 
623  if (!$constraint)
624  {
625  if ($this->$pk == "" || $this->$pk == 0) return false;
626  $constraint = "WHERE $pk={$this->$pk}";
627  }
628 
629  $query = "SELECT $pk FROM {$this->table} $constraint";
630  trace("DataItem::exists() - $query", 3);
631 
632  $db = $this->getConnection();
633  $exists = false;
634 
635  try
636  {
637  $result = $db->prepare($query);
638  $result->execute();
639 
640  if ($line = $result->fetch())
641  {
642  $exists = true;
643  }
644 
645  unset($result);
646  }
647  catch(PDOException $e)
648  {
649  $err = "DataItem::exists() failed - " . $e->getMessage();
650  trace($err, 2);
651  throw new DataItemException($err);
652  }
653 
654  return $exists;
655  }
656 
660  function update()
661  {
662  $pk = $this->primary_key;
663 
664  $query = "UPDATE {$this->table} SET ";
665 
666  $first = true;
667  $found = false;
668 
669  foreach($this->getFields() as $field => $type)
670  {
671  if ($field == $this->primary_key) continue;
672  if ($this->filter && $this->filter->isExcluded($field)) continue;
673  if (!isset($this->$field) && $this->getType($field) != Timestamp && $this->getType($field) != Boolean) continue;
674 
675  if (!$first) $query .= ", ";
676 
677  $first = false;
678  $found = true;
679 
680  $query .= "$field=";
681  $query .= $this->quoteFieldValue($field, $type);
682  }
683 
684  if (!$found) return true; // No fields to update - bug out quietly
685 
686  $query .= " WHERE $pk={$this->$pk} ".$this->getIdentityConstraint();
687 
688  trace("DataItem::update() - $query", 3);
689 
690  try
691  {
692  $db = $this->getConnection();
693 
694  $success = $db->exec($query);
695  if ($success === FALSE)
696  {
697  trace("DataItem::update failed - $query", 2);
698  }
699  else
700  {
701  $this->fireEvent("onUpdate");
702  }
703  }
704  catch(PDOException $e)
705  {
706  $err = "DataItem::update() failed - " . $e->getMessage();
707  trace($err, 2);
708  throw new DataItemException($err);
709  }
710 
711  return $success;
712  }
713 
724  function updateExplicit($updates, $params = null)
725  {
726  $pk = $this->primary_key;
727 
728  $query = "UPDATE {$this->table} $updates";
729 
730  if ($this->get($pk))
731  {
732  $query .= " WHERE {$pk}=".$this->get($pk);
733  }
734 
735  trace("DataItem::update() - $query", 3);
736 
737  try
738  {
739  $db = $this->getConnection();
740  $stmt = $db->prepare($query);
741  $success = $stmt->execute($params);
742  if ($success === FALSE)
743  {
744  trace("DataItem::updateExplicit failed - $query", 2);
745  }
746  if ($this->get($pk)) $this->select();
747  }
748  catch(PDOException $e)
749  {
750  $err = "DataItem::updateExplicit() failed - " . $e->getMessage();
751  trace($err, 2);
752  throw new DataItemException($err);
753  }
754 
755  return $success;
756  }
757 
761  function insert()
762  {
763  $pk = $this->primary_key;
764 
765  $first = true;
766 
767  $timestampField = null;
768 
769  foreach($this->getFields() as $field => $type)
770  {
771  if ($field == $pk && !$this->_disablePK) continue;
772  if ($this->filter && $this->filter->isExcluded($field)) continue;
773  if (!isset($this->$field) && $this->getType($field) != Timestamp && $this->getType($field) != Boolean) continue;
774 
775  if ($type == Timestamp)
776  {
777  $timestampField = $field;
778  }
779 
780  if (!$first)
781  {
782  $fields .= ", ";
783  $values .= ", ";
784  }
785 
786  $fields .= $field;
787  $values .= $this->quoteFieldValue($field, $type);
788 
789  $first = false;
790  }
791 
792  $query = "INSERT INTO {$this->table} ($fields) values ($values)";
793 
794  trace("DataItem::insert() - $query", 3);
795 
796  $success = false;
797 
798  try
799  {
800  $db = $this->getConnection();
801  $success = $db->exec($query);
802 
803  if ($success !== FALSE)
804  {
805  $this->$pk = $db->lastInsertId();
806  //AJG - Set the timestamp field value if the insert succeeded
807  if ($timestampField)
808  {
809  $this->$timestampField = $this->__timestamp;
810  unset($this->__timestamp);
811  }
812 
813  $this->fireEvent("onInsert");
814  }
815  else
816  {
817  $this->$pk = 0;
818  trace("DataItem::insert() failed - $query", 2);
819  }
820  }
821  catch(PDOException $e)
822  {
823  $err = "DataItem::insert() failed - ". $e->getMessage();
824  trace($err, 2);
825  throw new DataItemException($err);
826  }
827  return $success;
828  }
829 
833  function delete($constraint = "")
834  {
835  if ($constraint == "")
836  {
837  $fire = true;
838  $pk = $this->primary_key;
839  $constraint = "WHERE $pk={$this->$pk} ".$this->getIdentityConstraint();
840  }
841 
842  $query = "DELETE FROM {$this->table} $constraint";
843 
844  trace($query, 3);
845 
846  $db = $this->getConnection();
847 
848  try
849  {
850  if ($fire) $this->fireEvent("onPreDelete");
851  $db->exec($query);
852  if ($fire) $this->fireEvent("onPostDelete");
853  }
854  catch(PDOException $e)
855  {
856  $err = "DataItem::delete() failed - " . $e->getMessage();
857  trace($err, 2);
858  throw new DataItemException($err);
859  }
860  }
861 
865  function deleteAll()
866  {
867  $query = "TRUNCATE TABLE {$this->table}";
868  $db = $this->getConnection();
869 
870  trace($query, 3);
871 
872  try
873  {
874  $db->exec($query);
875  $this->fireEvent("onDeleteAll");
876  }
877  catch(PDOException $e)
878  {
879  $err = "DataItem::deleteAll() failed - " . $e->getMessage();
880  trace($err, 2);
881  throw new DataItemException($err);
882  }
883  }
884 
888  function tableExists()
889  {
890  $query = "SHOW TABLES LIKE '{$this->table}'";
891  $db = $this->getConnection();
892 
893  trace($query, 3);
894 
895  $exists = false;
896 
897  try
898  {
899  $result = $db->prepare($query);
900  $result->execute();
901 
902  if ($line = $result->fetch())
903  {
904  $exists = true;
905  }
906 
907  unset($result);
908  }
909  catch(PDOException $e)
910  {
911  $err = "DataItem::tableExists() failed - " . $e->getMessage();
912  trace($err, 2);
913  throw new DataItemException($err);
914  }
915 
916  return $exists;
917  }
926  function distinctValues($field, $sorted = false, $constraint = "")
927  {
928  $query = "SELECT DISTINCT $field from {$this->table} $constraint";
929 
930  trace($query, 3);
931 
932  $db = $this->getConnection();
933 
934  try
935  {
936  $result = $db->prepare($query);
937  $result->execute();
938 
939  $values = array();
940 
941  while($line = $result->fetch())
942  {
943  $values[] = $line[$field];
944  }
945 
946  if ($sorted)
947  {
948  sort($values);
949  }
950 
951  unset($result);
952 
953  return $values;
954  }
955  catch(PDOException $e)
956  {
957  $err = "DataItem::distinctValues() failed - " . $e->getMessage();
958  trace($err, 2);
959  throw new DataItemException($err);
960  }
961 
962  }
963 
967  function fromGET()
968  {
969  foreach($this->getFields() as $field => $type)
970  {
971  if ($this->filter && $this->filter->isExcluded($field)) continue;
972  if (array_key_exists($field, $_GET))
973  {
974  $this->set($field, $_GET[$field]);
975  }
976  }
977  }
978 
985  function fromPOST()
986  {
987  foreach($this->getFields() as $field => $type)
988  {
989  if ($this->filter && $this->filter->isExcluded($field)) continue;
990  if (array_key_exists($field, $_POST))
991  {
992  $this->set($field, $_POST[$field]);
993  }
994  elseif (!array_key_exists($field, $_POST) AND ($type == Boolean))
995  {
996  $this->$field = 0;
997  }
998  }
999  }
1000 
1005  function fromREQUEST()
1006  {
1007  switch($_SERVER["REQUEST_METHOD"])
1008  {
1009  case "POST":
1010  $this->fromPOST();
1011  break;
1012 
1013  case "GET":
1014  default:
1015  $this->fromGET();
1016  }
1017  }
1018 
1023  function fromDataSet($params)
1024  {
1025  foreach($this->getFields() as $field => $type)
1026  {
1027  if ($this->filter && $this->filter->isExcluded($field)) continue;
1028  if (array_key_exists($field, $params))
1029  {
1030  $this->$field = $params[$field];
1031  }
1032  elseif (!array_key_exists($field, $params) AND ($type == Boolean))
1033  {
1034  $this->$field = 0;
1035  }
1036  }
1037  }
1038 
1046  function compare($to)
1047  {
1048  foreach($this->getFields() as $field => $type)
1049  {
1050  if ($this->filter && $this->filter->isExcluded($field)) continue;
1051  if ($to->$field != $this->$field)
1052  {
1053  trace("$field '{$this->$field}' != '{$to->$field}'", 3);
1054  return false;
1055  }
1056  }
1057 
1058  return true;
1059  }
1060 
1067  function copy($from)
1068  {
1069  foreach($this->getFields() as $field => $type)
1070  {
1071  if ($this->filter && $this->filter->isExcluded($field)) continue;
1072  $this->$field = $from->$field;
1073  }
1074 
1075  if (is_array($this->calculatedFields))
1076  {
1077  foreach($this->calculatedFields as $field => $expr)
1078  {
1079  $this->$field = $from->$field;
1080  }
1081  }
1082  }
1083 
1084  function cacheLookup($id)
1085  {
1086  if ($this->cacheLocal)
1087  {
1088  $cache = get_class($this)."_cache";
1089  $items = Cache::get($cache);
1090  if (!is_array($items))
1091  {
1092  $items = IndexedQuery::create(get_class($this), "", $this->primary_key)->execute();
1093  Cache::put($cache, $items);
1094  }
1095  if (array_key_exists($id, $items))
1096  {
1097  trace("Using local cache $cache for item $id", 5);
1098  $this->copy($items[$id]);
1099  return true;
1100  }
1101  }
1102 
1103  return false;
1104  }
1105 
1115  function getRelated($class, $field = "")
1116  {
1117  $obj = new $class;
1118  if ($field == "")
1119  {
1120  $field = $obj->primary_key;
1121 
1122  }
1123 
1124  if (array_key_exists($field, $this->getFields()))
1125  {
1126  $pk = $obj->primary_key;
1127  $val = $this->get($field);
1128 
1129  if (!$val) return null;
1130 
1131  $obj->$pk = $val;
1132 
1133  $cache = "_{$class}_{$field}_{$val}";
1134  if (isset($this->$cache))
1135  {
1136  $obj->copy($this->$cache);
1137  }
1138  else
1139  {
1140  $obj->select();
1141  $this->$cache = $obj;
1142  }
1143  }
1144  else
1145  {
1146  $field = $this->primary_key;
1147  $obj = querySingle($class, "WHERE $field={$this->$field}");
1148  }
1149  return $obj;
1150  }
1151 
1165  function getRelatedList($class, $field = "", $orderBy = "")
1166  {
1167  $pk = $this->primary_key;
1168 
1169  if ($field == "") $field = $pk;
1170  $value = $this->$field ? $this->$field : $this->$pk;
1171  $orderBy = preg_replace("/^\s*WHERE\s+/i", "AND ", $orderBy);
1172  //$this->quoteFieldValue($this->$field, $this->fields[$field])
1173  $list = query($class, "WHERE $field=$value $orderBy");
1174 
1175  return $list;
1176  }
1177 
1187  function crossReference($class, $xref, $orderBy = "", $pkField = "", $xrefField = "")
1188  {
1189  $obj = new $class;
1190  $xref = new $xref;
1191 
1192  if ($orderBy != "")
1193  {
1194  foreach($obj->getFields() as $field => $type)
1195  {
1196  $orderBy = preg_replace("/\\b".$field."\\b/i", "a0.$field", $orderBy);
1197  }
1198  }
1199 
1200  $orderBy = preg_replace("/^\s*WHERE\s+/i", "AND ", $orderBy);
1201 
1202  $xt = $xref->table;
1203  $xp = ($xrefField != "") ? $xrefField : $obj->primary_key;
1204 
1205  $pkField = ($pkField != "") ? $pkField : $this->primary_key;
1206  $pk = $this->primary_key;
1207 
1208  $fieldList = $obj->getFieldList("a0");
1209 
1210  $query = "SELECT {$fieldList} FROM {$obj->table} a0, $xt x WHERE a0.{$obj->primary_key}=x.{$xp} AND x.{$pkField}={$this->$pk} $orderBy";
1211 
1212  trace($query, 3);
1213 
1214  try
1215  {
1216  $db = $this->getConnection();
1217 
1218  $result = $db->prepare($query);
1219  $result->execute();
1220 
1221  $list = array();
1222  while ($line = $result->fetch())
1223  {
1224  $obj = new $class;
1225  $obj->populate($line, "a0");
1226  $list[] = $obj;
1227  }
1228 
1229  unset($result);
1230  }
1231  catch(PDOException $e)
1232  {
1233  $err = "DataItem::crossReference() failed - " . $e->getMessage();
1234  trace($err, 2);
1235  throw new DataItemException($err);
1236  }
1237  return $list;
1238  }
1239 
1247  function queryValue($func)
1248  {
1249  $constraints = "";
1250  $value = null;
1251 
1252  if (func_num_args() > 1)
1253  {
1254  $constraints = func_get_arg(1);
1255 
1256  if (func_num_args() > 2)
1257  {
1258  $value = func_get_arg(2);
1259  }
1260  }
1261 
1262  if ($constraints == "") $constraints = "WHERE 1=1"; //TODO - tidy this up some day
1263  $constraints .= " ".$this->getIdentityConstraint();
1264 
1265  $query = "SELECT $func as result FROM {$this->table} $constraints";
1266 
1267  trace("DataItem::queryValue: $query", 3);
1268  try
1269  {
1270  $db = $this->getConnection();
1271  $result = $db->prepare($query);
1272  $result->execute();
1273 
1274  if ($row =$result->fetch())
1275  {
1276  $value = $row['result'];
1277  }
1278 
1279  unset($result);
1280  }
1281  catch(PDOException $e)
1282  {
1283  $err = "DataItem::queryValue() failed - " . $e->getMessage();
1284  trace($err, 2);
1285  throw new DataItemException($err);
1286  }
1287 
1288  return $value;
1289 
1290  }
1291 
1297  function toXML($indent = 0, $path = null)
1298  {
1299  trace(get_class($this)."->toXML()", 4);
1300 
1301  $xml = str_repeat(" ", $indent) . "<" . get_class($this) . ">\n";
1302 
1303  foreach($this->getFields() as $field => $type)
1304  {
1305  if ($this->filter && $this->filter->isExcluded($field)) continue;
1306  if (isset($this->$field))
1307  {
1308  if ($this->$field === "")
1309  {
1310  $xml .= str_repeat(" ", $indent) . " <$field/>\n";
1311  }
1312  else
1313  {
1314  $xml .= str_repeat(" ", $indent) . " <{$field}>".$this->formatFieldForXML($field)."</$field>\n";
1315  }
1316 
1317  }
1318  }
1319 
1320  $path[get_class($this)] = true;
1321  trace(implode(" > ", array_keys($path)), 4);
1322  trace("Options: ".$this->_options, 4);
1323 
1324  if (($this->_options & SerializeRelations) ||
1325  ($this->_options & SerializeDirectRelations) &&
1326  $this->relations)
1327  {
1328  if (is_array($this->relations))
1329  {
1330  foreach($this->relations as $rel => $relType)
1331  {
1332  if (is_array($path) && array_key_exists($relType, $path)) continue;
1333 
1334  $obj = $this->$rel();
1335  if ($obj)
1336  {
1337  $xml .= str_repeat(" ", $indent) . " <$rel>\n";
1338 
1339  if (is_array($obj))
1340  {
1341  foreach($obj as $item)
1342  {
1343  if ($this->_options & SerializeRelations)
1344  {
1345  $item->setOption(SerializeRelations);
1346  }
1347 
1348  if ($this->_options & ProtectHTML)
1349  {
1350  $item->setOption(ProtectHTML);
1351  }
1352 
1353  $xml .= $item->toXML($indent + 2, $path);
1354  }
1355  }
1356  else
1357  {
1358  if ($this->_options & SerializeRelations)
1359  {
1360  $obj->setOption(SerializeRelations);
1361  }
1362 
1363  if ($this->_options & ProtectHTML)
1364  {
1365  $obj->setOption(ProtectHTML);
1366  }
1367 
1368  $xml .= $obj->toXML($indent + 2, $path);
1369  }
1370 
1371  $xml .= str_repeat(" ", $indent) . " </$rel>\n";
1372  }
1373  else
1374  {
1375  $xml .= str_repeat(" ", $indent) . " <$rel/>\n";
1376  }
1377  }
1378  }
1379  }
1380 
1381  $xml .= str_repeat(" ", $indent) . "</" . get_class($this) . ">\n";
1382 
1383  return $xml;
1384  }
1385 
1386  function fromXML($node)
1387  {
1388  if ($node->nodeType != XML_ELEMENT_NODE || $node->tagName != get_class($this)) return;
1389 
1390  $kids = $node->childNodes;
1391  $numChildren = $kids->length;
1392 
1393  for($i = 0; $i < $numChildren; ++$i)
1394  {
1395  $n = $kids->item($i);
1396 
1397  if ($n->nodeType != XML_ELEMENT_NODE) continue;
1398  $field = $n->tagName;
1399  $this->set($field, $n->nodeValue);
1400  }
1401  }
1402 
1403  function toJSON()
1404  {
1405  $out = array();
1406 
1407  foreach($this->getFields() as $field => $type)
1408  {
1409  if ($this->filter && $this->filter->isExcluded($field))
1410  {
1411  continue;
1412  }
1413 
1414  $val = str_replace("\\'", "'", jsSafe($this->get($field)));
1415 
1416  $out[] = "\"{$field}\": \"".$val."\"";
1417  }
1418 
1419  return "{".implode(", ", $out)."}";
1420  }
1421 
1483  function format($template = "", $separator = ", ")
1484  {
1485  if ($template == "") $template = $this->default_format;
1486  if (is_array($template) && is_callable($template))
1487  {
1488  return call_user_func($template, $this);
1489  }
1490 
1491  foreach($this->getFields() as $field => $type)
1492  {
1493  $template = str_replace("{".$field."}", $this->formatFieldValue($field), $template);
1494  }
1495 
1496  if (isset($this->calculatedFields))
1497  {
1498  foreach($this->calculatedFields as $field => $expr)
1499  {
1500  $template = str_replace("{".$field."}", $this->$field, $template);
1501  }
1502  }
1503 
1504  if (isset($this->_decorations))
1505  {
1506  foreach($this->_decorations as $field => $value)
1507  {
1508  $template = str_replace("{".$field."}", $value, $template);
1509  }
1510  }
1511 
1512  // Allow drill-down through relation functions
1513  $template = $this->formatThroughRelation($template, $separator);
1514 
1515  $template = $this->formatField($template);
1516 
1517  // Simple method calls - no parameter passing
1518  // ??Is this block ever executed??
1519 
1520  $matches = array();
1521  preg_match_all("/\\{([\\w_]+)\\(\\)\\}/", $template, $matches, PREG_SET_ORDER);
1522 
1523  foreach($matches as $match)
1524  {
1525  $format = $match[0];
1526  $method = $match[1];
1527 
1528  $value = $this->$method();
1529 
1530  $template = str_replace($format, $value, $template);
1531  }
1532 
1533  return $template;
1534  }
1535 
1536  /*
1537  * Call formatFieldValue on a field with
1538  * formatting specification given.
1539  *
1540  * e.g.:
1541  * {amount:2}
1542  * {start_date:long}
1543  */
1544  function formatField($template)
1545  {
1546  $matches = array();
1547 
1548  preg_match_all("/\\{([\\w\\d_]+)(::?|\\^|\\(\\)|\\|)?([^}]*)}/", $template, $matches, PREG_SET_ORDER);
1549 
1550  foreach($matches as $match)
1551  {
1552  $field = $match[1];
1553  // JDG 3/12 fix issue with call to function in DataItem in format like "{getTitle()}" with no separator;
1554  $separator = ($match[2]) ? $match[2] : ":";
1555 
1556  $fieldFormat = $match[3];
1557  trace("formatField, template $template, field $field, separator $separator and fieldFormat $fieldFormat", 5);
1558 
1559  $format = "{".$field.$separator.$fieldFormat."}";
1560 
1561  switch($separator)
1562  {
1563  case "|":
1564  if (!$this->get($field))
1565  {
1566  $sub = $fieldFormat;
1567  }
1568  else
1569  {
1570  $sub = $this->formatFieldValue($field);
1571  }
1572  break;
1573 
1574  case "^":
1575  if (!$this->get($field))
1576  {
1577  $sub = $this->format("{".$fieldFormat."}");
1578  }
1579  else
1580  {
1581  $sub = $this->formatFieldValue($field);
1582  }
1583  break;
1584 
1585  case "::":
1586 
1587  $sub = call_user_func(array($field, $fieldFormat), $this);
1588  break;
1589 
1590  case "()":
1591 
1592  $sub = $this->$field();
1593  break;
1594 
1595  case ":":
1596  default:
1597  $sub = $this->formatFieldValue($field, $fieldFormat);
1598  }
1599 
1600  $template = str_replace($format, $sub, $template);
1601  }
1602  return $template;
1603  }
1604 
1605  /*
1606  * Format a field value that is accessed through a relation.
1607  * The relation can return multiple items.
1608  * e.g.,
1609  *
1610  * {Program.program_name}
1611  * {Event.start_date} or {Event.start_date:long}
1612  * {Events.event_name}
1613  */
1614  function formatThroughRelation($template, $separator = ", ")
1615  {
1616  $matches = array();
1617  preg_match_all("/\\{([\\w\\d_]+)\\.([\\w\\d_\\.\\(\\)]+):?([^}]*)}/", $template, $matches, PREG_SET_ORDER);
1618 
1619  foreach($matches as $match)
1620  {
1621  $relation = $match[1];
1622  $field = $match[2];
1623 
1624  if(count($match) == 4 && preg_match("/^where|order/i", $match[3]))
1625  $constraint = $match[3];
1626  elseif(count($match) == 4)
1627  $fieldTemplate = $match[3];
1628 
1629  trace("function format: formatThroughRelations template $template field $field relation $relation constraint $constraint", 5);
1630 
1631  if ($constraint)
1632  {
1633  $relations = $this->$relation($constraint);
1634  $format = "{".$relation.".".$field.":".$constraint."}";
1635  }
1636  elseif($fieldTemplate)
1637  {
1638  $relations = $this->$relation();
1639  $format = "{".$relation.".".$field.":".$fieldTemplate."}";
1640  }
1641  else
1642  {
1643  $relations = $this->$relation();
1644  $format = "{".$relation.".".$field."}";
1645  }
1646 
1647  $sub = "";
1648 
1649  if (is_array($relations))
1650  {
1651  $formatTemplate = ($fieldTemplate) ? "{".$field .":".$fieldTemplate . "}" : "{".$field."}";
1652  $sub = formatItems($relations, $formatTemplate, $separator);
1653 
1654  }
1655  else if ($relations)
1656  {
1657  if ($fieldTemplate) $fieldTemplate = ":{$fieldTemplate}";
1658  if ($relations) $sub = $relations->format("{{$field}{$fieldTemplate}}");
1659  }
1660 
1661  trace("format using relations: Replacing {$match[0]} [ $format ] with '$sub'", 5);
1662 
1663  $template = str_replace($format, $sub, $template);
1664  }
1665 
1666  return $template;
1667  }
1668 
1669 
1670  function prettifyFieldName($field)
1671  {
1672  if (isset($this->fieldAliases) && array_key_exists($field, $this->fieldAliases))
1673  {
1674  return $this->fieldAliases[$field];
1675  }
1676 
1677  $field = preg_replace("/([a-z])([A-Z0-9])/", "$1 $2", $field);
1678  $field = str_replace("_", " ", $field);
1679  $field = ucwords($field);
1680 
1681  return $field;
1682  }
1683 
1692  function relateTo($target, $field = "")
1693  {
1694  $pk = $target->primary_key;
1695 
1696  if (!$field) $field = $pk;
1697 
1698  $this->$field = $target->$pk;
1699  }
1700 }
1701 
1702 
1703 
1711 function querySingle($class)
1712 {
1713  $constraints = "";
1714 
1715  if (func_num_args() > 1)
1716  {
1717  $constraints = func_get_arg(1);
1718  }
1719 
1720  $result = query($class, $constraints);
1721 
1722  if (count($result) > 1)
1723  {
1724  throw new DataItemException("Ambiguous singleton query");
1725  }
1726 
1727  if (count($result) == 1)
1728  {
1729  return $result[0];
1730  }
1731 
1732  return null;
1733 }
1734 
1743 function queryValue($class, $func)
1744 {
1745  $constraints = "";
1746  $value = null;
1747 
1748  if (func_num_args() > 2)
1749  {
1750  $constraints = func_get_arg(2);
1751 
1752  if (func_num_args() > 3)
1753  {
1754  $value = func_get_arg(3);
1755  }
1756  }
1757 
1758  $prototype = new $class;
1759 
1760  if ($constraints == "") $constraints = "WHERE 1=1"; //TODO - tidy this up some day
1761  $constraints .= " ".$prototype->getIdentityConstraint();
1762 
1763  $query = "SELECT $func as result FROM {$prototype->table} $constraints";
1764 
1765  trace($query, 3);
1766 
1767  try
1768  {
1770 
1771  $result = $db->prepare($query);
1772  $result->execute();
1773 
1774  if ($row = $result->fetch())
1775  {
1776  $value = $row['result'];
1777  }
1778 
1779  unset($result);
1780  }
1781  catch(PDOException $e)
1782  {
1783  $err = "queryValue() failed - " . $e->getMessage();
1784  trace($err, 2);
1785  throw new DataItemException($err);
1786  }
1787 
1788  return $value;
1789 }
1790 
1791 
1792 
1799 function reindexList($list, $field, $autoPromote = true)
1800 {
1801  $result = array();
1802 
1803  foreach($list as $elt)
1804  {
1805  if (is_array($elt))
1806  {
1807  foreach($elt as $e)
1808  {
1809  if (array_key_exists($e->$field, $result))
1810  {
1811  if (!is_array($result[$e->$field]))
1812  {
1813  $result[$e->$field] = array($result[$e->$field]);
1814  }
1815  $result[$e->$field][] = $e;
1816  }
1817  else
1818  {
1819  $result[$e->$field] = $e;
1820  }
1821  }
1822  }
1823  else
1824  {
1825  if (array_key_exists($elt->$field, $result) && $autoPromote)
1826  {
1827  if (!is_array($result[$elt->$field]))
1828  {
1829  $result[$elt->$field] = array($result[$elt->$field]);
1830  }
1831  $result[$elt->$field][] = $elt;
1832  }
1833  else
1834  {
1835  $result[$elt->$field] = $elt;
1836  }
1837  }
1838  }
1839 
1840  return $result;
1841 }
1842 
1849 function regroupList($list, $field)
1850 {
1851  $result = array();
1852 
1853  foreach($list as $elt)
1854  {
1855  if (is_array($elt))
1856  {
1857  foreach ($elt as $e)
1858  {
1859  $result[$e->$field][] = $e;
1860  }
1861  }
1862  else
1863  {
1864  $result[$elt->$field][] = $elt;
1865  }
1866  }
1867 
1868  return $result;
1869 }
1870 
1882 function removeDuplicates($list, $field = "")
1883 {
1884  if (count($list) == 0) return $list;
1885 
1886  if ($field == "")
1887  {
1888  $field = $list[0]->primary_key;
1889  }
1890 
1891  $found = array();
1892  $filtered = array();
1893  foreach($list as $item)
1894  {
1895  if (!array_key_exists($item->$field, $found))
1896  {
1897  $filtered[] = $item;
1898  }
1899 
1900  $found[$item->$field] = true;
1901  }
1902 
1903  return $filtered;
1904 }
1905 
1911 {
1912  var $field;
1913 
1914  function __construct($field)
1915  {
1916  $this->field = $field;
1917  }
1918 
1919  function compare($a, $b)
1920  {
1921  return ($a->get($this->field) < $b->get($this->field)) ? -1 : 1;
1922  }
1923 }
1924 
1931 function sortList(&$list, $field)
1932 {
1933  $cmp = new DataItemFieldComparator($field);
1934 
1935  usort($list, array($cmp, "compare"));
1936 
1937  return $list;
1938 }
1939 
1947 function updateSortOrder($class, $field = "sort_order", $params = null)
1948 {
1949  if (!$params) $params = $_GET;
1950  $obj = new $class;
1951  $pk = $obj->getPrimaryKey();
1952 
1953  $tx = new DataTransaction();
1954 
1955  try
1956  {
1957  foreach($params[$pk] as $id => $sort_order)
1958  {
1959  checkNumeric($id);
1960  checkNumeric($sort_order);
1961 
1962  $item = new $class();
1963  $item->joinTransaction($tx);
1964 
1965  $item->filter = new InclusionFilter($pk, $field);
1966 
1967  $item->load($id);
1968  $item->set($field, $sort_order);
1969  $item->save();
1970  }
1971 
1972  $tx->commit();
1973  }
1974  catch(Exception $e)
1975  {
1976  $tx->rollback();
1977  throw $e;
1978  }
1979 }
1980 
1981 function toXML($tag, $objects, $header = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>")
1982 {
1983  $xml = "$header\n<$tag>\n";
1984 
1985  foreach($objects as $obj)
1986  {
1987  $xml .= $obj->toXML(1);
1988  }
1989  $xml .= "</$tag>\n";
1990 
1991  return $xml;
1992 }
1993 
1994 function toJSON($items)
1995 {
1996  $out = array();
1997 
1998  foreach($items as $item)
1999  {
2000  $out[] = $item->toJSON();
2001  }
2002 
2003  return "[".implode(", ", $out)."]";
2004 }
2005 
2006 function toJSONGrouped($items)
2007 {
2008  $out = array();
2009 
2010  foreach($items as $key => $group)
2011  {
2012  $out[] = "\"$key\": ".toJSON($group);
2013  }
2014 
2015  return "{".implode(", ", $out)."}";
2016 }
2017 
2018 function displayFieldAsList($items, $field, $separator = ", ")
2019 {
2020  return formatItems($items, "{".$field."}", $separator);
2021 }
2022 
2031 function formatItems($items, $template, $separator = "")
2032 {
2033  $list = "";
2034  $first = true;
2035 
2036  foreach($items as $item)
2037  {
2038  if (!$item) continue;
2039  if (!$first) $list .= $separator;
2040  $list .= $item->format($template);
2041  $first = false;
2042  }
2043 
2044  return $list;
2045 }
2046 
2047 function extractItems($items, $indexFormat, $valueFormat)
2048 {
2049  $list = array();
2050  foreach($items as $item)
2051  {
2052  $list[$item->format($indexFormat)] = $item->format($valueFormat);
2053  }
2054 
2055  return $list;
2056 }
2057 
2064 function extractFieldValues($items, $field)
2065 {
2066  $out = array();
2067  foreach($items as $item)
2068  {
2069  $out[] = $item->get($field);
2070  }
2071  return $out;
2072 }
2073 
2081 function extractIndexedFieldValues($items, $field)
2082 {
2083  $out = array();
2084  foreach($items as $item)
2085  {
2086  $out[$item->get($item->getPrimaryKey())] = $item->get($field);
2087  }
2088 
2089  return $out;
2090 }
2091 
2092 
2100 function findItem($items, $field, $value)
2101 {
2102  foreach($items as $item)
2103  {
2104  if ($item->get($field) == $value) return $item;
2105  }
2106 
2107  return null;
2108 }
2109 
2118 function findItemIndex($items, $field, $value)
2119 {
2120  $idx = 0;
2121 
2122  foreach($items as $item)
2123  {
2124  if ($item->get($field) == $value) return $idx;
2125  ++$idx;
2126  }
2127 
2128  return false;
2129 }
2130 
2131 function restoreHTML($text)
2132 {
2133  $v = str_replace( array("[_[OPENTAG]_]", "[_[CLOSETAG]_]", "[_[AMPERSAND]_]"), array("<", ">", "&"), $text);
2134  return $v;
2135 }
2136 
2143 function dumpCSV($class, $items, $filepath, $filter = null, $append = false)
2144 {
2145  $obj = new $class;
2146  $obj->filter = $filter;
2147 
2148  $fields = $obj->getFieldArray();
2149 
2150  if ($append)
2151  {
2152  $fp = fopen($filepath, "a");
2153  }
2154  else
2155  {
2156  $fp = fopen($filepath, "w");
2157  fputcsv($fp, $fields);
2158  }
2159 
2160  foreach($items as $item)
2161  {
2162  $vals = array();
2163  foreach($fields as $field)
2164  {
2165  $vals[] = $item->get($field);
2166  }
2167  fputcsv($fp, $vals);
2168  }
2169  fclose($fp);
2170 }
compare($to)
Compare this object to another object.
Definition: data_item.inc:1046
loadComposite()
Creates an outer CompositeDataItem from its base component.
Definition: data_item.inc:573
load($id)
Load the object with the specified primary key.
Definition: data_item.inc:536
formatThroughRelation($template, $separator=", ")
Definition: data_item.inc:1614
hasRelation($relation)
Returns true if this DataItem contains a relation with the specified name.
Definition: data_item.inc:441
getFieldArray()
Return an array of field names for this object filtered by any active filter.
Definition: data_item.inc:409
toXML($indent=0, $path=null)
Generates an XML representation of the object.
Definition: data_item.inc:1297
fromDataSet($params)
Automatically populate the object based on a custom set of parameters (such as a filtered $_POST coll...
Definition: data_item.inc:1023
copy($from)
Copies values from another object, field by field.
Definition: data_item.inc:1067
getRelated($class, $field="")
Returns a single item related by the specified foreign key.
Definition: data_item.inc:1115
deleteAll()
Delete all the rows in the database that correspond to this class.
Definition: data_item.inc:865
reindexList($list, $field, $autoPromote=true)
Reindex an indexed or grouped query result by a different field.
Definition: data_item.inc:1799
formatField($template)
Definition: data_item.inc:1544
extractFieldValues($items, $field)
Extract the field values for the specified field from a list of DataItems.
Definition: data_item.inc:2064
Simple field comparator to support sorting arrays of DataItems by the values in a specified field...
Definition: data_item.inc:1910
const SerializeRelations
static get($key)
Retrieve the specified object from the cache.
Definition: cache.inc:88
fromPOST()
Automatically populate the object based on parameters in the $_POST collection.
Definition: data_item.inc:985
startsWith($text, $start)
Tests whether a string starts with a given sub-string.
Definition: functions.inc:1419
overrideFieldType($field, $type)
Override the type for the specified field.
Definition: data_item.inc:341
getPrimaryKeyList()
Retrieves a list of all the primary keys used for an object as an array.
Definition: data_item.inc:458
update()
Update the row in the database that corresponds to this object.
Definition: data_item.inc:660
formatItems($items, $template, $separator="")
Format a list of DataItems using the specified templated.
Definition: data_item.inc:2031
formatFieldValue($field, $template="")
updateSortOrder($class, $field="sort_order", $params=null)
Utility method to update sort order for the selected class of objects based on an array that maps pri...
Definition: data_item.inc:1947
getHiddenFields()
Definition: data_item.inc:244
prettifyFieldName($field)
Definition: data_item.inc:1670
static put($key, $obj, $ttl=0)
Store the specified object in the cache at the specified key.
Definition: cache.inc:106
Abstract base class for all DataItem implementations.
toJSONGrouped($items)
Definition: data_item.inc:2006
findItemIndex($items, $field, $value)
Find the index of the first item in the array that matches the supplied value for the specified field...
Definition: data_item.inc:2118
displayFieldAsList($items, $field, $separator=", ")
Definition: data_item.inc:2018
extractItems($items, $indexFormat, $valueFormat)
Definition: data_item.inc:2047
DataItem is the generic base class for database mapped classes.
Definition: data_item.inc:57
setFilter($filter)
Sets the filter on this object.
Definition: data_item.inc:508
hasField($field)
Returns true if this DataItem contains a field with the specified name and that field is not excluded...
Definition: data_item.inc:428
fromREQUEST()
Automatically populate the object based on parameters in either the $_GET or $_POST collection...
Definition: data_item.inc:1005
getRelatedList($class, $field="", $orderBy="")
Returns a list of items that are related to this item.
Definition: data_item.inc:1165
format($template="", $separator=", ")
Substitute values for field names in a string, with the fields formatted using their type&#39;s default f...
Definition: data_item.inc:1483
getPrimaryKey()
Retrieves the primary key field name.
Definition: data_item.inc:449
Used to place a filter on the contents of a DataItem-derived object.
relateTo($target, $field="")
Link this object to the specified target by setting corresponding field to the value of the target&#39;s ...
Definition: data_item.inc:1692
insert()
Insert a new row in the database to store this object.
Definition: data_item.inc:761
trace($msg, $lvl, $callStack=null)
Send output to the trace log.
Definition: functions.inc:959
static create($class, $constraints="", $indexBy="")
fromXML($node)
Definition: data_item.inc:1386
getFields()
Retrieve the field type list for this object.
Definition: data_item.inc:327
querySingle($class)
Performs a query against the database and returns a matching singleton object.
Definition: data_item.inc:1711
static registerEventHandler($class, $event, $handler)
Register an event handler for a specific event and DataItem class.
Definition: data_item.inc:146
The DataTransaction class wraps the underlying database&#39;s transaction model.
Definition: transaction.inc:44
select()
Select the object from the database, based on the value of the primary key field. ...
Definition: data_item.inc:609
const SerializeDirectRelations
sortList(&$list, $field)
Sorts an array of DataItems based on the values in the specified field.
Definition: data_item.inc:1931
getConnection()
Retrieves a connection to the database.
removeDuplicates($list, $field="")
Remove duplicate DataItems from a list, based on the value of a field.
Definition: data_item.inc:1882
distinctValues($field, $sorted=false, $constraint="")
Retrieves the distinct values in the database for the specified field across the specified set of rec...
Definition: data_item.inc:926
static $_eventMap
Definition: data_item.inc:59
tableExists()
Check if the table for this class exists in the database.
Definition: data_item.inc:888
populate($line, $alias=false)
Populates the object using the supplied associative array (field -> value).
Definition: data_item.inc:257
fireEvent($event)
Fires the specified event to all registered handlers.
Definition: data_item.inc:164
regroupList($list, $field)
Regroup an indexed or grouped query result by a different field.
Definition: data_item.inc:1849
fromGET()
Automatically populate the object based on parameters in the $_GET collection.
Definition: data_item.inc:967
getTransaction()
Retrieves the current DataTransaction.
Definition: data_item.inc:201
findItem($items, $field, $value)
Find the first item in the array that matches the supplied value for the specified field...
Definition: data_item.inc:2100
cast($class)
Cast this object to another class.
Definition: data_item.inc:214
checkNumeric($p)
Security helper function.
Definition: functions.inc:630
static getConnection()
Retrieves a reference to the global database connection.
getType($field)
Retrieves the data type of the specified field.
Definition: data_item.inc:490
updateExplicit($updates, $params=null)
Executes an explicit update command against the database.
Definition: data_item.inc:724
static $dataTypeRendererMap
Definition: data_item.inc:66
DataItem()
Constructor.
Definition: data_item.inc:92
cacheLookup($id)
Definition: data_item.inc:1084
joinTransaction($tx)
Join the DataItem to the specified DataTransaction.
Definition: data_item.inc:193
query($class)
Performs a query against the database, returning an array of DataItem objects of the specified class...
Definition: query.inc:360
getFieldList($alias="")
Returned a comma-separated list of the fields for this object (applying the assigned filter if there ...
Definition: data_item.inc:355
restoreHTML($text)
Definition: data_item.inc:2131
queryValue($func)
Query the database to calculate an aggregate value.
Definition: data_item.inc:1247
getFieldAnnotations()
Retrieve the list of field annotations.
Definition: data_item.inc:526
crossReference($class, $xref, $orderBy="", $pkField="", $xrefField="")
Returns a list of items related to this item via a cross-reference table.
Definition: data_item.inc:1187
save()
Store the object in the database.
Definition: data_item.inc:589
getFieldAliases()
Retrieve the list of field aliases.
Definition: data_item.inc:517
enablePrimaryKey()
Definition: data_item.inc:234
exists($constraint="")
Check whether the object exists in the database.
Definition: data_item.inc:618
jsSafe($str, $escapeEntities=false)
Utility function to escape a string correctly for use in a Javascript client-side call...
Definition: functions.inc:434
quoteFieldValue($field, $type)
Returns the properly quoted value of the specified field.
static invalidate($key)
Invalidates the specifed entry in the cache.
Definition: cache.inc:119
dumpCSV($class, $items, $filepath, $filter=null, $append=false)
Dump a raw representation of a list of DataItems to CSV (one column per field, default format only) ...
Definition: data_item.inc:2143
extractIndexedFieldValues($items, $field)
Extract the field values for the specified field from a list of DataItems and return them in an array...
Definition: data_item.inc:2081
const ProtectHTML
disablePrimaryKey()
Definition: data_item.inc:224
getFilter()
Returns the filter set on this object.
Definition: data_item.inc:499