CWIS Developer Documentation
MetadataField.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: MetadataField.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2012 Edward Almasy and Internet Scout
7 # http://scout.wisc.edu
8 #
9 
11 
12  # ---- PUBLIC INTERFACE --------------------------------------------------
13 
14  # Update methods for timestamp fields
15  const UPDATEMETHOD_NOAUTOUPDATE = "NoAutoUpdate";
16  const UPDATEMETHOD_ONRECORDCREATE = "OnRecordCreate";
17  const UPDATEMETHOD_BUTTON = "Button";
18  const UPDATEMETHOD_ONRECORDEDIT = "OnRecordEdit";
19  const UPDATEMETHOD_ONRECORDCHANGE = "OnRecordChange";
20 
21  # values for the *UserIsValue fields
22  const USERISVALUE_OR = -1;
23  const USERISVALUE_UNSET = 0;
24  const USERISVALUE_AND = 1;
25 
26  # get current error status of object
27  function Status() { return $this->ErrorStatus; }
28 
29  # get/set type of field as enumerated value
30  function Type($NewValue = DB_NOVALUE)
31  {
32  # if new value supplied
33  if (($NewValue != DB_NOVALUE)
34  && ($NewValue != MetadataField::$FieldTypePHPEnums[
35  $this->DBFields["FieldType"]]))
36  {
37  # update database fields and store new type
38  $this->ModifyField(NULL, $NewValue);
39  }
40 
41  # return type to caller
42  return MetadataField::$FieldTypePHPEnums[$this->DBFields["FieldType"]];
43  }
44 
45  # get type of field as type name (string)
46  function TypeAsName()
47  {
48  return $this->DBFields["FieldType"];
49  }
50 
51  # get displayable name for the field
52  # first tries to get label but uses field name if label isn't set
53  function GetDisplayName()
54  {
55  return strlen($this->Label()) ? $this->Label() : $this->Name();
56  }
57 
58  # get/set name of field
59  # once the name is set to a valid value, it cannot be changed
60  function Name($NewName = DB_NOVALUE)
61  {
62  # if new name specified
63  if ($NewName != DB_NOVALUE
64  && trim($NewName) != $this->DBFields["FieldName"])
65  {
66  # if field name is invalid
67  $NewName = trim($NewName);
68  if (!preg_match("/^[[:alnum:] \(\)]+$/", $NewName))
69  {
70  # set error status to indicate illegal name
71  $this->ErrorStatus = MetadataSchema::MDFSTAT_ILLEGALNAME;
72  }
73  else
74  {
75  # check for duplicate name
76  $DuplicateCount = $this->DB->Query("
77  SELECT COUNT(*) AS RecordCount FROM MetadataFields
78  WHERE FieldName = '".addslashes($NewName)."'",
79  "RecordCount");
80 
81  # if field name is duplicate
82  if ($DuplicateCount > 0)
83  {
84  # set error status to indicate duplicate name
85  $this->ErrorStatus = MetadataSchema::MDFSTAT_DUPLICATENAME;
86  }
87  else
88  {
89  # modify database declaration to reflect new field name
90  $this->ErrorStatus = MetadataSchema::MDFSTAT_OK;
91  $this->ModifyField($NewName);
92  }
93  }
94  }
95 
96  # return value to caller
97  return $this->DBFields["FieldName"];
98  }
99 
100  # get/set label of field
101  public function Label($NewLabel = DB_NOVALUE)
102  {
103  $ValidValueExp = '/^[[:alnum:] ]*$/';
104  $Value = $this->DBFields["Label"];
105 
106  # if a new label was specified
107  if ($NewLabel !== DB_NOVALUE && trim($NewLabel) != $Value)
108  {
109  $NewLabel = trim($NewLabel);
110 
111  # if field label is valid
112  if (preg_match($ValidValueExp, $NewLabel))
113  {
114  $this->UpdateValue("Label", $NewLabel);
115  $Value = $NewLabel;
116  }
117 
118  # the field label is invalid
119  else
120  {
121  $this->ErrorStatus = MetadataSchema::MDFSTAT_ILLEGALLABEL;
122  }
123  }
124 
125  return $Value;
126  }
127 
128  # get associative array (enumeration => string) containing field types we can convert to
130  {
131  # determine type list based on our type
132  switch ($this->Type())
133  {
139  $AllowedTypes = array(
141  MetadataSchema::MDFTYPE_PARAGRAPH => "Paragraph",
142  MetadataSchema::MDFTYPE_NUMBER => "Number",
145  );
146  break;
147 
150  $AllowedTypes = array(
151  MetadataSchema::MDFTYPE_CONTROLLEDNAME => "ControlledName",
152  MetadataSchema::MDFTYPE_OPTION => "Option",
153  );
154  break;
155 
157  $AllowedTypes = array(
160  );
161  break;
162 
164  $AllowedTypes = array(
166  MetadataSchema::MDFTYPE_IMAGE => "Still Image",
167  );
168  break;
169 
174  default:
175  $AllowedTypes = array();
176  break;
177  }
178 
179  # return type list to caller
180  return $AllowedTypes;
181  }
182 
183  # get/set whether item is temporary instance
184  function IsTempItem($NewSetting = NULL)
185  {
186  $ItemTableName = "MetadataFields";
187  $ItemIdFieldName = "FieldId";
188  $ItemFactoryObjectName = "MetadataSchema";
189  $ItemAssociationTables = array(
190  "FieldQualifierInts",
191  );
192  $ItemAssociationFieldName = "MetadataFieldId";
193 
194  # if new temp item setting supplied
195  if (!is_null($NewSetting))
196  {
197  # if caller requested to switch
198  if (($this->Id() < 0 && $NewSetting == FALSE)
199  || ($this->Id() >= 0 && $NewSetting == TRUE))
200  {
201  # if field name is invalid
202  if (strlen($this->NormalizeFieldNameForDB($this->Name())) < 1)
203  {
204  # set error status to indicate illegal name
205  $this->ErrorStatus = MetadataSchema::MDFSTAT_ILLEGALNAME;
206  }
207  else
208  {
209  # lock DB tables to prevent next ID from being grabbed
210  $DB = $this->DB;
211  $DB->Query("LOCK TABLES ".$ItemTableName." WRITE,".
212  "APSessions WRITE, APSessionData WRITE");
213 
214  # get next temp item ID
215  $OldItemId = $this->Id();
216  $Factory = new $ItemFactoryObjectName();
217  if ($NewSetting == TRUE)
218  {
219  $NewId = $Factory->GetNextTempItemId();
220  }
221  else
222  {
223  $NewId = $Factory->GetNextItemId();
224  }
225 
226  # change item ID
227  $DB->Query("UPDATE ".$ItemTableName." SET ".$ItemIdFieldName." = ".
228  $NewId. " WHERE ".$ItemIdFieldName." = ".$OldItemId);
229 
230  # release DB tables
231  $DB->Query("UNLOCK TABLES");
232 
233  # change associations
234  foreach ($ItemAssociationTables as $TableName)
235  {
236  $DB->Query("UPDATE ".$TableName." SET ".$ItemAssociationFieldName." = ".
237  $NewId. " WHERE ".$ItemAssociationFieldName." = ".$OldItemId);
238  }
239 
240  # if changing item from temp to non-temp
241  if ($NewSetting == FALSE)
242  {
243  # add any needed database fields and/or entries
244  $this->AddDatabaseFields();
245 
246  # set field order values for new field
247  try
248  {
251 
252  $DisplayOrder->AppendItem($NewId, "MetadataField");
253  $EditOrder->AppendItem($NewId, "MetadataField");
254  } catch (Exception $Exception) {}
255  }
256 
257  # update metadata field id
258  $this->DBFields["FieldId"] = $NewId;
259  }
260  }
261  }
262 
263  # report to caller whether we are a temp item
264  return ($this->Id() < 0) ? TRUE : FALSE;
265  }
266 
267  # get field attributes
268  function Id() { return $this->DBFields["FieldId"]; }
269  function DBFieldName() { return $this->DBFields["DBFieldName"]; }
270 
271  # get/set field attributes
272  function Description($NewValue = DB_NOVALUE)
273  { return $this->UpdateValue("Description", $NewValue); }
274  function Instructions($NewValue = DB_NOVALUE)
275  { return $this->UpdateValue("Instructions", $NewValue); }
276  function Owner($NewValue = DB_NOVALUE)
277  { return $this->UpdateValue("Owner", $NewValue); }
278  function RequiredBySPT($NewValue = DB_NOVALUE)
279  { return $this->UpdateBoolValue("RequiredBySPT", $NewValue); }
280  function Enabled($NewValue = DB_NOVALUE)
281  { return $this->UpdateBoolValue("Enabled", $NewValue); }
282  function Optional($NewValue = DB_NOVALUE)
283  { return $this->UpdateBoolValue("Optional", $NewValue); }
284  function Editable($NewValue = DB_NOVALUE)
285  { return $this->UpdateBoolValue("Editable", $NewValue); }
286  function Viewable($NewValue = DB_NOVALUE)
287  { return $this->UpdateBoolValue("Viewable", $NewValue); }
288  function AllowMultiple($NewValue = DB_NOVALUE)
289  { return $this->UpdateBoolValue("AllowMultiple", $NewValue); }
290  function IncludeInKeywordSearch($NewValue = DB_NOVALUE)
291  { return $this->UpdateBoolValue("IncludeInKeywordSearch", $NewValue); }
292  function IncludeInAdvancedSearch($NewValue = DB_NOVALUE)
293  { return $this->UpdateBoolValue("IncludeInAdvancedSearch", $NewValue); }
294  function IncludeInSortOptions($NewValue = DB_NOVALUE)
295  { return $this->UpdateBoolValue("IncludeInSortOptions", $NewValue); }
296  function IncludeInRecommender($NewValue = DB_NOVALUE)
297  { return $this->UpdateBoolValue("IncludeInRecommender", $NewValue); }
298  function TextFieldSize($NewValue = DB_NOVALUE)
299  { return $this->UpdateIntValue("TextFieldSize", $NewValue); }
300  function MaxLength($NewValue = DB_NOVALUE)
301  { return $this->UpdateIntValue("MaxLength", $NewValue); }
302  function ParagraphRows($NewValue = DB_NOVALUE)
303  { return $this->UpdateIntValue("ParagraphRows", $NewValue); }
304  function ParagraphCols($NewValue = DB_NOVALUE)
305  { return $this->UpdateIntValue("ParagraphCols", $NewValue); }
306  function MinValue($NewValue = DB_NOVALUE)
307  { return $this->UpdateFloatValue("MinValue", $NewValue); }
308  function MaxValue($NewValue = DB_NOVALUE)
309  { return $this->UpdateFloatValue("MaxValue", $NewValue); }
310  function FlagOnLabel($NewValue = DB_NOVALUE)
311  { return $this->UpdateValue("FlagOnLabel", $NewValue); }
312  function FlagOffLabel($NewValue = DB_NOVALUE)
313  { return $this->UpdateValue("FlagOffLabel", $NewValue); }
314  function DateFormat($NewValue = DB_NOVALUE)
315  { return $this->UpdateValue("DateFormat", $NewValue); }
316  function SearchWeight($NewValue = DB_NOVALUE)
317  { return $this->UpdateIntValue("SearchWeight", $NewValue); }
318  function RecommenderWeight($NewValue = DB_NOVALUE)
319  { return $this->UpdateIntValue("RecommenderWeight", $NewValue); }
320  function MaxHeight($NewValue = DB_NOVALUE)
321  { return $this->UpdateIntValue("MaxHeight", $NewValue); }
322  function MaxWidth($NewValue = DB_NOVALUE)
323  { return $this->UpdateIntValue("MaxWidth", $NewValue); }
324  function MaxPreviewHeight($NewValue = DB_NOVALUE)
325  { return $this->UpdateIntValue("MaxPreviewHeight", $NewValue); }
326  function MaxPreviewWidth($NewValue = DB_NOVALUE)
327  { return $this->UpdateIntValue("MaxPreviewWidth", $NewValue); }
328  function MaxThumbnailHeight($NewValue = DB_NOVALUE)
329  { return $this->UpdateIntValue("MaxThumbnailHeight", $NewValue); }
330  function MaxThumbnailWidth($NewValue = DB_NOVALUE)
331  { return $this->UpdateIntValue("MaxThumbnailWidth", $NewValue); }
332  function DefaultAltText($NewValue = DB_NOVALUE)
333  { return $this->UpdateValue("DefaultAltText", $NewValue); }
334  function UsesQualifiers($NewValue = DB_NOVALUE)
335  { return $this->UpdateBoolValue("UsesQualifiers", $NewValue); }
336  function ShowQualifiers($NewValue = DB_NOVALUE)
337  { return $this->UpdateBoolValue("ShowQualifiers", $NewValue); }
338  function DefaultQualifier($NewValue = DB_NOVALUE)
339  { return $this->UpdateValue("DefaultQualifier", $NewValue); }
340  function AllowHTML($NewValue = DB_NOVALUE)
341  { return $this->UpdateBoolValue("AllowHTML", $NewValue); }
342  function UseWysiwygEditor($NewValue = DB_NOVALUE)
343  { return $this->UpdateBoolValue("UseWysiwygEditor", $NewValue); }
344  function UseForOaiSets($NewValue = DB_NOVALUE)
345  { return $this->UpdateBoolValue("UseForOaiSets", $NewValue); }
346  function NumAjaxResults($NewValue = DB_NOVALUE)
347  { return $this->UpdateIntValue("NumAjaxResults", $NewValue); }
348  function ViewingPrivilege($NewValue = DB_NOVALUE)
349  { return $this->UpdateConstValue("ViewingPrivilege", $NewValue); }
350  function AuthoringPrivilege($NewValue = DB_NOVALUE)
351  { return $this->UpdateConstValue("AuthoringPrivilege", $NewValue); }
352  function EditingPrivilege($NewValue = DB_NOVALUE)
353  { return $this->UpdateConstValue("EditingPrivilege", $NewValue); }
354  function ImagePreviewPrivilege($NewValue = DB_NOVALUE)
355  { return $this->UpdateConstValue("ImagePreviewPrivilege", $NewValue); }
356  function TreeBrowsingPrivilege($NewValue = DB_NOVALUE)
357  { return $this->UpdateConstValue("TreeBrowsingPrivilege", $NewValue); }
358  function EnableOnOwnerReturn($NewValue = DB_NOVALUE)
359  { return $this->UpdateBoolValue("EnableOnOwnerReturn", $NewValue); }
360  function ViewingUserIsValue($NewValue = DB_NOVALUE)
361  { return $this->UpdateConstValue("ViewingUserIsValue", $NewValue, "MetadataField"); }
362  function AuthoringUserIsValue($NewValue = DB_NOVALUE)
363  { return $this->UpdateConstValue("AuthoringUserIsValue", $NewValue, "MetadataField"); }
364  function EditingUserIsValue($NewValue = DB_NOVALUE)
365  { return $this->UpdateConstValue("EditingUserIsValue", $NewValue, "MetadataField"); }
366  function ViewingUserValue($NewValue = DB_NOVALUE)
367  { return $this->UpdateIntValue("ViewingUserValue", $NewValue, "MetadataField"); }
368  function AuthoringUserValue($NewValue = DB_NOVALUE)
369  { return $this->UpdateIntValue("AuthoringUserValue", $NewValue, "MetadataField"); }
370  function EditingUserValue($NewValue = DB_NOVALUE)
371  { return $this->UpdateIntValue("EditingUserValue", $NewValue, "MetadataField"); }
372 
373  function UserPrivilegeRestrictions($NewValue = DB_NOVALUE)
374  {
375  # new value
376  if ($NewValue != DB_NOVALUE)
377  {
378  $NewValue = serialize((array) $NewValue);
379  }
380 
381  $Value = $this->UpdateValue("UserPrivilegeRestrictions", $NewValue);
382 
383  # value set
384  if (strlen($Value))
385  {
386  $Value = (array) unserialize($Value);
387  }
388 
389  # no value set, set it to an empty array
390  else
391  {
392  $Value = $this->UserPrivilegeRestrictions(array());
393  }
394 
395  return $Value;
396  }
397 
398  function PointPrecision($NewValue = DB_NOVALUE)
399  {
400  if ($NewValue !== DB_NOVALUE && $this->Id() >= 0
401  && $this->Type() == MetadataSchema::MDFTYPE_POINT)
402  {
403  $OldValue = $this->UpdateValue("PointPrecision", DB_NOVALUE);
404 
405  if ($NewValue != $OldValue)
406  {
407  $Decimals = $this->UpdateValue("PointDecimalDigits", DB_NOVALUE);
408  $TotalDigits = $NewValue + $Decimals;
409 
410  $this->DB->Query("ALTER TABLE Resources MODIFY COLUMN "
411  ."`".$this->DBFields["DBFieldName"]."X` "
412  ."DECIMAL(".$TotalDigits.",".$Decimals.")");
413  $this->DB->Query("ALTER TABLE Resources MODIFY COLUMN "
414  ."`".$this->DBFields["DBFieldName"]."Y` "
415  ."DECIMAL(".$TotalDigits.",".$Decimals.")");
416  }
417  }
418 
419  return $this->UpdateValue("PointPrecision", $NewValue);
420  }
421 
422  function PointDecimalDigits($NewValue = DB_NOVALUE)
423  {
424  if ($NewValue !== DB_NOVALUE && $this->Id() >= 0
425  && $this->Type() == MetadataSchema::MDFTYPE_POINT)
426  {
427  $OldValue = $this->UpdateValue("PointDecimalDigits", DB_NOVALUE);
428 
429  if ($NewValue != $OldValue)
430  {
431  $Precision = $this->UpdateValue("PointPrecision", DB_NOVALUE);
432 
433  $TotalDigits = $NewValue + $Precision;
434 
435  $this->DB->Query("ALTER TABLE Resources MODIFY COLUMN "
436  ."`".$this->DBFields["DBFieldName"]."X` "
437  ."DECIMAL(".$TotalDigits.",".$NewValue.")");
438  $this->DB->Query("ALTER TABLE Resources MODIFY COLUMN "
439  ."`".$this->DBFields["DBFieldName"]."Y` "
440  ."DECIMAL(".$TotalDigits.",".$NewValue.")");
441  }
442  }
443 
444  return $this->UpdateValue("PointDecimalDigits", $NewValue);
445  }
446 
447  function DefaultValue($NewValue = DB_NOVALUE)
448  {
449  if ($this->Type() == MetadataSchema::MDFTYPE_POINT)
450  {
451  # valid value given
452  if ($NewValue !== DB_NOVALUE &&
453  isset($NewValue["X"]) && isset($NewValue["Y"]))
454  {
455  $NewValue = $NewValue["X"].",".$NewValue["Y"];
456  }
457 
458  # invalid value given
459  else
460  {
461  $NewValue = DB_NOVALUE;
462  }
463 
464  $Value = $this->UpdateValue("DefaultValue", $NewValue);
465 
466  if (is_array($Value))
467  {
468  $tmp = explode(",", $Value);
469 
470  if (count($tmp)==2)
471  {
472  return array("X" => $tmp[0], "Y" => $tmp[1]);
473  }
474  }
475 
476  return array("X" => NULL, "Y" => NULL);
477  }
478 
479  else if ($this->Type() == MetadataSchema::MDFTYPE_OPTION)
480  {
481  # multiple default values to set
482  if (is_array($NewValue))
483  {
484  # empty array
485  if (count($NewValue) == 0)
486  {
487  $NewValue = NULL;
488  }
489 
490  # multiple defaults are allowed
491  else if ($this->AllowMultiple())
492  {
493  $NewValue = serialize($NewValue);
494  }
495 
496  # only one default is allowed so get the first one
497  else
498  {
499  $NewValue = array_shift($NewValue);
500  }
501  }
502 
503  $Result = $this->UpdateValue("DefaultValue", $NewValue);
504 
505  return empty($Result) || is_numeric($Result) ?
506  $Result : unserialize($Result);
507  }
508 
509  return $this->UpdateValue("DefaultValue", $NewValue);
510  }
511 
517  function UpdateMethod($NewValue = DB_NOVALUE)
518  {
519  return $this->UpdateValue("UpdateMethod", $NewValue);
520  }
521 
522  # get possible values (only meaningful for Trees, Controlled Names, Options,
523  # Flags, and Users)
524  # (index for returned array is IDs for values)
525  function GetPossibleValues($MaxNumberOfValues = NULL, $Offset=0)
526  {
527  # retrieve values based on field type
528  switch ($this->Type())
529  {
531  $QueryString = "SELECT ClassificationId, ClassificationName"
532  ." FROM Classifications WHERE FieldId = ".$this->Id()
533  ." ORDER BY ClassificationName";
534  if ($MaxNumberOfValues)
535  {
536  $QueryString .= " LIMIT ".intval($MaxNumberOfValues)." OFFSET "
537  .intval($Offset);
538  }
539  $this->DB->Query($QueryString);
540  $PossibleValues = $this->DB->FetchColumn(
541  "ClassificationName", "ClassificationId");
542  break;
543 
546  $QueryString = "SELECT ControlledNameId, ControlledName"
547  ." FROM ControlledNames WHERE FieldId = ".$this->Id()
548  ." ORDER BY ControlledName";
549  if ($MaxNumberOfValues)
550  {
551  $QueryString .= " LIMIT ".intval($MaxNumberOfValues)." OFFSET "
552  .intval($Offset);
553  }
554  $this->DB->Query($QueryString);
555  $PossibleValues = $this->DB->FetchColumn(
556  "ControlledName", "ControlledNameId");
557  break;
558 
560  $PossibleValues[0] = $this->FlagOffLabel();
561  $PossibleValues[1] = $this->FlagOnLabel();
562  break;
563 
565  $UserFactory = new UserFactory($this->DB);
566  $Restrictions = $this->UserPrivilegeRestrictions();
567  $PossibleValues = array();
568 
569  if (count($Restrictions))
570  {
571  $PossibleValues = call_user_func_array(
572  array($UserFactory, "GetUsersWithPrivileges"),
573  $Restrictions);
574  }
575 
576  else
577  {
578  $Users = $UserFactory->GetMatchingUsers(".*.");
579 
580  foreach ($Users as $Id => $Data)
581  {
582  $PossibleValues[$Id] = $Data["UserName"];
583  }
584  }
585 
586  break;
587 
588  default:
589  # for everything else return an empty array
590  $PossibleValues = array();
591  break;
592  }
593 
594  # return array of possible values to caller
595  return $PossibleValues;
596  }
597 
598  # get count of possible values (only meaningful for Trees, Controlled Names,
599  # Options, and Users)
601  {
602  # retrieve values based on field type
603  switch ($this->Type())
604  {
606  $Count = $this->DB->Query("SELECT count(*) AS ValueCount"
607  ." FROM Classifications WHERE FieldId = ".$this->Id(),
608  "ValueCount");
609  break;
610 
613  $Count = $this->DB->Query("SELECT count(*) AS ValueCount"
614  ." FROM ControlledNames WHERE FieldId = ".$this->Id(),
615  "ValueCount");
616  break;
617 
619  $Count = 2;
620  break;
621 
623  $Count = count($this->GetPossibleValues());
624  break;
625 
626  default:
627  # for everything else return an empty array
628  $Count = 0;
629  break;
630  }
631 
632  # return count of possible values to caller
633  return $Count;
634  }
635 
636  # get ID for specified value (only meaningful for Trees / Controlled Names / Options)
637  # (returns NULL if value not found)
638  function GetIdForValue($Value)
639  {
640  # retrieve ID based on field type
641  switch ($this->Type())
642  {
644  $Id = $this->DB->Query("SELECT ClassificationId FROM Classifications"
645  ." WHERE ClassificationName = '".addslashes($Value)."'"
646  ." AND FieldId = ".$this->Id(),
647  "ClassificationId");
648  break;
649 
652  $Id = $this->DB->Query("SELECT ControlledNameId FROM ControlledNames"
653  ." WHERE ControlledName = '".addslashes($Value)."'"
654  ." AND FieldId = ".$this->Id(),
655  "ControlledNameId");
656  break;
657 
658  default:
659  # for everything else return NULL
660  $Id = NULL;
661  break;
662  }
663 
664  # return ID for value to caller
665  return $Id;
666  }
667 
668  # get value for specified ID (only meaningful for Trees / Controlled Names / Options)
669  # (returns NULL if ID not found)
670  function GetValueForId($Id)
671  {
672  # retrieve ID based on field type
673  switch ($this->Type())
674  {
676  $Value = $this->DB->Query("SELECT ClassificationName FROM Classifications"
677  ." WHERE ClassificationId = '".intval($Id)."'"
678  ." AND FieldId = ".$this->Id(),
679  "ClassificationName");
680  break;
681 
684  $Value = $this->DB->Query("SELECT ControlledName FROM ControlledNames"
685  ." WHERE ControlledNameId = '".intval($Id)."'"
686  ." AND FieldId = ".$this->Id(),
687  "ControlledName");
688  break;
689 
690  default:
691  # for everything else return NULL
692  $Value = NULL;
693  break;
694  }
695 
696  # return ID for value to caller
697  return $Value;
698  }
699 
710  function ValueUseCount($Value)
711  {
712  # retrieve ID if object passed in
713  if (is_object($Value) && method_exists($Value, "Id"))
714  {
715  $Value = $Value->Id();
716  }
717 
718  # check value based on field type
719  $DBFieldName = $this->DBFields["DBFieldName"];
720  switch ($this->Type())
721  {
731  $UseCount = $this->DB->Query("SELECT COUNT(*) AS UseCount"
732  ." FROM Resources"
733  ." WHERE `".$DBFieldName."` = '".addslashes($Value)."'",
734  "UseCount");
735  break;
736 
738  $UseCount = $this->DB->Query("SELECT COUNT(*) AS UseCount"
739  ." FROM ResourceClassInts"
740  ." WHERE ClassificationId = ".intval($Value),
741  "UseCount");
742  break;
743 
746  $UseCount = $this->DB->Query("SELECT COUNT(*) AS UseCount"
747  ." FROM ResourceNameInts"
748  ." WHERE ControlledNameId = ".intval($Value),
749  "UseCount");
750  break;
751 
753  $UseCount = $this->DB->Query("SELECT COUNT(*) AS UseCount"
754  ." FROM Resources"
755  ." WHERE `".$DBFieldName."X` = '".$Value["X"]."'"
756  ." AND `".$DBFieldName."Y` = '".$Value["Y"]."'",
757  "UseCount");
758  break;
759 
760  default:
761  throw new Exception(__CLASS__."::".__METHOD__."() called for"
762  ." unsupported field type (".$this->Type().").");
763  break;
764  }
765 
766  # report use count to caller
767  return $UseCount;
768  }
769 
770  # get/set whether field uses item-level qualifiers
771  function HasItemLevelQualifiers($NewValue = DB_NOVALUE)
772  {
773  # if value provided different from present value
774  if (($NewValue != DB_NOVALUE)
775  && ($NewValue != $this->DBFields["HasItemLevelQualifiers"]))
776  {
777  # check if qualifier column currently exists
778  $QualColName = $this->DBFieldName()."Qualifier";
779  $QualColExists = $this->DB->FieldExists("Resources", $QualColName);
780 
781  # if new value indicates qualifiers should now be used
782  if ($NewValue == TRUE)
783  {
784  # if qualifier column does not exist in DB for this field
785  if ($QualColExists == FALSE)
786  {
787  # add qualifier column in DB for this field
788  $this->DB->Query("ALTER TABLE Resources ADD COLUMN `"
789  .$QualColName."` INT");
790  }
791  }
792  else
793  {
794  # if qualifier column exists in DB for this field
795  if ($QualColExists == TRUE)
796  {
797  # remove qualifier column from DB for this field
798  $this->DB->Query("ALTER TABLE Resources DROP COLUMN `"
799  .$QualColName."`");
800  }
801  }
802  }
803 
804  return $this->UpdateValue("HasItemLevelQualifiers", $NewValue);
805  }
806 
807  # get list of qualifiers associated with field
809  {
810  # start with empty list
811  $List = array();
812 
813  # for each associated qualifier
814  $this->DB->Query("SELECT QualifierId FROM FieldQualifierInts"
815  ." WHERE MetadataFieldId = ".$this->DBFields["FieldId"]);
816  while ($Record = $this->DB->FetchRow())
817  {
818  # load qualifier object
819  $Qual = new Qualifier($Record["QualifierId"]);
820 
821  # add qualifier ID and name to list
822  $List[$Qual->Id()] = $Qual->Name();
823  }
824 
825  # return list to caller
826  return $List;
827  }
828 
829  # get list of qualifiers not associated with field
831  {
832  # grab list of associated qualifiers
833  $AssociatedQualifiers = $this->AssociatedQualifierList();
834 
835  # get list of all qualifiers
836  $QFactory = new QualifierFactory();
837  $AllQualifiers = $QFactory->QualifierList();
838 
839  # return list of unassociated qualifiers
840  return array_diff($AllQualifiers, $AssociatedQualifiers);
841  }
842 
843  # add qualifier association
844  function AssociateWithQualifier($QualifierIdOrObject)
845  {
846  # if qualifier object passed in
847  if (is_object($QualifierIdOrObject))
848  {
849  # grab qualifier ID from object
850  $QualifierIdOrObject = $QualifierIdOrObject->Id();
851  }
852 
853  # if not already associated
854  $RecordCount = $this->DB->Query(
855  "SELECT COUNT(*) AS RecordCount FROM FieldQualifierInts"
856  ." WHERE QualifierId = ".$QualifierIdOrObject
857  ." AND MetadataFieldId = ".$this->Id(), "RecordCount");
858  if ($RecordCount < 1)
859  {
860  # associate field with qualifier
861  $this->DB->Query("INSERT INTO FieldQualifierInts SET"
862  ." QualifierId = ".$QualifierIdOrObject.","
863  ." MetadataFieldId = ".$this->Id());
864  }
865  }
866 
867  # delete qualifier association
868  function UnassociateWithQualifier($QualifierIdOrObject)
869  {
870  # if qualifier object passed in
871  if (is_object($QualifierIdOrObject))
872  {
873  # grab qualifier ID from object
874  $QualifierIdOrObject = $QualifierIdOrObject->Id();
875  }
876 
877  # delete intersection record from database
878  $this->DB->Query("DELETE FROM FieldQualifierInts WHERE QualifierId = "
879  .$QualifierIdOrObject." AND MetadataFieldId = ".
880  $this->Id());
881  }
882 
883  # retrieve item factory object for this field
884  function GetFactory()
885  {
886  switch ($this->Type())
887  {
889  $Factory = new ClassificationFactory($this->Id());
890  break;
891 
894  $Factory = new ControlledNameFactory($this->Id());
895  break;
896 
897  default:
898  $Factory = NULL;
899  break;
900  }
901 
902  return $Factory;
903  }
904 
905 
906  # ---- PRIVATE INTERFACE -------------------------------------------------
907 
908  private $DB;
909  private $DBFields;
910  private $ErrorStatus;
911 
915  public static $FieldTypeHumanEnums = array(
917  MetadataSchema::MDFTYPE_PARAGRAPH => "Paragraph",
918  MetadataSchema::MDFTYPE_NUMBER => "Number",
920  MetadataSchema::MDFTYPE_TIMESTAMP => "Timestamp",
923  MetadataSchema::MDFTYPE_CONTROLLEDNAME => "Controlled Name",
924  MetadataSchema::MDFTYPE_OPTION => "Option",
929  MetadataSchema::MDFTYPE_POINT => "Point");
930 
931  # field type DB/PHP enum translations
932  public static $FieldTypeDBEnums = array(
934  MetadataSchema::MDFTYPE_PARAGRAPH => "Paragraph",
935  MetadataSchema::MDFTYPE_NUMBER => "Number",
937  MetadataSchema::MDFTYPE_TIMESTAMP => "TimeStamp",
940  MetadataSchema::MDFTYPE_CONTROLLEDNAME => "ControlledName",
941  MetadataSchema::MDFTYPE_OPTION => "Option",
943  MetadataSchema::MDFTYPE_IMAGE => "Still Image",
947  );
948  public static $FieldTypeDBAllowedEnums = array(
950  MetadataSchema::MDFTYPE_PARAGRAPH => "Paragraph",
951  MetadataSchema::MDFTYPE_NUMBER => "Number",
953  MetadataSchema::MDFTYPE_TIMESTAMP => "TimeStamp",
956  MetadataSchema::MDFTYPE_CONTROLLEDNAME => "ControlledName",
957  MetadataSchema::MDFTYPE_OPTION => "Option",
959  MetadataSchema::MDFTYPE_IMAGE => "Still Image",
963  );
964  public static $FieldTypePHPEnums = array(
966  "Paragraph" => MetadataSchema::MDFTYPE_PARAGRAPH,
967  "Number" => MetadataSchema::MDFTYPE_NUMBER,
969  "TimeStamp" => MetadataSchema::MDFTYPE_TIMESTAMP,
972  "ControlledName" => MetadataSchema::MDFTYPE_CONTROLLEDNAME,
973  "Option" => MetadataSchema::MDFTYPE_OPTION,
975  "Still Image" => MetadataSchema::MDFTYPE_IMAGE,
979  );
980 
981  public static $UpdateTypes = array(
982  MetadataField::UPDATEMETHOD_NOAUTOUPDATE => "Do not update automatically",
983  MetadataField::UPDATEMETHOD_ONRECORDCREATE => "Update on record creation",
984  MetadataField::UPDATEMETHOD_BUTTON => "Provide an update button",
985  MetadataField::UPDATEMETHOD_ONRECORDEDIT => "Update when record is edited",
986  MetadataField::UPDATEMETHOD_ONRECORDCHANGE => "Update when record is changed"
987  );
988 
989 
990  # object constructor (only for use by MetadataSchema object)
991  function MetadataField($FieldId, $FieldName = NULL, $FieldType = NULL,
992  $Optional = TRUE, $DefaultValue = NULL)
993  {
994  # assume everything will be okay
995  $this->ErrorStatus = MetadataSchema::MDFSTAT_OK;
996 
997  # grab our own database handle
998  $this->DB = new Database();
999  $DB = $this->DB;
1000 
1001  # if field ID supplied
1002  if ($FieldId != NULL)
1003  {
1004  # look up field in database
1005  $DB->Query("SELECT * FROM MetadataFields WHERE FieldId = ".intval($FieldId));
1006  $Record = $DB->FetchRow();
1007  }
1008 
1009  # if no field ID supplied or if record not found in database
1010  if (($FieldId == NULL) || ($Record == NULL))
1011  {
1012  # error out if valid field type not supplied
1013  if (empty(MetadataField::$FieldTypeDBEnums[$FieldType]))
1014  {
1015  $this->ErrorStatus = MetadataSchema::MDFSTAT_FIELDDOESNOTEXIST;
1016  return;
1017  }
1018 
1019  # if field name supplied
1020  $FieldName = trim($FieldName);
1021  if (strlen($FieldName) > 0)
1022  {
1023  # error out if field name is duplicate
1024  $DuplicateCount = $DB->Query("
1025  SELECT COUNT(*) AS RecordCount FROM MetadataFields
1026  WHERE FieldName = '".addslashes($FieldName)."'
1027  OR Label = '".addslashes($FieldName)."'",
1028  "RecordCount");
1029 
1030  if ($DuplicateCount > 0)
1031  {
1032  $this->ErrorStatus = MetadataSchema::MDFSTAT_DUPLICATENAME;
1033  return;
1034  }
1035  }
1036 
1037  # grab current user ID
1038  global $G_User;
1039  $UserId = $G_User->Get("UserId");
1040 
1041  # lock DB tables and get next temporary field ID
1042  $Schema = new MetadataSchema();
1043  $DB->Query("LOCK TABLES MetadataFields WRITE");
1044  $FieldId = $Schema->GetNextTempItemId();
1045 
1046  # add field to MDF table in database
1047  $DB->Query("
1048  INSERT INTO MetadataFields
1049  (FieldId, FieldName, FieldType, LastModifiedById) VALUES
1050  (".intval($FieldId).",
1051  '".addslashes($FieldName)."',
1052  '".MetadataField::$FieldTypeDBEnums[$FieldType]."',
1053  '".$UserId."')");
1054 
1055  # release DB tables
1056  $DB->Query("UNLOCK TABLES");
1057 
1058  # re-read record from database
1059  $DB->Query("
1060  SELECT * FROM MetadataFields
1061  WHERE FieldId = ".intval($FieldId));
1062  $this->DBFields = $DB->FetchRow();
1063  $this->DBFields["DBFieldName"] =
1064  $this->NormalizeFieldNameForDB($this->DBFields["FieldName"]);
1065 
1066  # set field defaults
1067  $this->SetDefaults();
1068  $this->Optional($Optional ? TRUE : FALSE);
1069 
1070  # set the default value if specified since NULL is invalid for some
1071  # field types
1072  if (!is_null($DefaultValue))
1073  {
1074  $this->DefaultValue($DefaultValue);
1075  }
1076  }
1077  else
1078  {
1079  # save values locally
1080  $this->DBFields = $Record;
1081  $this->DBFields["DBFieldName"] =
1082  $this->NormalizeFieldNameForDB($Record["FieldName"]);
1083  }
1084  }
1085 
1089  public static $FixedDefaults = array(
1090  "Label" => NULL,
1091  "Description" => NULL,
1092  "Instructions" => NULL,
1093  "Enabled" => TRUE,
1094  "Optional" => TRUE,
1095  "Editable" => TRUE,
1096  "Viewable" => TRUE,
1097  "AllowMultiple" => FALSE,
1098  "IncludeInKeywordSearch" => FALSE,
1099  "IncludeInAdvancedSearch" => FALSE,
1100  "IncludeInSortOptions" => TRUE,
1101  "IncludeInRecommender" => FALSE,
1102  "ParagraphRows" => 4,
1103  "ParagraphCols" => 50,
1104  "MinValue" => 1,
1105  "FlagOnLabel" => "On",
1106  "FlagOffLabel" => "Off",
1107  "DateFormat" => NULL,
1108  "RecommenderWeight" => 1,
1109  "MaxHeight" => 500,
1110  "MaxWidth" => 500,
1111  "MaxPreviewHeight" => 100,
1112  "MaxPreviewWidth" => 100,
1113  "MaxThumbnailHeight" => 50,
1114  "MaxThumbnailWidth" => 50,
1115  "DefaultAltText" => NULL,
1116  "UsesQualifiers" => FALSE,
1117  "HasItemLevelQualifiers" => FALSE,
1118  "ShowQualifiers" => FALSE,
1119  "DefaultQualifier" => NULL,
1120  "AllowHTML" => FALSE,
1121  "UseWysiwygEditor" => FALSE,
1122  "UseForOaiSets" => FALSE,
1123  "NumAjaxResults" => 50,
1124  "ViewingPrivilege" => NULL,
1125  "AuthoringPrivilege" => PRIV_MYRESOURCEADMIN,
1126  "EditingPrivilege" => PRIV_RESOURCEADMIN,
1127  "ImagePreviewPrivilege" => NULL,
1128  "TreeBrowsingPrivilege" => NULL,
1129  "ViewingUserIsValue" => self::USERISVALUE_UNSET,
1130  "AuthoringUserIsValue" => self::USERISVALUE_UNSET,
1131  "EditingUserIsValue" => self::USERISVALUE_UNSET,
1132  "ViewingUserValue" => NULL,
1133  "AuthoringUserValue" => NULL,
1134  "EditingUserValue" => NULL,
1135  "PointPrecision" => 8,
1136  "PointDecimalDigits" => 5,
1137  "UserPrivilegeRestrictions" => array(),
1138  "UpdateMethod" => "NoAutoUpdate",
1139  # 9999 is the default max value because default number field length is 4
1140  "MaxValue" => 9999);
1141 
1145  public static $TypeBasedDefaults = array(
1147  "DefaultValue" => NULL,
1148  "SearchWeight" => 1,
1149  "TextFieldSize" => 50,
1150  "MaxLength" => 100),
1152  "DefaultValue" => NULL,
1153  "SearchWeight" => 1,
1154  "TextFieldSize" => 50,
1155  "MaxLength" => 100),
1157  "DefaultValue" => NULL,
1158  "SearchWeight" => 1,
1159  "TextFieldSize" => 4,
1160  "MaxLength" => 100),
1162  "DefaultValue" => NULL,
1163  "SearchWeight" => 1,
1164  "TextFieldSize" => 10,
1165  "MaxLength" => 100),
1167  "DefaultValue" => NULL,
1168  "SearchWeight" => 1,
1169  "TextFieldSize" => 50,
1170  "MaxLength" => 100),
1172  "DefaultValue" => NULL,
1173  "SearchWeight" => 1,
1174  "TextFieldSize" => 50,
1175  "MaxLength" => 100),
1177  "DefaultValue" => NULL,
1178  "SearchWeight" => 1,
1179  "TextFieldSize" => 50,
1180  "MaxLength" => 100),
1182  "DefaultValue" => NULL,
1183  "SearchWeight" => 3,
1184  "TextFieldSize" => 50,
1185  "MaxLength" => 100),
1187  "DefaultValue" => NULL,
1188  "SearchWeight" => 3,
1189  "TextFieldSize" => 50,
1190  "MaxLength" => 100),
1192  "DefaultValue" => NULL,
1193  "SearchWeight" => 1,
1194  "TextFieldSize" => 50,
1195  "MaxLength" => 100),
1197  "DefaultValue" => NULL,
1198  "SearchWeight" => 1,
1199  "TextFieldSize" => 50,
1200  "MaxLength" => 100),
1202  "DefaultValue" => NULL,
1203  "SearchWeight" => 1,
1204  "TextFieldSize" => 50,
1205  "MaxLength" => 100),
1206  MetadataSchema::MDFTYPE_URL => array(
1207  "DefaultValue" => NULL,
1208  "SearchWeight" => 1,
1209  "TextFieldSize" => 50,
1210  "MaxLength" => 255),
1212  "DefaultValue" => array("X" => NULL, "Y" => NULL),
1213  "SearchWeight" => 1,
1214  "TextFieldSize" => 10,
1215  "MaxLength" => 100));
1216 
1221  public function SetDefaults()
1222  {
1223  # set defaults that are the same for every field
1224  foreach (self::$FixedDefaults as $Key => $Value)
1225  {
1226  $this->$Key($Value);
1227  }
1228 
1229  # set defaults that depend on the type of the field
1230  foreach (self::$TypeBasedDefaults[$this->Type()] as $Key => $Value)
1231  {
1232  $this->$Key($Value);
1233  }
1234 
1235  # tweak the update method if dealing with the date of record creation
1236  if ($this->Name() == "Date Of Record Creation")
1237  {
1238  $this->UpdateMethod("OnRecordCreate");
1239  }
1240  }
1241 
1242  # remove field from database (only for use by MetadataSchema object)
1243  function Drop()
1244  {
1245  # clear other database entries as appropriate for field type
1246  $DB = $this->DB;
1247  $DBFieldName = $this->DBFields["DBFieldName"];
1248  switch (MetadataField::$FieldTypePHPEnums[$this->DBFields["FieldType"]])
1249  {
1258  # remove field from resources table
1259  if ($DB->FieldExists("Resources", $DBFieldName))
1260  {
1261  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."`");
1262  }
1263  break;
1264 
1266  if ($DB->FieldExists("Resources", $DBFieldName."X"))
1267  {
1268  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."X`");
1269  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."Y`");
1270  }
1271  break;
1272 
1274  # remove fields from resources table
1275  if ($DB->FieldExists("Resources", $DBFieldName."Begin"))
1276  {
1277  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."Begin`");
1278  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."End`");
1279  $DB->Query("ALTER TABLE Resources DROP COLUMN `".$DBFieldName."Precision`");
1280  }
1281  break;
1282 
1284  $DB->Query("SELECT ClassificationId FROM Classifications "
1285  ."WHERE FieldId = ".$this->Id());
1286  $TempDB = new Database();
1287  while ($ClassificationId = $DB->FetchField("ClassificationId"))
1288  {
1289  # remove any resource / name intersections
1290  $TempDB->Query("DELETE FROM ResourceClassInts WHERE "
1291  ."ClassificationId = ".$ClassificationId);
1292 
1293  # remove controlled name
1294  $TempDB->Query("DELETE FROM Classifications WHERE "
1295  ."ClassificationId = ".$ClassificationId);
1296  }
1297  break;
1298 
1301  $DB->Query("SELECT ControlledNameId FROM ControlledNames "
1302  ."WHERE FieldId = ".$this->Id());
1303  $TempDB = new Database();
1304  while ($ControlledNameId = $DB->FetchField("ControlledNameId"))
1305  {
1306  # remove any resource / name intersections
1307  $TempDB->Query("DELETE FROM ResourceNameInts WHERE "
1308  ."ControlledNameId = ".$ControlledNameId);
1309 
1310  # remove any variant names
1311  $TempDB->Query("DELETE FROM VariantNames WHERE "
1312  ."ControlledNameId = ".$ControlledNameId);
1313 
1314  # remove controlled name
1315  $TempDB->Query("DELETE FROM ControlledNames WHERE "
1316  ."ControlledNameId = ".$ControlledNameId);
1317  }
1318  break;
1319 
1321  # for each file associated with this field
1322  $DB->Query("SELECT FileId FROM Files WHERE FieldId = '".$this->Id()."'");
1323  while ($FileId = $DB->FetchRow())
1324  {
1325  # delete file
1326  $File = new File(intval($FileId));
1327  $File->Delete();
1328  }
1329  break;
1330  }
1331 
1332  # remove field from database
1333  $DB->Query("DELETE FROM MetadataFields "
1334  ."WHERE FieldId = '".$this->DBFields["FieldId"]."'");
1335 
1336  # remove any qualifier associations
1337  $DB->Query("DELETE FROM FieldQualifierInts WHERE MetadataFieldId = '"
1338  .$this->DBFields["FieldId"]."'");
1339 
1340  # remove the field from the display and edit order
1341  try
1342  {
1345 
1346  # remove it from the dispaly and edit oorder
1347  $DisplayOrder->RemoveItem($this->Id(), "MetadataField");
1348  $EditOrder->RemoveItem($this->Id(), "MetadataField");
1349 
1350  # remove field from any metadata field groups in the display order
1351  foreach ($DisplayOrder->GetItemIds() as $Item)
1352  {
1353  if ($Item["Type"] == "MetadataFieldGroup")
1354  {
1355  $Group = new MetadataFieldGroup($Item["ID"]);
1356  $Group->RemoveItem($this->Id(), "MetadataField");
1357  }
1358  }
1359 
1360  # remove field from any metadata field groups in the edit order
1361  foreach ($EditOrder->GetItemIds() as $Item)
1362  {
1363  if ($Item["Type"] == "MetadataFieldGroup")
1364  {
1365  $Group = new MetadataFieldGroup($Item["ID"]);
1366  $Group->RemoveItem($this->Id(), "MetadataField");
1367  }
1368  }
1369  } catch (Exception $Exception) {}
1370  }
1371 
1372  # modify any database fields
1373  private function ModifyField($NewName = NULL, $NewType = NULL)
1374  {
1375  # grab old DB field name
1376  $OldDBFieldName = $this->DBFields["DBFieldName"];
1377  $OldFieldType = NULL;
1378 
1379  # if new field name supplied
1380  if ($NewName != NULL)
1381  {
1382  # cache the old name for options and controllednames below
1383  $OldName = $this->DBFields["FieldName"];
1384 
1385  # store new name
1386  $this->UpdateValue("FieldName", $NewName);
1387 
1388  # determine new DB field name
1389  $NewDBFieldName = $this->NormalizeFieldNameForDB($NewName);
1390 
1391  # store new database field name
1392  $this->DBFields["DBFieldName"] = $NewDBFieldName;
1393  }
1394  else
1395  {
1396  # set new field name equal to old field name
1397  $NewDBFieldName = $OldDBFieldName;
1398  }
1399 
1400  # if new type supplied
1401  if ($NewType != NULL)
1402  {
1403  # grab old field type
1404  $OldFieldType = MetadataField::$FieldTypePHPEnums[$this->DBFields["FieldType"]];
1405 
1406  # store new field type
1407  $this->UpdateValue("FieldType", MetadataField::$FieldTypeDBEnums[$NewType]);
1408  }
1409 
1410  # if this is not a temporary field
1411  if ($this->Id() >= 0)
1412  {
1413  # modify field in DB as appropriate for field type
1414  $DB = $this->DB;
1415  $FieldType = MetadataField::$FieldTypePHPEnums[$this->DBFields["FieldType"]];
1416  switch ($FieldType)
1417  {
1421  # alter field declaration in Resources table
1422  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1423  .$OldDBFieldName."` `"
1424  .$NewDBFieldName."` TEXT "
1425  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1426  break;
1427 
1430  # alter field declaration in Resources table
1431  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1432  .$OldDBFieldName."` `"
1433  .$NewDBFieldName."` INT "
1434  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1435  break;
1436 
1438  $Precision = $this->UpdateValue("PointPrecision",
1439  DB_NOVALUE);
1440  $Digits = $this->UpdateValue("PointDecimalDigits",
1441  DB_NOVALUE);
1442  $DB->Query("ALTER TABLE Resources CHANGE COLUMN "
1443  ."`".$OldDBFieldName."X` "
1444  ."`".$NewDBFieldName."X`".
1445  " DECIMAL(".$Precision.",".$Digits.")");
1446  $DB->Query("ALTER TABLE Resources CHANGE COLUMN "
1447  ."`".$OldDBFieldName."Y` "
1448  ."`".$NewDBFieldName."Y`".
1449  " DECIMAL(".$Precision.",".$Digits.")");
1450  break;
1451 
1453  # if DB field name has changed
1454  if ($NewDBFieldName != $OldDBFieldName)
1455  {
1456  # alter field declaration in Resources table
1457  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1458  .$OldDBFieldName."` `"
1459  .$NewDBFieldName."` TEXT");
1460  }
1461  break;
1462 
1464  # if DB field name has changed
1465  if ($NewDBFieldName != $OldDBFieldName)
1466  {
1467  # alter field declaration in Resources table
1468  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1469  .$OldDBFieldName."` `"
1470  .$NewDBFieldName."` INT");
1471  }
1472  break;
1473 
1475  # alter field declaration in Resources table
1476  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1477  .$OldDBFieldName."` `"
1478  .$NewDBFieldName."` INT"
1479  ." DEFAULT ".intval($this->DefaultValue()));
1480 
1481  # set any unset values to default
1482  $DB->Query("UPDATE Resources SET `".$NewDBFieldName
1483  ."` = ".intval($this->DefaultValue())
1484  ." WHERE `".$NewDBFieldName."` IS NULL");
1485  break;
1486 
1488  # if new type supplied and new type is different from old
1489  if (($NewType != NULL) && ($NewType != $OldFieldType))
1490  {
1491  # if old type was time stamp
1492  if ($OldFieldType == MetadataSchema::MDFTYPE_TIMESTAMP)
1493  {
1494  # change time stamp field in resources table to begin date
1495  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1496  .$OldDBFieldName."` `"
1497  .$NewDBFieldName."Begin` DATE "
1498  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1499 
1500  # add end date and precision fields
1501  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$NewDBFieldName."End"
1502  ."` DATE");
1503  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$NewDBFieldName."Precision`"
1504  ." INT ".($Optional ? "" : "NOT NULL"));
1505 
1506  # set precision to reflect time stamp content
1507  $DB->Query("UPDATE Resources SET `".$NewDBFieldName."Precision` = "
1508  .(DATEPRE_BEGINYEAR|DATEPRE_BEGINMONTH|DATEPRE_BEGINDAY));
1509  }
1510  else
1511  {
1512  exit("<br>ERROR: Attempt to convert metadata field to date from type other than timestamp<br>\n");
1513  }
1514  }
1515  else
1516  {
1517  # change name of fields
1518  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1519  .$OldDBFieldName."Begin` `"
1520  .$NewDBFieldName."Begin` DATE "
1521  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1522  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1523  .$OldDBFieldName."End` `"
1524  .$NewDBFieldName."End` DATE "
1525  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1526  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1527  .$OldDBFieldName."Precision` `"
1528  .$NewDBFieldName."Precision` INT "
1529  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1530  }
1531  break;
1532 
1534  # if new type supplied and new type is different from old
1535  if (($NewType != NULL) && ($NewType != $OldFieldType))
1536  {
1537  # if old type was date
1538  if ($OldFieldType == MetadataSchema::MDFTYPE_DATE)
1539  {
1540  # change begin date field in resource table to time stamp
1541  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1542  .$OldDBFieldName."Begin` `"
1543  .$NewDBFieldName."` DATETIME "
1544  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1545 
1546  # drop end date and precision fields
1547  $DB->Query("ALTER TABLE Resources DROP COLUMN `"
1548  .$OldDBFieldName."End`");
1549  $DB->Query("ALTER TABLE Resources DROP COLUMN `"
1550  .$OldDBFieldName."Precision`");
1551  }
1552  else
1553  {
1554  exit("<br>ERROR: Attempt to convert metadata field to time stamp from type other than date<br>\n");
1555  }
1556  }
1557  else
1558  {
1559  # change name of field
1560  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1561  .$OldDBFieldName."` `"
1562  .$NewDBFieldName."` DATETIME "
1563  .($this->DBFields["Optional"] ? "" : "NOT NULL"));
1564  }
1565  break;
1566 
1570  break;
1571  }
1572 
1573  # if qualifier DB field exists
1574  if ($DB->FieldExists("Resources", $OldDBFieldName."Qualifier"))
1575  {
1576  # rename qualifier DB field
1577  $DB->Query("ALTER TABLE Resources CHANGE COLUMN `"
1578  .$OldDBFieldName."Qualifier` `"
1579  .$NewDBFieldName."Qualifier` INT ");
1580  }
1581  }
1582  }
1583 
1584  # convenience functions to supply parameters to Database->UpdateValue()
1585  private function UpdateValue($FieldName, $NewValue)
1586  {
1587  return $this->DB->UpdateValue("MetadataFields", $FieldName, $NewValue,
1588  "FieldId = ".intval($this->DBFields["FieldId"]),
1589  $this->DBFields);
1590  }
1591  private function UpdateIntValue($FieldName, $NewValue)
1592  {
1593  return $this->DB->UpdateIntValue("MetadataFields", $FieldName, $NewValue,
1594  "FieldId = ".intval($this->DBFields["FieldId"]),
1595  $this->DBFields);
1596  }
1597  private function UpdateFloatValue($FieldName, $NewValue)
1598  {
1599  return $this->DB->UpdateFloatValue("MetadataFields", $FieldName, $NewValue,
1600  "FieldId = ".intval($this->DBFields["FieldId"]),
1601  $this->DBFields);
1602  }
1603  private function UpdateBoolValue($FieldName, $NewValue)
1604  {
1605  $NewValue = $this->TranslateStringToConstants($NewValue);
1606  return $this->DB->UpdateIntValue("MetadataFields", $FieldName, $NewValue,
1607  "FieldId = ".intval($this->DBFields["FieldId"]),
1608  $this->DBFields);
1609  }
1610  private function UpdateConstValue($FieldName, $NewValue, $ClassName=NULL)
1611  {
1612  $NewValue = $this->TranslateStringToConstants($NewValue, $ClassName);
1613  return $this->DB->UpdateIntValue("MetadataFields", $FieldName, $NewValue,
1614  "FieldId = ".intval($this->DBFields["FieldId"]),
1615  $this->DBFields);
1616  }
1617 
1618  # normalize field name for use as database field name
1619  private function NormalizeFieldNameForDB($Name)
1620  {
1621  return preg_replace("/[^a-z0-9]/i", "", $Name);
1622  }
1623 
1624  # add any needed database fields and/or entries
1625  private function AddDatabaseFields()
1626  {
1627  # grab values for common use
1628  $DB = $this->DB;
1629  $FieldName = $this->Name();
1630  $DBFieldName = $this->DBFieldName();
1631  $Optional = $this->Optional();
1632  $DefaultValue = $this->DefaultValue();
1633 
1634  # set up field(s) based on field type
1635  switch ($this->Type())
1636  {
1640  # add field to resources table (if not already present)
1641  if (!$DB->FieldExists("Resources", $DBFieldName))
1642  {
1643  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName
1644  ."` TEXT ".($Optional ? "" : "NOT NULL"));
1645  }
1646 
1647  # if default value supplied
1648  if ($DefaultValue != NULL)
1649  {
1650  # set all existing records to default value
1651  $DB->Query("UPDATE Resources SET `"
1652  .$DBFieldName."` = '".addslashes($DefaultValue)."'");
1653  }
1654  break;
1655 
1657  # add field to resources table (if not already present)
1658  if (!$DB->FieldExists("Resources", $DBFieldName))
1659  {
1660  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName
1661  ."` INT ".($Optional ? "" : "NOT NULL"));
1662  }
1663 
1664  # if default value supplied
1665  if ($DefaultValue != NULL)
1666  {
1667  # set all existing records to default value
1668  $DB->Query("UPDATE Resources SET `"
1669  .$DBFieldName."` = '".addslashes($DefaultValue)."'");
1670  }
1671  break;
1672 
1674  if (!$DB->FieldExists("Resources", $DBFieldName."X"))
1675  {
1676  $Precision = $this->UpdateValue("PointPrecision",
1677  DB_NOVALUE);
1678  $Digits = $this->UpdateValue("PointDecimalDigits",
1679  DB_NOVALUE);
1680 
1681  $DB->Query("ALTER TABLE Resources ADD COLUMN `"
1682  .$DBFieldName."X`".
1683  " DECIMAL(".$Precision.",".$Digits.")");
1684  $DB->Query("ALTER TABLE Resources ADD COLUMN `"
1685  .$DBFieldName."Y`".
1686  " DECIMAL(".$Precision.",".$Digits.")");
1687  }
1688 
1689  break;
1691  # if field is not already present in database
1692  if (!$DB->FieldExists("Resources", $DBFieldName))
1693  {
1694  # add field to resources table
1695  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName
1696  ."` INT DEFAULT ".intval($DefaultValue));
1697 
1698  # set all existing records to default value
1699  $DB->Query("UPDATE Resources SET `"
1700  .$DBFieldName."` = ".intval($DefaultValue));
1701  }
1702  break;
1703 
1705  # add field to resources table (if not already present)
1706  if (!$DB->FieldExists("Resources", $DBFieldName))
1707  {
1708  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName
1709  ."` INT ".($Optional ? "" : "NOT NULL"));
1710  }
1711  break;
1712 
1714  # add fields to resources table (if not already present)
1715  if (!$DB->FieldExists("Resources", $DBFieldName))
1716  {
1717  $DB->Query("ALTER TABLE Resources ADD COLUMN `"
1718  .$DBFieldName."` TEXT");
1719  }
1720  break;
1721 
1723  # add fields to resources table (if not already present)
1724  if (!$DB->FieldExists("Resources", $DBFieldName))
1725  {
1726  $DB->Query("ALTER TABLE Resources ADD COLUMN `"
1727  .$DBFieldName."` INT");
1728  }
1729  break;
1730 
1732  # add fields to resources table (if not already present)
1733  if (!$DB->FieldExists("Resources", $DBFieldName."Begin"))
1734  {
1735  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName."Begin`"
1736  ." DATE ".($Optional ? "" : "NOT NULL"));
1737  }
1738  if (!$DB->FieldExists("Resources", $DBFieldName."End"))
1739  {
1740  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName."End`"
1741  ." DATE");
1742  }
1743  if (!$DB->FieldExists("Resources", $DBFieldName."Precision"))
1744  {
1745  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName."Precision`"
1746  ." INT ".($Optional ? "" : "NOT NULL"));
1747  }
1748  break;
1749 
1751  # add fields to resources table (if not already present)
1752  if (!$DB->FieldExists("Resources", $DBFieldName))
1753  {
1754  $DB->Query("ALTER TABLE Resources ADD COLUMN `".$DBFieldName
1755  ."` DATETIME ".($Optional ? "" : "NOT NULL"));
1756  }
1757  break;
1758 
1762  break;
1763 
1764  default:
1765  exit("<br>ERROR: Attempt to add database fields for illegal metadata field type<br>\n");
1766  break;
1767  }
1768  }
1769 
1777  private function TranslateStringToConstants($CString, $ClassName = NULL)
1778  {
1779  # if not a string return value unchanged to caller
1780  if (!is_string($CString) || ($CString === DB_NOVALUE))
1781  {
1782  $ReturnValue = $CString;
1783  }
1784  # handle booleans as a special case
1785  elseif (strtoupper(trim($CString)) == "TRUE")
1786  {
1787  $ReturnValue = TRUE;
1788  }
1789  elseif (strtoupper(trim($CString)) == "FALSE")
1790  {
1791  $ReturnValue = FALSE;
1792  }
1793  else
1794  {
1795  # assume no values will be found
1796  $ReturnValue = NULL;
1797 
1798  # split apart any ORed-together values
1799  $Values = explode("|", $CString);
1800 
1801  # for each value found
1802  foreach ($Values as $Value)
1803  {
1804  # trim off any extraneous whitespace
1805  $Value = trim($Value);
1806 
1807  # add class name prefix to constant name if requested
1808  if ($ClassName) { $Value = $ClassName."::".$Value; }
1809 
1810  # if value corresponds to a constant
1811  if (defined($Value))
1812  {
1813  # add constant to return value
1814  $ReturnValue = ($ReturnValue === NULL)
1815  ? constant($Value)
1816  : ($ReturnValue | constant($Value));
1817  }
1818  }
1819 
1820  # if no corresponding constants were found
1821  if ($ReturnValue === NULL)
1822  {
1823  # return original value to caller
1824  $ReturnValue = $CString;
1825  }
1826  }
1827 
1828  # return result to caller
1829  return $ReturnValue;
1830  }
1831 
1832 }