Framework  3.9
data_item.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__)."/connection_manager.inc");
38 require_once realpath(dirname(__FILE__)."/abstract_data_item.inc");
39 require_once realpath(dirname(__FILE__)."/query.inc");
40 require_once realpath(dirname(__FILE__)."/indexed_query.inc");
41 require_once realpath(dirname(__FILE__)."/grouped_query.inc");
42 require_once realpath(dirname(__FILE__)."/iterated_query.inc");
43 require_once realpath(dirname(__FILE__)."/json_query.inc");
44 
45 /*define("String", 1);
46 define("Number", 2);
47 define("Date", 3);
48 define("HTML", 4);
49 define("Currency", 5);
50 define("Boolean", 6);
51 define("Password", 7);
52 define("Timestamp", 8);
53 define("Text", 9);*/
54 
62 {
63  static $_eventMap = array();
64 
65  var $_tx = null;
66  var $_pkDisabled = false;
67 
68  // When adding new renderers, must also update
69  // AutoForm $fieldRendererMap
70  static $dataTypeRendererMap = array(
71  "Boolean" => BooleanTypeRenderer,
72  "Currency" => CurrencyTypeRenderer,
73  "Currency3" => CurrencyTypeRenderer,
74  "Date" => DateTypeRenderer,
75  "DateTime" => DateTimeTypeRenderer,
76  "Time" => TimeTypeRenderer,
77  "Number" => NumberTypeRenderer,
78  "String" => StringTypeRenderer,
79  "Text" => TextTypeRenderer,
80  "HTML" => TextTypeRenderer,
81  "Timestamp" => TimestampTypeRenderer,
82  "Timezone" => TimezoneTypeRenderer,
83  "PhoneNumber" => PhoneNumberTypeRenderer,
84  "DateOfBirth" => DateTypeRenderer
85  );
86 
87 
97  function DataItem()
98  {
99  if (func_num_args() > 0)
100  {
101  $arg = func_get_arg(0);
102 
103  if (is_array($arg) )
104  {
105  if (count($arg) > 1)
106  {
107  $this->populate($arg);
108  }
109  else if (count($arg) > 0)
110  {
111  if (is_array($arg[0]))
112  {
113  $this->populate($arg[0]);
114  }
115  else
116  {
117  $this->load($arg[0]);
118  }
119  }
120  }
121  else
122  {
123  if (func_num_args() > 1)
124  {
125  $this->filter = func_get_arg(1);
126  }
127 
128  $this->load($arg);
129  }
130  }
131  }
132 
133  function __sleep()
134  {
135  // No need to persist class variables, such as field metadata
136 
137  $f = array_keys($this->getFields());
138  array_push($f, "primary_key", "table", "filter");
139  return $f;
140  }
141 
151  static function registerEventHandler($class, $event, $handler)
152  {
153  $eventKey = "{$class}_{$event}";
154 
155  if (!array_key_exists($eventKey, DataItem::$_eventMap))
156  {
157 
158  DataItem::$_eventMap[$eventKey]= array();
159  }
160 
161  array_push(DataItem::$_eventMap[$eventKey], $handler);
162  }
163 
169  function fireEvent($event)
170  {
171  $eventKey = get_class($this)."_{$event}";
172  if (!array_key_exists($eventKey, DataItem::$_eventMap))
173  {
174  return;
175  }
176 
177  trace("===== DataItem event key = $eventKey", 3);
178  $handlers = DataItem::$_eventMap[$eventKey];
179 
180  if (!is_array($handlers)) return;
181  foreach($handlers as $handler)
182  {
183  if (!is_callable($handler))
184  {
185  trace(get_class($this)." {$event} handler is invalid", 2);
186  }
187  else
188  {
189  call_user_func_array($handler, array($this));
190  }
191  }
192  }
193 
198  function joinTransaction($tx)
199  {
200  $this->_tx = $tx;
201  }
202 
206  function getTransaction()
207  {
208  return $this->_tx;
209  }
210 
219  function cast($class)
220  {
221  if (get_class($this) != $class)
222  {
223  throw new DataItemException("Cannot cast ".get_class($this)." to $class.");
224  }
225 
226  return $this;
227  }
228 
229  function disablePrimaryKey()
230  {
231  if (!$this->_disablePK)
232  {
233  $conn = $this->getConnection();
234  $conn->prepare("ALTER TABLE `{$this->table}` DISABLE KEYS")->execute();
235  $this->_disablePK = true;
236  }
237  }
238 
239  function enablePrimaryKey()
240  {
241  if ($this->_disablePK)
242  {
243  $conn = $this->getConnection();
244  $conn->prepare("ALTER TABLE `{$this->table}` ENABLE KEYS")->execute();
245  $this->_disablePK = false;
246  }
247  }
248 
249  function getHiddenFields()
250  {
251  return $this->hiddenFields;
252  }
253 
262  function populate($line, $alias = false)
263  {
264  global $config;
265 
266  // NOTE - structured for speed, since the general case is no aliasing
267  // therefore we want to reduce the number of tests of the alias
268 
269  $fields = $this->getFields();
270 
271  if ($alias)
272  {
273  $offset = strlen($alias) + 1;
274 
275  foreach ($line as $field => $value)
276  {
277  if (!startsWith($field, $alias)) continue;
278  $field = substr($field, $offset);
279 
280  if (!array_key_exists($field, $fields)) continue;
281  if ($this->filter && $this->filter->isExcluded($field)) continue;
282 
283  if (!isset($config["no_charset_conversions"]) || $config["no_charset_conversions"])
284  {
285  $this->$field = $value;
286  }
287  else
288  {
289  $this->$field = iconv("UTF-8", "CP1252//IGNORE", $value);
290  }
291  }
292  }
293  else
294  {
295  foreach ($line as $field => $value)
296  {
297  if (!array_key_exists($field, $fields)) continue;
298  if ($this->filter && $this->filter->isExcluded($field)) continue;
299 
300  if (!isset($config["no_charset_conversions"]) || $config["no_charset_conversions"])
301  {
302  $this->$field = $value;
303  }
304  else
305  {
306  $this->$field = iconv("UTF-8", "CP1252//IGNORE", $value);
307  }
308  }
309  }
310 
311  if (isset($this->calculatedFields))
312  {
313  foreach($this->calculatedFields as $field => $expr)
314  {
315  if ($alias)
316  {
317  $this->$field = $line[$alias.".".$field];
318  }
319  else
320  {
321  $this->$field = $line[$field];
322  }
323  }
324  }
325 
326  $this->unpack();
327  $this->fireEvent("onPopulate");
328  }
329 
333  function getFields()
334  {
335  if ($this->fields) return $this->fields;
336  $class = get_class($this);
337  if ($class::$fields) return $class::$fields;
338 
339  throw new FakoliException("DataItem does not contain any fields");
340  }
341 
347  function overrideFieldType($field, $type)
348  {
349  if (!is_array($this->fields))
350  {
351  throw new FakoliException("Cannot override field types for statically defined DataItems");
352  }
353 
354  $this->fields[$field] = $type;
355  }
356 
361  function getFieldList($alias = "")
362  {
363  $list = "";
364  $first = true;
365 
366  foreach($this->getFields() as $field => $type)
367  {
368  if ($this->filter && $this->filter->isExcluded($field)) continue;
369  if (!$first) $list .= ", ";
370  if ($alias)
371  {
372  $list .= "$alias.";
373  }
374  $list .= "`".$field."`";
375  if ($alias)
376  {
377  $list .= " as `$alias.$field`";
378  }
379  $first = false;
380  }
381 
382  if (isset($this->calculatedFields))
383  {
384  foreach($this->calculatedFields as $field => $expr)
385  {
386  if ($this->filter && $this->filter->isExcluded($field)) continue;
387  if (!$first) $list .= ", ";
388 
389  if ($alias)
390  {
391  foreach($this->getFields() as $f => $type)
392  {
393  $expr = preg_replace('/([\s\‍(])('.$f.')\b/', "$1{$alias}.$2", $expr);
394  $expr = preg_replace('/\b'.$this->table.'\.'.$f.'\b/', "{$alias}.{$f}", $expr);
395  }
396  }
397 
398  $list .= $expr . " as `";
399  if ($alias)
400  {
401  $list .= $alias.".";
402  }
403  $list .= $field."`";
404 
405  }
406  }
407 
408  return $list;
409  }
410 
415  function getFieldArray()
416  {
417  $arr = array();
418  foreach($this->getFields() as $field => $type)
419  {
420  if ($this->filter && $this->filter->isExcluded($field)) continue;
421  $arr[] = $field;
422  }
423 
424  return $arr;
425  }
426 
434  function hasField($field)
435  {
436  if (!array_key_exists($field, $this->getFields())) return false;
437  if ($this->filter && $this->filter->isExcluded($field)) return false;
438  return true;
439  }
440 
447  function hasRelation($relation)
448  {
449  return (!array_key_exists($relation, $this->relations)) ? false : true;
450  }
451 
455  function getPrimaryKey()
456  {
457  return $this->primary_key;
458  }
459 
464  function getPrimaryKeyList()
465  {
466  return array($this->primary_key);
467  }
468 
474  function get($field)
475  {
476  if (!$field) throw new FakoliException("Cannot access empty field");
477  return $this->$field;
478  }
479 
485  function set($field, $value)
486  {
487  if (!$field) throw new FakoliException("Cannot access empty field");
488  $this->$field = $value;
489  }
490 
496  function getType($field)
497  {
498  $fields = $this->getFields();
499  return $fields[$field];
500  }
501 
505  function getFilter()
506  {
507  return $this->filter;
508  }
509 
514  function setFilter($filter)
515  {
516  $this->filter = $filter;
517  }
518 
523  function getFieldAliases()
524  {
525  return $this->fieldAliases;
526  }
527 
533  {
534  return $this->fieldAnnotations;
535  }
536 
537 
543  function pack()
544  {
545  }
546 
552  function unpack()
553  {
554  }
555 
561  function load($id)
562  {
563  if ($this->cacheLookup($id)) return;
564 
565  $fields = $this->getFieldList();
566  $query = "SELECT $fields FROM {$this->table} WHERE {$this->primary_key}=$id ".$this->getIdentityConstraint();
567  trace("DataItem::load($id): $query", 3);
568 
569  $db = $this->getConnection();
570 
571  try
572  {
573  $result = $db->prepare($query);
574  $result->execute();
575 
576  if ($line = $result->fetch())
577  {
578  $this->populate($line);
579  }
580 
581  unset($result);
582  }
583  catch(PDOException $e)
584  {
585  $err = "DataItem::load() failed - ".$e->getMessage();
586  trace($err, 2);
587  throw new DataItemException($err);
588  }
589  }
590 
591 
601  function old()
602  {
603  $pk = $this->getPrimaryKeyValue();
604  if (!$pk) return null;
605 
606  $cl = get_class($this);
607  $n = new $cl;
608  $n->filter = $this->filter;
609  $n->joinTransaction($this->getTransaction());
610  $n->load($pk);
611  return $n;
612  }
613 
620  function loadComposite()
621  {
622  if (!$this->hasField("composite_class") || !$this->composite_class)
623  {
624  throw new DataItemException("Cannot create composite from ".get_class($this)." as required composite cannot be determined");
625  }
626 
627  $composite = new $this->composite_class;
628  $composite->loadFromBase($this->get($this->getPrimaryKey()));
629 
630  return $composite;
631  }
632 
636  function save()
637  {
638  if ($this->cacheLocal)
639  {
640  Cache::invalidate(get_class($this)."_cache");
641  }
642 
643  if ($this->exists())
644  {
645  return $this->update();
646  }
647  else
648  {
649  return $this->insert();
650  }
651  }
652 
656  function select()
657  {
658  $pk = $this->primary_key;
659  $this->load($this->$pk);
660  }
661 
665  function exists($constraint = "")
666  {
667 
668  $pk = $this->primary_key;
669 
670  if (!$constraint)
671  {
672  if ($this->$pk == "" || $this->$pk == 0) return false;
673  $constraint = "WHERE $pk={$this->$pk}";
674  }
675 
676  $query = "SELECT $pk FROM {$this->table} $constraint";
677  trace("DataItem::exists() - $query", 3);
678 
679  $db = $this->getConnection();
680  $exists = false;
681 
682  try
683  {
684  $result = $db->prepare($query);
685  $result->execute();
686 
687  if ($line = $result->fetch())
688  {
689  $exists = true;
690  }
691 
692  unset($result);
693  }
694  catch(PDOException $e)
695  {
696  $err = "DataItem::exists() failed - " . $e->getMessage();
697  trace($err, 2);
698  throw new DataItemException($err);
699  }
700 
701  return $exists;
702  }
703 
707  function update()
708  {
709  $this->fireEvent("beforeUpdate");
710  $this->pack();
711 
712  $pk = $this->primary_key;
713 
714  $query = "UPDATE {$this->table} SET ";
715 
716  $first = true;
717  $found = false;
718 
719  foreach($this->getFields() as $field => $type)
720  {
721  if ($field == $this->primary_key) continue;
722  if ($this->filter && $this->filter->isExcluded($field)) continue;
723  if (!isset($this->$field) && $this->getType($field) != Timestamp && $this->getType($field) != Boolean) continue;
724 
725  if (!$first) $query .= ", ";
726 
727  $first = false;
728  $found = true;
729 
730  $query .= "`$field`=";
731  $query .= $this->quoteFieldValue($field, $type);
732  }
733 
734  if (!$found) return true; // No fields to update - bug out quietly
735 
736  $query .= " WHERE $pk={$this->$pk} ".$this->getIdentityConstraint();
737 
738  trace("DataItem::update() - $query", 3);
739 
740  try
741  {
742 
743  $db = $this->getConnection();
744 
745  $success = $db->exec($query);
746  if ($success === FALSE)
747  {
748  trace("DataItem::update failed - $query", 2);
749  }
750  else
751  {
752  $this->fireEvent("onUpdate");
753  }
754  }
755  catch(PDOException $e)
756  {
757  $err = "DataItem::update() failed - " . $e->getMessage();
758  trace($err, 2);
759  throw new DataItemException($err);
760  }
761 
762  return $success;
763  }
764 
775  function updateExplicit($updates, $params = null)
776  {
777  $pk = $this->primary_key;
778 
779  $query = "UPDATE {$this->table} $updates";
780 
781  if ($this->get($pk))
782  {
783  $query .= " WHERE {$pk}=".$this->get($pk);
784  }
785 
786  trace("DataItem::update() - $query", 3);
787 
788  try
789  {
790  $db = $this->getConnection();
791  $stmt = $db->prepare($query);
792  $success = $stmt->execute($params);
793  if ($success === FALSE)
794  {
795  trace("DataItem::updateExplicit failed - $query", 2);
796  }
797  if ($this->get($pk)) $this->select();
798  }
799  catch(PDOException $e)
800  {
801  $err = "DataItem::updateExplicit() failed - " . $e->getMessage();
802  trace($err, 2);
803  throw new DataItemException($err);
804  }
805 
806  return $success;
807  }
808 
812  function insert()
813  {
814  $this->pack();
815 
816  $this->fireEvent("beforeInsert");
817 
818  $pk = $this->primary_key;
819 
820  $first = true;
821 
822  $timestampField = null;
823 
824  foreach($this->getFields() as $field => $type)
825  {
826  if ($field == $pk && !$this->_disablePK) continue;
827  if ($this->filter && $this->filter->isExcluded($field)) continue;
828  if (!isset($this->$field) && $this->getType($field) != Timestamp && $this->getType($field) != Boolean) continue;
829 
830  if ($type == Timestamp)
831  {
832  $timestampField = $field;
833  }
834 
835  if (!$first)
836  {
837  $fields .= ", ";
838  $values .= ", ";
839  }
840 
841  $fields .= "`".$field."`";
842  $values .= $this->quoteFieldValue($field, $type);
843 
844  $first = false;
845  }
846 
847  $query = "INSERT INTO {$this->table} ($fields) values ($values)";
848 
849  trace("DataItem::insert() - $query", 3);
850 
851  $success = false;
852 
853  try
854  {
855  $db = $this->getConnection();
856  $success = $db->exec($query);
857 
858  if ($success !== FALSE)
859  {
860  $this->$pk = $db->lastInsertId();
861  //AJG - Set the timestamp field value if the insert succeeded
862  if ($timestampField)
863  {
864  $this->$timestampField = $this->__timestamp;
865  unset($this->__timestamp);
866  }
867 
868  $this->fireEvent("onInsert");
869  }
870  else
871  {
872  $this->$pk = 0;
873  trace("DataItem::insert() failed - $query", 2);
874  }
875  }
876  catch(PDOException $e)
877  {
878  $err = "DataItem::insert() failed - ". $e->getMessage();
879  trace($err, 2);
880  throw new DataItemException($err);
881  }
882  return $success;
883  }
884 
888  function delete($constraint = "")
889  {
890  if ($constraint == "")
891  {
892  $fire = true;
893  $pk = $this->primary_key;
894  $constraint = "WHERE $pk={$this->$pk} ".$this->getIdentityConstraint();
895  }
896 
897  $query = "DELETE FROM {$this->table} $constraint";
898 
899  trace($query, 3);
900 
901  $db = $this->getConnection();
902 
903  try
904  {
905  if ($fire) $this->fireEvent("onPreDelete");
906  $db->exec($query);
907  if ($fire) $this->fireEvent("onPostDelete");
908  }
909  catch(PDOException $e)
910  {
911  $err = "DataItem::delete() failed - " . $e->getMessage();
912  trace($err, 2);
913  throw new DataItemException($err);
914  }
915  }
916 
920  function deleteAll()
921  {
922  //$query = "TRUNCATE TABLE {$this->table}";
923  $query = "DELETE FROM {$this->table}; ALTER TABLE {$this->table} AUTO_INCREMENT=1";
924  $db = $this->getConnection();
925 
926  trace($query, 3);
927 
928  try
929  {
930  $db->exec($query);
931  $this->fireEvent("onDeleteAll");
932  }
933  catch(PDOException $e)
934  {
935  $err = "DataItem::deleteAll() failed - " . $e->getMessage();
936  trace($err, 2);
937  throw new DataItemException($err);
938  }
939  }
940 
944  function tableExists()
945  {
946  $query = "SHOW TABLES LIKE '{$this->table}'";
947  $db = $this->getConnection();
948 
949  trace($query, 3);
950 
951  $exists = false;
952 
953  try
954  {
955  $result = $db->prepare($query);
956  $result->execute();
957 
958  if ($line = $result->fetch())
959  {
960  $exists = true;
961  }
962 
963  unset($result);
964  }
965  catch(PDOException $e)
966  {
967  $err = "DataItem::tableExists() failed - " . $e->getMessage();
968  trace($err, 2);
969  throw new DataItemException($err);
970  }
971 
972  return $exists;
973  }
974 
983  function duplicate()
984  {
985  $pk = $this->primary_key;
986  $old = $this->get($pk);
987 
988  unset($this->$pk);
989  $this->save();
990  return $old;
991  }
992 
1001  function distinctValues($field, $sorted = false, $constraint = "")
1002  {
1003  $query = "SELECT DISTINCT $field from {$this->table} $constraint";
1004 
1005  trace($query, 3);
1006 
1007  $db = $this->getConnection();
1008 
1009  try
1010  {
1011  $result = $db->prepare($query);
1012  $result->execute();
1013 
1014  $values = array();
1015 
1016  while($line = $result->fetch())
1017  {
1018  $values[] = $line[$field];
1019  }
1020 
1021  if ($sorted)
1022  {
1023  sort($values);
1024  }
1025 
1026  unset($result);
1027 
1028  return $values;
1029  }
1030  catch(PDOException $e)
1031  {
1032  $err = "DataItem::distinctValues() failed - " . $e->getMessage();
1033  trace($err, 2);
1034  throw new DataItemException($err);
1035  }
1036 
1037  }
1038 
1042  function fromGET()
1043  {
1044  foreach($this->getFields() as $field => $type)
1045  {
1046  if ($this->filter && $this->filter->isExcluded($field)) continue;
1047  if (array_key_exists($field, $_GET))
1048  {
1049  $this->set($field, $_GET[$field]);
1050  }
1051  }
1052 
1053  $this->unpack();
1054  }
1055 
1062  function fromPOST()
1063  {
1064  foreach($this->getFields() as $field => $type)
1065  {
1066  if ($this->filter && $this->filter->isExcluded($field)) continue;
1067  if (array_key_exists($field, $_POST))
1068  {
1069  $this->set($field, $_POST[$field]);
1070  }
1071  elseif (!array_key_exists($field, $_POST) AND ($type == Boolean))
1072  {
1073  $this->$field = 0;
1074  }
1075  }
1076 
1077  $this->unpack();
1078  }
1079 
1084  function fromREQUEST()
1085  {
1086  switch($_SERVER["REQUEST_METHOD"])
1087  {
1088  case "POST":
1089  $this->fromPOST();
1090  break;
1091 
1092  case "GET":
1093  default:
1094  $this->fromGET();
1095  }
1096  }
1097 
1102  function fromDataSet($params)
1103  {
1104  foreach($this->getFields() as $field => $type)
1105  {
1106  if ($this->filter && $this->filter->isExcluded($field)) continue;
1107  if (array_key_exists($field, $params))
1108  {
1109  $this->$field = $params[$field];
1110  }
1111  elseif (!array_key_exists($field, $params) AND ($type == Boolean))
1112  {
1113  $this->$field = 0;
1114  }
1115  }
1116 
1117  $this->unpack();
1118  }
1119 
1127  function compare($to)
1128  {
1129  foreach($this->getFields() as $field => $type)
1130  {
1131  if ($this->filter && $this->filter->isExcluded($field)) continue;
1132  if ($to->$field != $this->$field)
1133  {
1134  trace("$field '{$this->$field}' != '{$to->$field}'", 3);
1135  return false;
1136  }
1137  }
1138 
1139  return true;
1140  }
1141 
1148  function copy($from)
1149  {
1150  foreach($this->getFields() as $field => $type)
1151  {
1152  if ($this->filter && $this->filter->isExcluded($field)) continue;
1153  $this->set($field, $from->$field);
1154  }
1155 
1156  if (is_array($this->calculatedFields))
1157  {
1158  foreach($this->calculatedFields as $field => $expr)
1159  {
1160  $this->set($field, $from->$field);
1161  }
1162  }
1163  }
1164 
1172  function cloneFrom($from)
1173  {
1174  $this->copy($from);
1175  $pk = $this->primary_key;
1176  unset($this->$pk);
1177  }
1178 
1179  function cacheLookup($id)
1180  {
1181  if ($this->cacheLocal)
1182  {
1183  $cache = get_class($this)."_cache";
1184  $items = Cache::get($cache);
1185  if (!is_array($items))
1186  {
1187  $items = IndexedQuery::create(get_class($this), "", $this->primary_key)->execute();
1188  Cache::put($cache, $items);
1189  }
1190  if (array_key_exists($id, $items))
1191  {
1192  trace("Using local cache $cache for item $id", 5);
1193  $this->copy($items[$id]);
1194  return true;
1195  }
1196  }
1197 
1198  return false;
1199  }
1200 
1210  function getRelated($class, $field = "")
1211  {
1212  $obj = new $class;
1213  if ($field == "")
1214  {
1215  $field = $obj->primary_key;
1216 
1217  }
1218 
1219  if (array_key_exists($field, $this->getFields()))
1220  {
1221  $pk = $obj->primary_key;
1222  $val = $this->get($field);
1223 
1224  if (!$val) return null;
1225 
1226  $obj->$pk = $val;
1227 
1228  $cache = "_{$class}_{$field}_{$val}";
1229  if (isset($this->$cache))
1230  {
1231  $obj->copy($this->$cache);
1232  }
1233  else
1234  {
1235  $obj->select();
1236  $this->$cache = $obj;
1237  }
1238  }
1239  else
1240  {
1241  $field = $this->primary_key;
1242  $obj = querySingle($class, "WHERE $field={$this->$field}");
1243  }
1244  return $obj;
1245  }
1246 
1260  function getRelatedList($class, $field = "", $orderBy = "")
1261  {
1262  $pk = $this->primary_key;
1263 
1264  if ($field == "") $field = $pk;
1265  $value = $this->$field ? $this->$field : $this->$pk;
1266  $orderBy = preg_replace("/^\s*WHERE\s+/i", "AND ", $orderBy);
1267  //$this->quoteFieldValue($this->$field, $this->fields[$field])
1268  $list = query($class, "WHERE $field=$value $orderBy");
1269 
1270  return $list;
1271  }
1272 
1286  function crossReference($class, $xref, $orderBy = "", $pkField = "", $xrefField = "")
1287  {
1288  $obj = new $class;
1289  $xref = new $xref;
1290 
1291  if ($orderBy != "")
1292  {
1293  foreach($obj->getFields() as $field => $type)
1294  {
1295  $orderBy = preg_replace("/\\b".$field."\\b/i", "a0.$field", $orderBy);
1296  }
1297  }
1298 
1299  $orderBy = preg_replace("/^\s*WHERE\s+/i", "AND ", $orderBy);
1300 
1301  $xt = $xref->table;
1302  $xp = ($xrefField != "") ? $xrefField : $obj->primary_key;
1303 
1304  $pkField = ($pkField != "") ? $pkField : $this->primary_key;
1305  $pk = $this->primary_key;
1306 
1307  $fieldList = $obj->getFieldList("a0");
1308 
1309  $query = "SELECT {$fieldList} FROM {$obj->table} a0, $xt x WHERE a0.{$obj->primary_key}=x.{$xp} AND x.{$pkField}={$this->$pk} $orderBy";
1310 
1311  trace($query, 3);
1312 
1313  try
1314  {
1315  $db = $this->getConnection();
1316 
1317  $result = $db->prepare($query);
1318  $result->execute();
1319 
1320  $list = array();
1321  while ($line = $result->fetch())
1322  {
1323  $obj = new $class;
1324  $obj->populate($line, "a0");
1325  $list[] = $obj;
1326  }
1327 
1328  unset($result);
1329  }
1330  catch(PDOException $e)
1331  {
1332  $err = "DataItem::crossReference() failed - " . $e->getMessage();
1333  trace($err, 2);
1334  throw new DataItemException($err);
1335  }
1336  return $list;
1337  }
1338 
1346  function queryValue($func)
1347  {
1348  $constraints = "";
1349  $value = null;
1350 
1351  if (func_num_args() > 1)
1352  {
1353  $constraints = func_get_arg(1);
1354 
1355  if (func_num_args() > 2)
1356  {
1357  $value = func_get_arg(2);
1358  }
1359  }
1360 
1361  if ($constraints == "") $constraints = "WHERE 1=1"; //TODO - tidy this up some day
1362  $constraints .= " ".$this->getIdentityConstraint();
1363 
1364  $query = "SELECT $func as result FROM {$this->table} $constraints";
1365 
1366  trace("DataItem::queryValue: $query", 3);
1367  try
1368  {
1369  $db = $this->getConnection();
1370  $result = $db->prepare($query);
1371  $result->execute();
1372 
1373  if ($row =$result->fetch())
1374  {
1375  $value = $row['result'];
1376  }
1377 
1378  unset($result);
1379  }
1380  catch(PDOException $e)
1381  {
1382  $err = "DataItem::queryValue() failed - " . $e->getMessage();
1383  trace($err, 2);
1384  throw new DataItemException($err);
1385  }
1386 
1387  return $value;
1388 
1389  }
1390 
1396  function toXML($indent = 0, $path = null)
1397  {
1398  trace(get_class($this)."->toXML()", 4);
1399 
1400  $xml = str_repeat(" ", $indent) . "<" . get_class($this) . ">\n";
1401 
1402  foreach($this->getFields() as $field => $type)
1403  {
1404  if ($this->filter && $this->filter->isExcluded($field)) continue;
1405  if (isset($this->$field))
1406  {
1407  if ($this->$field === "")
1408  {
1409  $xml .= str_repeat(" ", $indent) . " <$field/>\n";
1410  }
1411  else
1412  {
1413  $xml .= str_repeat(" ", $indent) . " <{$field}>".$this->formatFieldForXML($field)."</$field>\n";
1414  }
1415 
1416  }
1417  }
1418 
1419  $path[get_class($this)] = true;
1420  trace(implode(" > ", array_keys($path)), 4);
1421  trace("Options: ".$this->_options, 4);
1422 
1423  if (($this->_options & SerializeRelations) ||
1424  ($this->_options & SerializeDirectRelations) &&
1425  $this->relations)
1426  {
1427  if (is_array($this->relations))
1428  {
1429  foreach($this->relations as $rel => $relType)
1430  {
1431  if (is_array($path) && array_key_exists($relType, $path)) continue;
1432 
1433  $obj = $this->$rel();
1434  if ($obj)
1435  {
1436  $xml .= str_repeat(" ", $indent) . " <$rel>\n";
1437 
1438  if (is_array($obj))
1439  {
1440  foreach($obj as $item)
1441  {
1442  if ($this->_options & SerializeRelations)
1443  {
1444  $item->setOption(SerializeRelations);
1445  }
1446 
1447  if ($this->_options & ProtectHTML)
1448  {
1449  $item->setOption(ProtectHTML);
1450  }
1451 
1452  $xml .= $item->toXML($indent + 2, $path);
1453  }
1454  }
1455  else
1456  {
1457  if ($this->_options & SerializeRelations)
1458  {
1459  $obj->setOption(SerializeRelations);
1460  }
1461 
1462  if ($this->_options & ProtectHTML)
1463  {
1464  $obj->setOption(ProtectHTML);
1465  }
1466 
1467  $xml .= $obj->toXML($indent + 2, $path);
1468  }
1469 
1470  $xml .= str_repeat(" ", $indent) . " </$rel>\n";
1471  }
1472  else
1473  {
1474  $xml .= str_repeat(" ", $indent) . " <$rel/>\n";
1475  }
1476  }
1477  }
1478  }
1479 
1480  $xml .= str_repeat(" ", $indent) . "</" . get_class($this) . ">\n";
1481 
1482  return $xml;
1483  }
1484 
1485  function fromXML($node)
1486  {
1487  if ($node->nodeType != XML_ELEMENT_NODE || $node->tagName != get_class($this)) return;
1488 
1489  $kids = $node->childNodes;
1490  $numChildren = $kids->length;
1491 
1492  for($i = 0; $i < $numChildren; ++$i)
1493  {
1494  $n = $kids->item($i);
1495 
1496  if ($n->nodeType != XML_ELEMENT_NODE) continue;
1497  $field = $n->tagName;
1498  $this->set($field, $n->nodeValue);
1499  }
1500  }
1501 
1502  function toJSON()
1503  {
1504  $out = array();
1505 
1506  foreach($this->getFields() as $field => $type)
1507  {
1508  if ($this->filter && $this->filter->isExcluded($field))
1509  {
1510  continue;
1511  }
1512 
1513  $val = str_replace("\\'", "'", json_encode((string)$this->get($field)));
1514 
1515  $out[] = "\"{$field}\": ".$val;
1516  }
1517 
1518  return "{".implode(", ", $out)."}";
1519  }
1520 
1582  function format($template = "", $separator = ", ")
1583  {
1584  if ($template == "") $template = $this->default_format;
1585  if (is_array($template) && is_callable($template))
1586  {
1587  return call_user_func($template, $this);
1588  }
1589 
1590  foreach($this->getFields() as $field => $type)
1591  {
1592  $template = str_replace("{".$field."}", $this->formatFieldValue($field), $template);
1593  }
1594 
1595  if (isset($this->calculatedFields))
1596  {
1597  foreach($this->calculatedFields as $field => $expr)
1598  {
1599  $template = str_replace("{".$field."}", $this->$field, $template);
1600  }
1601  }
1602 
1603  if (isset($this->_decorations))
1604  {
1605  foreach($this->_decorations as $field => $value)
1606  {
1607  $template = str_replace("{".$field."}", $value, $template);
1608  }
1609  }
1610 
1611  // Allow drill-down through relation functions
1612  $template = $this->formatThroughRelation($template, $separator);
1613 
1614  $template = $this->formatField($template);
1615 
1616  // Simple method calls - no parameter passing
1617  // ??Is this block ever executed??
1618 
1619  $matches = array();
1620  preg_match_all("/\\{([\\w_]+)\\(\\)\\}/", $template, $matches, PREG_SET_ORDER);
1621 
1622  foreach($matches as $match)
1623  {
1624  $format = $match[0];
1625  $method = $match[1];
1626 
1627  $value = $this->$method();
1628 
1629  $template = str_replace($format, $value, $template);
1630  }
1631 
1632  return $template;
1633  }
1634 
1635  /*
1636  * Call formatFieldValue on a field with
1637  * formatting specification given.
1638  *
1639  * e.g.:
1640  * {amount:2}
1641  * {start_date:long}
1642  */
1643  function formatField($template)
1644  {
1645  $matches = array();
1646 
1647  preg_match_all("/\\{([\\w\\d_]+)(::?|\\^|\\(\\)|\\|)?([^}]*)}/", $template, $matches, PREG_SET_ORDER);
1648 
1649  foreach($matches as $match)
1650  {
1651  $field = $match[1];
1652  // JDG 3/12 fix issue with call to function in DataItem in format like "{getTitle()}" with no separator;
1653  $separator = ($match[2]) ? $match[2] : ":";
1654 
1655  $fieldFormat = $match[3];
1656  trace("formatField, template $template, field $field, separator $separator and fieldFormat $fieldFormat", 5);
1657 
1658  $format = "{".$field.$separator.$fieldFormat."}";
1659 
1660  switch($separator)
1661  {
1662  case "|":
1663  if (!$this->get($field))
1664  {
1665  $sub = $fieldFormat;
1666  }
1667  else
1668  {
1669  $sub = $this->formatFieldValue($field);
1670  }
1671  break;
1672 
1673  case "^":
1674  if (!$this->get($field))
1675  {
1676  $sub = $this->format("{".$fieldFormat."}");
1677  }
1678  else
1679  {
1680  $sub = $this->formatFieldValue($field);
1681  }
1682  break;
1683 
1684  case "::":
1685 
1686  $sub = call_user_func(array($field, $fieldFormat), $this);
1687  break;
1688 
1689  case "()":
1690 
1691  $sub = $this->$field();
1692  break;
1693 
1694  case ":":
1695  default:
1696  $sub = $this->formatFieldValue($field, $fieldFormat);
1697  }
1698 
1699  $template = str_replace($format, $sub, $template);
1700  }
1701  return $template;
1702  }
1703 
1704  /*
1705  * Format a field value that is accessed through a relation.
1706  * The relation can return multiple items.
1707  * e.g.,
1708  *
1709  * {Program.program_name}
1710  * {Event.start_date} or {Event.start_date:long}
1711  * {Events.event_name}
1712  */
1713  function formatThroughRelation($template, $separator = ", ")
1714  {
1715  $matches = array();
1716  preg_match_all("/\\{([\\w\\d_]+)\\.([\\w\\d_\\.\\(\\)]+)([:\\|\\^])?([^}]*)}/", $template, $matches, PREG_SET_ORDER);
1717 
1718  foreach($matches as $match)
1719  {
1720  $relation = $match[1];
1721  $field = $match[2];
1722  $divider = $match[3];
1723  if(count($match) == 5 && preg_match("/^where|order/i", $match[4]))
1724  $constraint = $match[4];
1725  elseif(count($match) == 5)
1726  $fieldTemplate = $match[4];
1727 
1728  trace("function format: formatThroughRelations template $template field $field relation $relation constraint $constraint", 5);
1729 
1730  if ($constraint)
1731  {
1732  $relations = $this->$relation($constraint);
1733  $format = "{".$relation.".".$field.$divider.$constraint."}";
1734  }
1735  elseif($fieldTemplate)
1736  {
1737  $relations = $this->$relation();
1738  $format = "{".$relation.".".$field.$divider.$fieldTemplate."}";
1739  }
1740  else
1741  {
1742  $relations = $this->$relation();
1743  $format = "{".$relation.".".$field."}";
1744  }
1745 
1746  $sub = "";
1747 
1748  if (is_array($relations))
1749  {
1750  $formatTemplate = ($fieldTemplate) ? "{".$field .":".$fieldTemplate . "}" : "{".$field."}";
1751  $sub = formatItems($relations, $formatTemplate, $separator);
1752 
1753  }
1754  else if ($relations)
1755  {
1756  if ($fieldTemplate) $fieldTemplate = ":{$fieldTemplate}";
1757  if ($relations) $sub = $relations->format("{{$field}{$fieldTemplate}}");
1758  }
1759 
1760  trace("format using relations: Replacing {$match[0]} [ $format ] with '$sub'", 5);
1761 
1762  $template = str_replace($format, $sub, $template);
1763  }
1764 
1765  return $template;
1766  }
1767 
1768 
1769  function prettifyFieldName($field)
1770  {
1771  if (isset($this->fieldAliases) && array_key_exists($field, $this->fieldAliases))
1772  {
1773  return $this->fieldAliases[$field];
1774  }
1775 
1776  $field = preg_replace("/([a-z])([A-Z0-9])/", "$1 $2", $field);
1777  $field = str_replace("_", " ", $field);
1778  $field = ucwords($field);
1779 
1780  return $field;
1781  }
1782 
1791  function relateTo($target, $field = "")
1792  {
1793  $pk = $target->primary_key;
1794 
1795  if (!$field) $field = $pk;
1796 
1797  $this->$field = $target->$pk;
1798  }
1799 }
1800 
1801 
1802 
1810 function querySingle($class)
1811 {
1812  $constraints = "";
1813 
1814  if (func_num_args() > 1)
1815  {
1816  $constraints = func_get_arg(1);
1817  }
1818 
1819  $result = query($class, $constraints);
1820 
1821  if (count($result) > 1)
1822  {
1823  throw new DataItemException("Ambiguous singleton query");
1824  }
1825 
1826  if (count($result) == 1)
1827  {
1828  return $result[0];
1829  }
1830 
1831  return null;
1832 }
1833 
1842 function queryValue($class, $func)
1843 {
1844  $constraints = "";
1845  $value = null;
1846 
1847  if (func_num_args() > 2)
1848  {
1849  $constraints = func_get_arg(2);
1850 
1851  if (func_num_args() > 3)
1852  {
1853  $value = func_get_arg(3);
1854  }
1855  }
1856 
1857  $prototype = new $class;
1858 
1859  if ($constraints == "") $constraints = "WHERE 1=1"; //TODO - tidy this up some day
1860  $constraints .= " ".$prototype->getIdentityConstraint();
1861 
1862  $query = "SELECT $func as result FROM {$prototype->table} $constraints";
1863 
1864  trace($query, 3);
1865 
1866  try
1867  {
1869 
1870  $result = $db->prepare($query);
1871  $result->execute();
1872 
1873  if ($row = $result->fetch())
1874  {
1875  $value = $row['result'];
1876  }
1877 
1878  unset($result);
1879  }
1880  catch(PDOException $e)
1881  {
1882  $err = "queryValue() failed - " . $e->getMessage();
1883  trace($err, 2);
1884  throw new DataItemException($err);
1885  }
1886 
1887  return $value;
1888 }
1889 
1890 
1891 
1898 function reindexList($list, $field, $autoPromote = true)
1899 {
1900  $result = array();
1901 
1902  foreach($list as $elt)
1903  {
1904  if (is_array($elt))
1905  {
1906  foreach($elt as $e)
1907  {
1908  if (array_key_exists($e->$field, $result))
1909  {
1910  if (!is_array($result[$e->$field]))
1911  {
1912  $result[$e->$field] = array($result[$e->$field]);
1913  }
1914  $result[$e->$field][] = $e;
1915  }
1916  else
1917  {
1918  $result[$e->$field] = $e;
1919  }
1920  }
1921  }
1922  else
1923  {
1924  if (array_key_exists($elt->$field, $result) && $autoPromote)
1925  {
1926  if (!is_array($result[$elt->$field]))
1927  {
1928  $result[$elt->$field] = array($result[$elt->$field]);
1929  }
1930  $result[$elt->$field][] = $elt;
1931  }
1932  else
1933  {
1934  $result[$elt->$field] = $elt;
1935  }
1936  }
1937  }
1938 
1939  return $result;
1940 }
1941 
1948 function regroupList($list, $field)
1949 {
1950  $result = array();
1951 
1952  foreach($list as $elt)
1953  {
1954  if (is_array($elt))
1955  {
1956  foreach ($elt as $e)
1957  {
1958  $result[$e->$field][] = $e;
1959  }
1960  }
1961  else
1962  {
1963  $result[$elt->$field][] = $elt;
1964  }
1965  }
1966 
1967  return $result;
1968 }
1969 
1981 function removeDuplicates($list, $field = "")
1982 {
1983  if (count($list) == 0) return $list;
1984 
1985  if ($field == "")
1986  {
1987  $field = $list[0]->primary_key;
1988  }
1989 
1990  $found = array();
1991  $filtered = array();
1992  foreach($list as $item)
1993  {
1994  if (!array_key_exists($item->$field, $found))
1995  {
1996  $filtered[] = $item;
1997  }
1998 
1999  $found[$item->$field] = true;
2000  }
2001 
2002  return $filtered;
2003 }
2004 
2010 {
2011  var $field;
2012 
2014  {
2015  $this->field = $field;
2016  }
2017 
2018  function compare($a, $b)
2019  {
2020  return ($a->get($this->field) < $b->get($this->field)) ? -1 : 1;
2021  }
2022 }
2023 
2030 function sortList(&$list, $field)
2031 {
2032  $cmp = new DataItemFieldComparator($field);
2033 
2034  usort($list, array($cmp, "compare"));
2035 
2036  return $list;
2037 }
2038 
2046 function updateSortOrder($class, $field = "sort_order", $params = null)
2047 {
2048  if (!$params) $params = $_GET;
2049  $obj = new $class;
2050  $pk = $obj->getPrimaryKey();
2051 
2052  $tx = new DataTransaction();
2053 
2054  try
2055  {
2056  foreach($params[$pk] as $id => $sort_order)
2057  {
2058  checkNumeric($id);
2059  checkNumeric($sort_order);
2060 
2061  $item = new $class();
2062  $item->joinTransaction($tx);
2063 
2064  $item->filter = new InclusionFilter($pk, $field);
2065 
2066  $item->load($id);
2067  $item->set($field, $sort_order);
2068  $item->save();
2069  }
2070 
2071  $tx->commit();
2072  }
2073  catch(Exception $e)
2074  {
2075  $tx->rollback();
2076  throw $e;
2077  }
2078 }
2079 
2080 function toXML($tag, $objects, $header = null)
2081 {
2082  global $config;
2083 
2084  if ($header === null)
2085  {
2086  $default_charset = $config["default_charset"];
2087  if (!$default_charset) $default_charset = "iso-8859-1";
2088  $header = "<?xml version=\"1.0\" encoding=\"{$default_charset}\"?>";
2089  }
2090 
2091  $xml = "$header\n<$tag>\n";
2092 
2093  foreach($objects as $obj)
2094  {
2095  $xml .= $obj->toXML(1);
2096  }
2097  $xml .= "</$tag>\n";
2098 
2099  return $xml;
2100 }
2101 
2102 function toJSON($items)
2103 {
2104  $out = array();
2105 
2106  foreach($items as $item)
2107  {
2108  $out[] = $item->toJSON();
2109  }
2110 
2111  return "[".implode(", ", $out)."]";
2112 }
2113 
2114 function toJSONGrouped($items)
2115 {
2116  $out = array();
2117 
2118  foreach($items as $key => $group)
2119  {
2120  $out[] = "\"$key\": ".toJSON($group);
2121  }
2122 
2123  return "{".implode(", ", $out)."}";
2124 }
2125 
2126 function toJSONIndexed($items)
2127 {
2128  $out = array();
2129 
2130  foreach($items as $key => $item)
2131  {
2132  $out[] = "\"$key\": ".$item->toJSON();
2133  }
2134 
2135  return "{".implode(", ", $out)."}";
2136 }
2137 
2138 function fromJSON($class, $json)
2139 {
2140  $data = json_decode($json);
2141 
2142  if (is_object($data))
2143  {
2144  $obj = new $class;
2145  $obj->copy($data);
2146  return $obj;
2147  }
2148  else if (is_array($data))
2149  {
2150  foreach($data as $datum)
2151  {
2152  $obj = new $class;
2153  $obj->copy($datum);
2154  $out[] = $obj;
2155  }
2156 
2157  return $out;
2158  }
2159 
2160  return null;
2161 }
2162 
2163 function displayFieldAsList($items, $field, $separator = ", ")
2164 {
2165  return formatItems($items, "{".$field."}", $separator);
2166 }
2167 
2176 function formatItems($items, $template, $separator = "")
2177 {
2178  $list = "";
2179  $first = true;
2180 
2181  foreach($items as $item)
2182  {
2183  if (!$item) continue;
2184  if (!$first) $list .= $separator;
2185  $list .= $item->format($template);
2186  $first = false;
2187  }
2188 
2189  return $list;
2190 }
2191 
2192 function extractItems($items, $indexFormat, $valueFormat)
2193 {
2194  $list = array();
2195  foreach($items as $item)
2196  {
2197  $list[$item->format($indexFormat)] = $item->format($valueFormat);
2198  }
2199 
2200  return $list;
2201 }
2202 
2209 function extractFieldValues($items, $field)
2210 {
2211  $out = array();
2212  foreach($items as $item)
2213  {
2214  $out[] = $item->get($field);
2215  }
2216  return $out;
2217 }
2218 
2226 function extractIndexedFieldValues($items, $field)
2227 {
2228  $out = array();
2229  foreach($items as $item)
2230  {
2231  $out[$item->get($item->getPrimaryKey())] = $item->get($field);
2232  }
2233 
2234  return $out;
2235 }
2236 
2243 function itemExists($class, $key)
2244 {
2245  $obj = new $class;
2246  if (!$obj instanceof DataItem)
2247  {
2248  return false;
2249  }
2250  $obj->set($obj->getPrimaryKey(), $key);
2251  return $obj->exists();
2252 }
2253 
2261 function findItem($items, $field, $value)
2262 {
2263  foreach($items as $item)
2264  {
2265  if ($item->get($field) == $value) return $item;
2266  }
2267 
2268  return null;
2269 }
2270 
2279 function findItemIndex($items, $field, $value)
2280 {
2281  $idx = 0;
2282 
2283  foreach($items as $item)
2284  {
2285  if ($item->get($field) == $value) return $idx;
2286  ++$idx;
2287  }
2288 
2289  return false;
2290 }
2291 
2292 function restoreHTML($text)
2293 {
2294  $v = str_replace( array("[_[OPENTAG]_]", "[_[CLOSETAG]_]", "[_[AMPERSAND]_]"), array("<", ">", "&"), $text);
2295  return $v;
2296 }
2297 
2304 function dumpCSV($class, $items, $filepath, $filter = null, $append = false)
2305 {
2306  $obj = new $class;
2307  $obj->filter = $filter;
2308 
2309  $fields = $obj->getFieldArray();
2310 
2311  if ($append)
2312  {
2313  $fp = fopen($filepath, "a");
2314  }
2315  else
2316  {
2317  $fp = fopen($filepath, "w");
2318  fputcsv($fp, $fields);
2319  }
2320 
2321  foreach($items as $item)
2322  {
2323  $vals = array();
2324  foreach($fields as $field)
2325  {
2326  $vals[] = $item->get($field);
2327  }
2328  fputcsv($fp, $vals);
2329  }
2330  fclose($fp);
2331 }?>
Abstract base class for all DataItem implementations.
getConnection()
Retrieves a connection to the database.
formatFieldValue($field, $template="")
quoteFieldValue($field, $type=null)
Returns the properly quoted value of the specified field.
getPrimaryKeyValue()
Retrieves the primary key value.
static invalidate($key)
Invalidates the specifed entry in the cache.
Definition: cache.inc:119
static get($key)
Retrieve the specified object from the cache.
Definition: cache.inc:88
static put($key, $obj, $ttl=0)
Store the specified object in the cache at the specified key.
Definition: cache.inc:106
static getConnection()
Retrieves a reference to the global database connection.
Simple field comparator to support sorting arrays of DataItems by the values in a specified field.
Definition: data_item.inc:2010
DataItem is the generic base class for database mapped classes.
Definition: data_item.inc:62
load($id)
Load the object with the specified primary key.
Definition: data_item.inc:561
getFields()
Retrieve the field type list for this object.
Definition: data_item.inc:333
fromXML($node)
Populates the object from the specified XML node.
Definition: data_item.inc:1485
getFilter()
Returns the filter set on this object.
Definition: data_item.inc:505
getHiddenFields()
Retrieves the list of hidden fields.
Definition: data_item.inc:249
fromPOST()
Automatically populate the object based on parameters in the $_POST collection.
Definition: data_item.inc:1062
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:1001
prettifyFieldName($field)
Definition: data_item.inc:1769
formatField($template)
Definition: data_item.inc:1643
cast($class)
Cast this object to another class.
Definition: data_item.inc:219
static $dataTypeRendererMap
Definition: data_item.inc:70
duplicate()
Persists a duplicate of the DataItem to the database under a new primary key.
Definition: data_item.inc:983
disablePrimaryKey()
Definition: data_item.inc:229
cacheLookup($id)
Populate the object from the local cache if the object is marked as "cacheLocal".
Definition: data_item.inc:1179
exists($constraint="")
Check whether the object exists in the database.
Definition: data_item.inc:665
compare($to)
Compare this object to another object.
Definition: data_item.inc:1127
DataItem()
Constructor.
Definition: data_item.inc:97
relateTo($target, $field="")
Link this object to the specified target by setting corresponding field to the value of the target's ...
Definition: data_item.inc:1791
cloneFrom($from)
Copies values from another object, field by field, excluding the primary key.
Definition: data_item.inc:1172
hasField($field)
Returns true if this DataItem contains a field with the specified name and that field is not excluded...
Definition: data_item.inc:434
old()
Retrieves the currently stored state of the DataItem from the database and returns it as a new object...
Definition: data_item.inc:601
getTransaction()
Retrieves the current DataTransaction.
Definition: data_item.inc:206
fireEvent($event)
Fires the specified event to all registered handlers.
Definition: data_item.inc:169
getRelated($class, $field="")
Returns a single item related by the specified foreign key.
Definition: data_item.inc:1210
deleteAll()
Delete all the rows in the database that correspond to this class.
Definition: data_item.inc:920
format($template="", $separator=", ")
Substitute values for field names in a string, with the fields formatted using their type's default f...
Definition: data_item.inc:1582
updateExplicit($updates, $params=null)
Executes an explicit update command against the database.
Definition: data_item.inc:775
joinTransaction($tx)
Join the DataItem to the specified DataTransaction.
Definition: data_item.inc:198
fromGET()
Automatically populate the object based on parameters in the $_GET collection.
Definition: data_item.inc:1042
copy($from)
Copies values from another object, field by field.
Definition: data_item.inc:1148
toXML($indent=0, $path=null)
Generates an XML representation of the object.
Definition: data_item.inc:1396
static $_eventMap
Definition: data_item.inc:63
queryValue($func)
Query the database to calculate an aggregate value.
Definition: data_item.inc:1346
getRelatedList($class, $field="", $orderBy="")
Returns a list of items that are related to this item.
Definition: data_item.inc:1260
tableExists()
Check if the table for this class exists in the database.
Definition: data_item.inc:944
getFieldList($alias="")
Returned a comma-separated list of the fields for this object (applying the assigned filter if there ...
Definition: data_item.inc:361
getPrimaryKeyList()
Retrieves a list of all the primary keys used for an object as an array.
Definition: data_item.inc:464
getFieldAnnotations()
Retrieve the list of field annotations.
Definition: data_item.inc:532
getType($field)
Retrieves the data type of the specified field.
Definition: data_item.inc:496
static registerEventHandler($class, $event, $handler)
Register an event handler for a specific event and DataItem class.
Definition: data_item.inc:151
populate($line, $alias=false)
Populates the object using the supplied associative array (field -> value).
Definition: data_item.inc:262
unpack()
The unpack() method is called after populating a DataItem.
Definition: data_item.inc:552
fromREQUEST()
Automatically populate the object based on parameters in either the $_GET or $_POST collection,...
Definition: data_item.inc:1084
getPrimaryKey()
Retrieves the primary key field name.
Definition: data_item.inc:455
insert()
Insert a new row in the database to store this object.
Definition: data_item.inc:812
setFilter($filter)
Sets the filter on this object.
Definition: data_item.inc:514
fromDataSet($params)
Automatically populate the object based on a custom set of parameters (such as a filtered $_POST coll...
Definition: data_item.inc:1102
pack()
The pack() method is called prior to persisting a DataItem to storage.
Definition: data_item.inc:543
crossReference($class, $xref, $orderBy="", $pkField="", $xrefField="")
Returns a list of items related to this item via a cross-reference table.
Definition: data_item.inc:1286
hasRelation($relation)
Returns true if this DataItem contains a relation with the specified name.
Definition: data_item.inc:447
getFieldArray()
Return an array of field names for this object filtered by any active filter.
Definition: data_item.inc:415
enablePrimaryKey()
Definition: data_item.inc:239
select()
Select the object from the database, based on the value of the primary key field.
Definition: data_item.inc:656
overrideFieldType($field, $type)
Override the type for the specified field.
Definition: data_item.inc:347
formatThroughRelation($template, $separator=", ")
Definition: data_item.inc:1713
save()
Store the object in the database.
Definition: data_item.inc:636
loadComposite()
Creates an outer CompositeDataItem from its base component.
Definition: data_item.inc:620
getFieldAliases()
Retrieve the list of field aliases.
Definition: data_item.inc:523
update()
Update the row in the database that corresponds to this object.
Definition: data_item.inc:707
The DataTransaction class wraps the underlying database's transaction model.
Definition: transaction.inc:48
Used to place a filter on the contents of a DataItem-derived object.
static create($class, $constraints="", $indexBy="")
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
startsWith($text, $start)
Tests whether a string starts with a given sub-string.
Definition: functions.inc:1470
itemExists($class, $key)
Utility method to test for the existence of a DataItem record in the database.
Definition: data_item.inc:2243
toJSONGrouped($items)
Definition: data_item.inc:2114
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:2046
const SerializeDirectRelations
reindexList($list, $field, $autoPromote=true)
Reindex an indexed or grouped query result by a different field.
Definition: data_item.inc:1898
regroupList($list, $field)
Regroup an indexed or grouped query result by a different field.
Definition: data_item.inc:1948
findItem($items, $field, $value)
Find the first item in the array that matches the supplied value for the specified field.
Definition: data_item.inc:2261
const SerializeRelations
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:2226
formatItems($items, $template, $separator="")
Format a list of DataItems using the specified templated.
Definition: data_item.inc:2176
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:2279
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:2304
const ProtectHTML
toXML($tag, $objects, $header=null)
Definition: data_item.inc:2080
toJSONIndexed($items)
Definition: data_item.inc:2126
extractFieldValues($items, $field)
Extract the field values for the specified field from a list of DataItems.
Definition: data_item.inc:2209
displayFieldAsList($items, $field, $separator=", ")
Definition: data_item.inc:2163
restoreHTML($text)
Definition: data_item.inc:2292
query($class)
Performs a query against the database, returning an array of DataItem objects of the specified class.
Definition: query.inc:373
removeDuplicates($list, $field="")
Remove duplicate DataItems from a list, based on the value of a field.
Definition: data_item.inc:1981
querySingle($class)
Performs a query against the database and returns a matching singleton object.
Definition: data_item.inc:1810
fromJSON($class, $json)
Definition: data_item.inc:2138
queryValue($class, $func)
Query the database to calculate an aggregate value.
Definition: data_item.inc:1842
toJSON($items)
Definition: data_item.inc:2102
extractItems($items, $indexFormat, $valueFormat)
Definition: data_item.inc:2192
sortList(&$list, $field)
Sorts an array of DataItems based on the values in the specified field.
Definition: data_item.inc:2030