3 # FILE: MetadataSchema.php
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011 Edward Almasy and Internet Scout
7 # http://scout.wisc.edu
12 # ---- PUBLIC INTERFACE --------------------------------------------------
14 # types of field ordering
19 # metadata field types
20 # (must parallel MetadataFields.FieldType declaration in install/CreateTables.sql
21 # and MetadataField::$FieldTypeDBEnums declaration below)
52 # set up item factory base class
54 "MetadataField",
"MetadataFields",
"FieldId",
"FieldName");
56 # start with field info caching enabled
57 $this->CachingOn = TRUE;
60 # turn internal caching of field info on or off
63 $this->CachingOn = $NewValue;
66 # add new metadata field
67 function AddField($FieldName, $FieldType, $Optional = TRUE, $DefaultValue = NULL)
70 $Field =
new MetadataField(NULL, $FieldName, $FieldType, $Optional, $DefaultValue);
72 # save error code if create failed and return NULL
75 $this->ErrorStatus = $Field->Status();
79 # return new field to caller
94 # assume field addition will fail
95 $Field = self::MDFSTAT_ERROR;
97 # add XML prefixes if needed
99 if (!preg_match(
"/^<\?xml/i", $Xml))
101 if (!preg_match(
"/^<document>/i", $Xml))
103 $Xml =
"<document>".$Xml.
"</document>";
105 $Xml =
"<?xml version='1.0'?>".$Xml;
109 $XmlData = simplexml_load_string($Xml);
111 # if required values are present
112 if (is_object($XmlData)
113 && isset($XmlData->Name)
114 && isset($XmlData->Type)
115 && constant(
"MetadataSchema::".$XmlData->Type))
117 # create the metadata field
119 constant(
"MetadataSchema::".$XmlData->Type));
121 # if field creation failed
122 if ($Field->Status() !== self::MDFSTAT_OK)
124 # reset field value to error code
125 $Field = $Field->Status();
129 # for other field attributes
130 foreach ($XmlData as $MethodName => $Value)
132 # if they look valid and have not already been set
133 if (method_exists($Field, $MethodName)
134 && ($MethodName !=
"Name")
135 && ($MethodName !=
"Type"))
137 # condense down any extraneous whitespace
138 $Value = preg_replace(
"/\s+/",
" ", trim($Value));
140 # set value for field
141 $Field->$MethodName($Value);
145 # make new field permanent
146 $Field->IsTempItem(FALSE);
150 # return new field (if any) to caller
154 # delete metadata field
161 # retrieve field by ID
166 # if caching is off or field is already loaded
167 if (($this->CachingOn != TRUE) || !isset($Fields[
$FieldId]))
173 # return field to caller
210 static $FieldIdsByName;
212 # if caching is off or field ID is already loaded
213 if (($this->CachingOn != TRUE) || !isset($FieldIdsByName[$FieldName]))
215 # retrieve field ID from DB
216 $Condition = $IgnoreCase
217 ?
"WHERE LOWER(FieldName) = '".addslashes(strtolower($FieldName)).
"'"
218 :
"WHERE FieldName = '".addslashes($FieldName).
"'";
219 $FieldIdsByName[$FieldName] = $this->DB->Query(
220 "SELECT FieldId FROM MetadataFields ".$Condition,
"FieldId");
223 return $FieldIdsByName[$FieldName];
235 static $FieldIdsByLabel;
237 # if caching is off or field ID is already loaded
238 if (($this->CachingOn != TRUE) || !isset($FieldIdsByLabel[$FieldLabel]))
240 # retrieve field ID from DB
241 $Condition = $IgnoreCase
242 ?
"WHERE LOWER(Label) = '".addslashes(strtolower($FieldLabel)).
"'"
243 :
"WHERE Label = '".addslashes($FieldLabel).
"'";
244 $FieldIdsByLabel[$FieldLabel] = $this->DB->Query(
245 "SELECT FieldId FROM MetadataFields ".$Condition,
"FieldId");
248 return $FieldIdsByLabel[$FieldLabel];
251 # check whether field with specified name exists
254 # retrieve array of fields
255 function GetFields($FieldTypes = NULL, $OrderType = NULL,
256 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
258 # create empty array to pass back
261 # for each field type in database
262 if ($IncludeTempFields && $IncludeDisabledFields)
264 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields");
268 if ($IncludeTempFields)
270 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields WHERE Enabled != 0");
272 elseif ($IncludeDisabledFields)
274 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields WHERE FieldId >= 0");
278 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields WHERE FieldId >= 0 AND Enabled != 0");
281 while ($Record = $this->DB->FetchRow())
283 # if no specific type requested or if field is of requested type
284 if (($FieldTypes == NULL)
287 # create field object and add to array to be passed back
288 $Fields[$Record[
"FieldId"]] = $this->
GetField($Record[
"FieldId"]);
292 # if field sorting requested
293 if ($OrderType !== NULL)
295 # update field comparison ordering if not set yet
296 if (!self::FieldCompareOrdersSet())
298 self::UpdateFieldCompareOrders();
301 $this->FieldCompareType = $OrderType;
303 # sort field array by requested order type
304 uasort($Fields, array($this,
"CompareFieldOrder"));
307 # return array of field objects to caller
312 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
317 $Fields = $this->
GetFields($FieldTypes, $OrderType, $IncludeDisabledFields, $IncludeTempFields);
319 foreach($Fields as $Field)
321 $DB->Query(
"SELECT FieldName FROM MetadataFields WHERE FieldId=".$Field->Id());
322 $FieldNames[ $Field->Id() ] = $DB->FetchField(
"FieldName");
344 $SelectedFieldId = NULL, $IncludeNullOption = TRUE,
345 $AddEntries = NULL, $AllowMultiple = FALSE)
347 # retrieve requested fields
350 # transform field names to labels
351 foreach ($FieldNames as
$FieldId => $FieldName)
356 # begin HTML option list
357 $Html =
"<select id=\"".$OptionListName.
"\" name=\"".$OptionListName.
"\"";
359 # if multiple selections should be allowed
362 $Html .=
" multiple=\"multiple\"";
367 if ($IncludeNullOption)
369 $Html .=
"<option value=\"\">--</option>\n";
372 # make checking for IDs simpler
373 if (!is_array($SelectedFieldId))
375 $SelectedFieldId = array($SelectedFieldId);
378 # for each metadata field
379 foreach ($FieldNames as $Id => $Name)
381 # add entry for field to option list
382 $Html .=
"<option value=\"".$Id.
"\"";
383 if (in_array($Id, $SelectedFieldId)) { $Html .=
" selected"; }
384 $Html .=
">".htmlspecialchars($Name).
"</option>\n";
387 # if additional entries were requested
390 foreach ($AddEntries as $Value => $Label)
392 $Html .=
"<option value=\"".$Value.
"\"";
393 if (in_array($Value,$SelectedFieldId)) { $Html .=
" selected"; }
394 $Html .=
">".htmlspecialchars($Label).
"</option>\n";
398 # end HTML option list
399 $Html .=
"</select>\n";
401 # return constructed HTML to caller
405 # retrieve array of field types (enumerated type => field name)
411 # retrieve array of field types that user can create (enumerated type => field name)
417 # remove all metadata field associations for a given qualifier
420 # sanitize qualifier ID or grab it from object
421 $QualifierIdOrObject = is_object($QualifierIdOrObject)
422 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
424 # delete intersection records from database
425 $this->DB->Query(
"DELETE FROM FieldQualifierInts WHERE QualifierId = "
426 .$QualifierIdOrObject);
429 # return whether qualifier is in use by metadata field
432 # sanitize qualifier ID or grab it from object
433 $QualifierIdOrObject = is_object($QualifierIdOrObject)
434 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
436 # determine whether any fields use qualifier as default
437 $DefaultCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount FROM MetadataFields"
438 .
" WHERE DefaultQualifier = ".$QualifierIdOrObject,
441 # determine whether any fields are associated with qualifier
442 $AssociationCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount FROM FieldQualifierInts"
443 .
" WHERE QualifierId = ".$QualifierIdOrObject,
446 # report whether qualifier is in use based on defaults and associations
447 return (($DefaultCount + $AssociationCount) > 0) ? TRUE : FALSE;
450 # return highest field ID currently in use
464 self::$FieldMappings[$MappedName] =
$FieldId;
466 return isset(self::$FieldMappings[$MappedName])
467 ? self::$FieldMappings[$MappedName] : NULL;
480 foreach (self::$FieldMappings as $MappedName => $MappedFieldId)
513 SELECT * FROM MetadataFields
514 WHERE Owner IS NOT NULL AND LENGTH(Owner) > 0");
516 while (FALSE !== ($Row = $this->DB->FetchRow()))
532 if (is_callable($Callback))
534 self::$OwnerListRetrievalFunction = $Callback;
545 # if an owner list retrieval function exists
546 if (self::$OwnerListRetrievalFunction)
548 # retrieve the list of owners that currently exist
549 $OwnerList = call_user_func(self::$OwnerListRetrievalFunction);
551 # an array is expected
552 if (is_array($OwnerList))
556 # get each metadata field that is owned by a plugin
557 $OwnedFields = $Schema->GetOwnedFields();
559 # loop through each owned field
560 foreach ($OwnedFields as $OwnedField)
562 # the owner of the current field
563 $Owner = $OwnedField->Owner();
565 # if the owner of the field is in the list of owners that
566 # currently exist, i.e., available plugins
567 if (in_array($Owner, $OwnerList))
569 # enable the field and reset its "enable on owner return"
570 # flag if the "enable on owner return" flag is currently
571 # set to true. in other words, re-enable the field since
572 # the owner has returned to the list of existing owners
573 if ($OwnedField->EnableOnOwnerReturn())
575 $OwnedField->Enabled(TRUE);
576 $OwnedField->EnableOnOwnerReturn(FALSE);
580 # if the owner of the field is *not* in the list of owners
581 # that currently exist, i.e., available plugins
584 # first, see if the field is currently enabled since it
585 # will determine whether the field is re-enabled when
586 # the owner becomes available again
587 $Enabled = $OwnedField->Enabled();
589 # if the field is enabled, set its "enable on owner
590 # return" flag to true and disable the field. nothing
591 # needs to be done if the field is already disabled
594 $OwnedField->EnableOnOwnerReturn($Enabled);
595 $OwnedField->Enabled(FALSE);
617 foreach ($DisplayOrder->GetFields() as $Field)
619 self::$FieldCompareDisplayOrder[$Field->Id()] = $Index++;
624 foreach ($EditOrder->GetFields() as $Field)
626 self::$FieldCompareEditOrder[$Field->Id()] = $Index++;
630 catch (Exception $Exception)
632 # there was an error, so make no assumptions about the order
633 self::$FieldCompareDisplayOrder = array();
634 self::$FieldCompareEditOrder = array();
644 return self::$FieldCompareDisplayOrder && self::$FieldCompareEditOrder;
658 return ($FieldA->GetDisplayName() < $FieldB->GetDisplayName()) ? -1 : 1;
663 $Order = self::$FieldCompareEditOrder;
668 $Order = self::$FieldCompareDisplayOrder;
671 $PositionA = GetArrayValue($Order, $FieldA->Id(), 0);
672 $PositionB = GetArrayValue($Order, $FieldB->Id(), 0);
674 return $PositionA < $PositionB ? -1 : 1;
677 # ---- PRIVATE INTERFACE -------------------------------------------------
679 private $FieldCompareType;
681 private static $FieldMappings;