3 # FILE: MetadataSchema.php 5 # Part of the Collection Workflow Integration System (CWIS) 6 # Copyright 2012-2013 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu/cwis 16 # ---- PUBLIC INTERFACE -------------------------------------------------- 18 # metadata field base types 19 # (must parallel MetadataFields.FieldType declaration in install/CreateTables.sql 20 # and MetadataField::$FieldTypeDBEnums declaration below) 37 # types of field ordering 62 # names used for display and edit orders 66 # maximum option list size for GetFieldsAsOptionList 80 public function __construct($SchemaId = self::SCHEMAID_DEFAULT)
82 # set up item factory base class 83 parent::__construct(
"MetadataField",
"MetadataFields",
84 "FieldId",
"FieldName", FALSE,
85 "SchemaId = ".intval($SchemaId));
87 # make sure schema info cache is loaded 88 if (self::$ValueCache === NULL)
90 $this->DB->Query(
"SELECT * FROM MetadataSchemas");
91 self::$ValueCache = array();
92 foreach ($this->DB->FetchRows() as $Row)
94 self::$ValueCache[$Row[
"SchemaId"]] = $Row;
98 # if standard field mappings have not yet been loaded 99 if (!isset(self::$FieldMappings))
101 # load metadata field IDs to check against 102 $this->DB->Query(
"SELECT SchemaId, FieldId" 103 .
" FROM MetadataFields");
104 $FieldSchemaIds = $this->DB->FetchColumn(
"SchemaId",
"FieldId");
106 # for each standard field mapping 107 $this->DB->Query(
"SELECT * FROM StandardMetadataFieldMappings");
108 foreach ($this->DB->FetchRows() as $Row)
110 # if mapping is for a valid field in appropriate schema 111 if (isset($FieldSchemaIds[$Row[
"FieldId"]])
112 && ($FieldSchemaIds[$Row[
"FieldId"]] == $Row[
"SchemaId"]))
115 self::$FieldMappings[$Row[
"SchemaId"]][$Row[
"Name"]] =
121 throw new Exception(
"Standard field mapping for" 122 .
" \"".$Row[
"Name"].
"\" found with" 123 .
" invalid schema/field ID combination" 124 .
" (".$Row[
"SchemaId"].
"/".$Row[
"FieldId"].
").");
129 # make sure specified schema ID is valid 130 if (!isset(self::$ValueCache[$SchemaId]))
132 throw new InvalidArgumentException(
"Attempt to load metadata schema" 133 .
" with invalid ID (".$SchemaId.
") at " 134 .StdLib::GetMyCaller().
".");
137 # load schema info from cache 138 $Info = self::$ValueCache[$SchemaId];
139 $this->
Id = $SchemaId;
143 $this->
ViewPage = $Info[
"ViewPage"];
144 if (!isset(self::$FieldMappings[$this->
Id]))
146 self::$FieldMappings[$this->Id] = array();
161 # retrieve all constants for class 162 $Reflect =
new ReflectionClass(get_class());
163 $Constants = $Reflect->getConstants();
166 foreach ($Constants as $CName => $CValue)
168 # if value matches and prefix (if supplied) matches 169 if (($CValue == $Value)
170 && (($Prefix === NULL) || (strpos($CName, $Prefix) === 0)))
172 # return name to caller 177 # report to caller that no matching constant was found 203 $ResourceName = NULL)
205 # supply privilege settings if none provided 206 if ($AuthorPrivs === NULL) { $AuthorPrivs =
new PrivilegeSet(); }
207 if ($EditPrivs === NULL) { $EditPrivs =
new PrivilegeSet(); }
208 if ($ViewPrivs === NULL) { $ViewPrivs =
new PrivilegeSet(); }
210 # add schema to database 212 if (strtoupper($Name) ==
"RESOURCES")
214 $Id = self::SCHEMAID_DEFAULT;
216 elseif (strtoupper($Name) ==
"USER")
218 $Id = self::SCHEMAID_USER;
222 $Id =
$DB->Query(
"SELECT SchemaId FROM MetadataSchemas" 223 .
" ORDER BY SchemaId DESC LIMIT 1",
"SchemaId") + 1;
225 $DB->Query(
"INSERT INTO MetadataSchemas" 226 .
" (SchemaId, Name, ViewPage," 227 .
" AuthoringPrivileges, EditingPrivileges, ViewingPrivileges)" 228 .
" VALUES (".intval($Id).
"," 229 .
"'".addslashes($Name).
"'," 230 .
"'".
$DB->EscapeString($ViewPage).
"'," 231 .
"'".
$DB->EscapeString($AuthorPrivs->Data()).
"'," 232 .
"'".
$DB->EscapeString($EditPrivs->Data()).
"'," 233 .
"'".
$DB->EscapeString($ViewPrivs->Data()).
"')");
235 # clear schema data cache so it will be reloaded 236 self::$ValueCache = NULL;
238 # construct the new schema 241 # set schema name if none supplied 244 $Schema->Name(
"Metadata Schema ".$Id);
247 # set the resource name if one is supplied 248 if ($ResourceName === NULL)
252 $Schema->ResourceName($ResourceName);
254 # create display and edit orders 258 # return the new schema 268 # delete resources associated with schema 270 $ResourceIds = $RFactory->GetItemIds();
271 foreach ($ResourceIds as $ResourceId)
273 $Resource =
new Resource($ResourceId);
277 # unmap all the mapped fields 278 $MappedNames = array_keys(self::$FieldMappings[$this->
Id]);
279 foreach ($MappedNames as $MappedName)
284 # delete fields associated with schema 285 $Fields = $this->
GetFields(NULL, NULL, TRUE, TRUE);
286 foreach ($Fields as $FieldId => $Field)
291 # delete metadata field orders associated with schema 297 # remove schema info from database 298 $this->DB->Query(
"DELETE FROM MetadataSchemas WHERE SchemaId = " 309 if (!is_numeric($SchemaId))
314 $DB->Query(
"SELECT * FROM MetadataSchemas" 315 .
" WHERE SchemaId = ".intval($SchemaId));
316 return (
$DB->NumRowsSelected() > 0) ? TRUE : FALSE;
326 # return value to caller 327 return intval($this->
Id);
349 $AName = $this->
UpdateValue(
"AbbreviatedName", $NewValue);
352 $AName = strtoupper(substr($this->
Name(), 0, 1));
364 $RName = $this->
UpdateValue(
"ResourceName", $NewValue);
367 $RName = self::RESOURCENAME_DEFAULT;
389 # if new privileges supplied 390 if ($NewValue !== NULL)
392 # store new privileges in database 393 $this->
UpdateValue(
"AuthoringPrivileges", $NewValue->Data());
397 # return current value to caller 398 return $this->AuthoringPrivileges;
408 # if new privileges supplied 409 if ($NewValue !== NULL)
411 # store new privileges in database 412 $this->
UpdateValue(
"EditingPrivileges", $NewValue->Data());
416 # return current value to caller 417 return $this->EditingPrivileges;
427 # if new privileges supplied 428 if ($NewValue !== NULL)
430 # store new privileges in database 431 $this->
UpdateValue(
"ViewingPrivileges", $NewValue->Data());
435 # return current value to caller 436 return $this->ViewingPrivileges;
448 # get authoring privilege set for schema 451 # user can author if privileges are greater than resource set 452 $CanAuthor = $AuthorPrivs->MeetsRequirements($User);
454 # allow plugins to modify result of permission check 455 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
456 "EVENT_RESOURCE_AUTHOR_PERMISSION_CHECK", array(
459 "CanAuthor" => $CanAuthor));
460 $CanAuthor = $SignalResult[
"CanAuthor"];
462 # report back to caller whether user can author field 475 # get editing privilege set for schema 478 # user can edit if privileges are greater than resource set 479 $CanEdit = $EditPrivs->MeetsRequirements($User);
481 # allow plugins to modify result of permission check 482 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
483 "EVENT_RESOURCE_EDIT_PERMISSION_CHECK", array(
486 "CanEdit" => $CanEdit,
487 "Schema" => $this, ));
488 $CanEdit = $SignalResult[
"CanEdit"];
490 # report back to caller whether user can edit field 503 # get viewing privilege set for schema 506 # user can view if privileges are greater than resource set 507 $CanView = $ViewPrivs->MeetsRequirements($User);
509 # allow plugins to modify result of permission check 510 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
511 "EVENT_RESOURCE_VIEW_PERMISSION_CHECK", array(
514 "CanView" => $CanView,
515 "Schema" => $this, ));
516 $CanView = $SignalResult[
"CanView"];
518 # report back to caller whether user can view field 529 # get the query/GET parameters for the view page 530 $Query = parse_url($this->
ViewPage(), PHP_URL_QUERY);
532 # the URL couldn't be parsed 533 if (!is_string($Query))
538 # parse the GET parameters out of the query string 539 $GetVars = ParseQueryString($Query);
541 # search for the ID parameter 542 $Result = array_search(
"\$ID", $GetVars);
544 return $Result !== FALSE ? $Result : NULL;
561 # get the query/GET parameters for the view page 562 $Query = parse_url($this->
ViewPage(), PHP_URL_QUERY);
564 # can't perform matching if the URL couldn't be parsed 565 if (!is_string($Query))
570 # parse the GET parameters out of the query string 571 $GetVars = ParseQueryString($Query);
573 # now, get the query/GET parameters from the path given 574 $PathQuery = parse_url($Path, PHP_URL_QUERY);
576 # can't perform matching if the URL couldn't be parsed 577 if (!is_string($PathQuery))
582 # parse the GET parameters out of the path's query string 583 $PathGetVars = ParseQueryString($PathQuery);
585 # make sure the given path GET parameters contain at least the GET 586 # parameters from the view page and that all non-variable parameters are 587 # equal. the path GET parameters may contain more, which is okay 588 foreach ($GetVars as $GetVarName => $GetVarValue)
590 # there's a required parameter that is not included in the path GET 592 if (!array_key_exists($GetVarName, $PathGetVars))
597 # require the path's value to be equal to the view page's value if 598 # the view page's value is not a variable, 599 if ($PathGetVars[$GetVarName] != $GetVarValue
600 && (!strlen($GetVarValue) || $GetVarValue{0} !=
"$"))
606 # the path matches the view page path 620 $FieldName, $FieldType, $Optional = TRUE, $DefaultValue = NULL)
622 # clear any existing error messages 623 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
624 { unset($this->ErrorMsgs[__METHOD__]); }
630 $FieldName, $Optional, $DefaultValue);
632 catch (Exception $Exception)
634 $this->ErrorMsgs[__METHOD__][] = $Exception->getMessage();
638 # clear internal caches to make sure new field is recognized going forward 641 # return new field to caller 661 # clear loading status 663 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
664 { unset($this->ErrorMsgs[__METHOD__]); }
666 # check that file exists and is readable 667 if (!file_exists($FileName))
669 $this->ErrorMsgs[__METHOD__][] =
"Could not find XML file '" 673 elseif (!is_readable($FileName))
675 $this->ErrorMsgs[__METHOD__][] =
"Could not read from XML file '" 681 libxml_use_internal_errors(TRUE);
682 $XmlData = simplexml_load_file($FileName);
683 $Errors = libxml_get_errors();
684 libxml_use_internal_errors(FALSE);
687 if ($XmlData === FALSE)
689 # retrieve XML error messages 690 foreach ($Errors as $Err)
692 $ErrType = ($Err->level == LIBXML_ERR_WARNING) ?
"Warning" 693 : (($Err->level == LIBXML_ERR_WARNING) ?
"Error" 695 $this->ErrorMsgs[__METHOD__][] =
"XML ".$ErrType.
": ".$Err->message
696 .
" (".$Err->file.
":".$Err->line.
",".$Err->column.
")";
699 # else if no metadata fields found record error message 700 elseif (!count($XmlData->MetadataField))
702 $this->ErrorMsgs[__METHOD__][] =
"No metadata fields found.";
704 # else process metadata fields 707 # for each metadata field entry found 710 foreach ($XmlData->MetadataField as $FieldXml)
714 # pull out field type if present 715 if (isset($FieldXml->Type))
717 $FieldType =
"MetadataSchema::".$FieldXml->Type;
718 if (!defined($FieldType))
720 $FieldType =
"MetadataSchema::MDFTYPE_" 721 .strtoupper(preg_replace(
"/\\s+/",
"",
726 # if required values are missing 727 if (!isset($FieldXml->Name)
728 || !isset($FieldXml->Type)
729 || !isset($FieldType)
730 || !defined($FieldType))
732 # add error message about required value missing 733 if (!isset($FieldXml->Name))
735 $this->ErrorMsgs[__METHOD__][] =
736 "Field name not found (MetadataField #" 739 if (!isset($FieldXml->Type)
740 || !isset($FieldType)
741 || !defined($FieldType))
743 $this->ErrorMsgs[__METHOD__][] =
744 "Valid type not found for field '" 745 .$FieldXml->Name.
"' (MetadataField #" 749 # else if there is not already a field with this name 750 elseif (!$this->
NameIsInUse(trim($FieldXml->Name)))
753 $Field = $this->
AddField($FieldXml->Name, constant($FieldType));
755 # if field creation failed 758 # add any error message to our error list 760 foreach ($ErrorMsgs as $Msg)
762 $this->ErrorMsgs[__METHOD__][] =
768 # add field to list of created fields 771 # assume no vocabulary to load 774 # for other field attributes 775 foreach ($FieldXml as $MethodName => $Value)
777 # if tags look valid and have not already been set 778 if (method_exists($Field, $MethodName)
779 && ($MethodName !=
"Name")
780 && ($MethodName !=
"Type"))
782 # if tag indicates privilege set 783 if (preg_match(
"/^[a-z]+Privileges\$/i",
786 # save element for later processing 787 $PrivilegesToSet[$Field->Id()][$MethodName] = $Value;
791 # condense down any extraneous whitespace 792 $Value = preg_replace(
"/\s+/",
" ", trim($Value));
794 # set value for field 795 $Field->$MethodName($Value);
798 elseif ($MethodName ==
"VocabularyFile")
800 $VocabToLoad = $Value;
804 # save the temp ID so that any privileges to set 805 # can be mapped to the actual ID when the field is 807 $TempId = $Field->Id();
809 # make new field permanent 810 $Field->IsTempItem(FALSE);
812 # load any vocabularies 813 if ($VocabToLoad !== NULL)
815 $Field->LoadVocabulary($VocabToLoad);
818 # map privileges to set to the permanent field ID 819 if (isset($PrivilegesToSet) &&
820 isset($PrivilegesToSet[$TempId]) )
822 # copy the privileges over 823 $PrivilegesToSet[$Field->Id()] =
824 $PrivilegesToSet[$TempId];
826 # remove the values for the temp ID 827 unset($PrivilegesToSet[$TempId]);
833 # if we have schema-level privileges to set 834 if (count($XmlData->SchemaPrivileges))
836 foreach ($XmlData->SchemaPrivileges->children() as $PrivName => $PrivXml)
838 # if our current value for this privset is empty, 839 # take the one from the file 840 if ($this->$PrivName()->ComparisonCount() == 0)
842 # extract the values to set from the XML 843 $Value = $this->ConvertXmlToPrivilegeSet($PrivXml);
845 $this->$PrivName($Value);
850 # if we have privileges to set 851 if (isset($PrivilegesToSet))
853 # for each field with privileges 854 foreach ($PrivilegesToSet as $FieldId => $Privileges)
856 # load the field for which to set the privileges 859 # for each set of privileges for field 860 foreach ($Privileges as $MethodName => $Value)
862 # convert privilege value 863 $Value = $this->ConvertXmlToPrivilegeSet($Value);
865 # if conversion failed 868 # add resulting error messages to our list 870 "ConvertXmlToPrivilegeSet");
871 foreach ($ErrorMsgs as $Msg)
873 $this->ErrorMsgs[__METHOD__][] =
874 $Msg.
" (ConvertXmlToPrivilegeSet)";
879 # set value for field 880 $Field->$MethodName($Value);
886 # if errors were found during creation 887 if (array_key_exists(__METHOD__, $this->ErrorMsgs) || $TestRun)
889 # remove any fields that were created 898 # set owner for new fields (if supplied) 903 $Field->Owner($Owner);
907 # if there were standard field mappings included 908 if (isset($XmlData->StandardFieldMapping))
910 # for each standard field mapping found 911 foreach ($XmlData->StandardFieldMapping as $MappingXml)
913 # if required values are supplied 914 if (isset($MappingXml->Name)
915 && isset($MappingXml->StandardName))
917 # get ID for specified field 918 $FieldName = (string)$MappingXml->Name;
919 $StandardName = (
string)$MappingXml->StandardName;
922 # if field ID was found 923 if ($FieldId !== FALSE)
925 # set standard field mapping 927 $StandardName, $FieldId);
931 # log error about field not found 932 $this->ErrorMsgs[__METHOD__][] =
933 "Field not found with name '".$FieldName
934 .
"' to map to standard field name '" 940 # log error about missing value 941 if (!isset($MappingXml->Name))
943 $this->ErrorMsgs[__METHOD__][] =
944 "Field name missing for standard" 947 if (!isset($MappingXml->StandardName))
949 $this->ErrorMsgs[__METHOD__][] =
950 "Standard field name missing for" 951 .
" standard field mapping.";
959 # report success or failure based on whether errors were recorded 960 return (array_key_exists(__METHOD__, $this->ErrorMsgs)) ? FALSE : TRUE;
970 return $this->NewFields;
984 if ($Method === NULL)
986 return $this->ErrorMsgs;
990 if (!method_exists($this, $Method))
992 throw new Exception(
"Error messages requested for non-existent" 993 .
" method (".$Method.
").");
995 return array_key_exists(__CLASS__.
"::".$Method, $this->ErrorMsgs)
996 ? $this->ErrorMsgs[__CLASS__.
"::".$Method] : array();
1011 # assume field addition will fail 1012 $Field = self::MDFSTAT_ERROR;
1014 # add XML prefixes if needed 1016 if (!preg_match(
"/^<\?xml/i", $Xml))
1018 if (!preg_match(
"/^<document>/i", $Xml))
1020 $Xml =
"<document>".$Xml.
"</document>";
1022 $Xml =
"<?xml version='1.0'?".
">".$Xml;
1026 $XmlData = simplexml_load_string($Xml);
1028 # if required values are present 1029 if (is_object($XmlData)
1030 && isset($XmlData->Name)
1031 && isset($XmlData->Type)
1032 && constant(
"MetadataSchema::".$XmlData->Type))
1034 # create the metadata field 1037 constant(
"MetadataSchema::".$XmlData->Type));
1039 # if field creation succeeded 1042 # for other field attributes 1043 foreach ($XmlData as $MethodName => $Value)
1045 # if they look valid and have not already been set 1046 if (method_exists($Field, $MethodName)
1047 && ($MethodName !=
"Name")
1048 && ($MethodName !=
"Type"))
1050 # if tag indicates privilege set 1051 if (preg_match(
"/^[a-z]+Privileges\$/i",
1054 # save element for later processing 1055 $PrivilegesToSet[$MethodName] = $Value;
1059 # condense down any extraneous whitespace 1060 $Value = preg_replace(
"/\s+/",
" ", trim($Value));
1062 # set value for field 1063 $Field->$MethodName($Value);
1068 # make new field permanent 1069 $Field->IsTempItem(FALSE);
1071 # if we have privileges to set 1072 if (isset($PrivilegesToSet))
1074 # for each set of privileges for field 1075 foreach ($PrivilegesToSet as $MethodName => $Value)
1077 # convert privilege value 1078 $Value = $this->ConvertXmlToPrivilegeSet($Value);
1080 # if conversion failed 1081 if ($Value === NULL)
1083 # add resulting error messages to our list 1085 "ConvertXmlToPrivilegeSet");
1086 foreach ($ErrorMsgs as $Msg)
1088 $this->ErrorMsgs[__METHOD__][] =
1089 $Msg.
" (ConvertXmlToPrivilegeSet)";
1094 # set value for field 1095 $Field->$MethodName($Value);
1102 # return new field (if any) to caller 1113 $Field = $this->
GetField($FieldId);
1114 if ($Field === NULL)
1119 # verify that this field is not mapped prior to dropping it 1120 foreach (self::$FieldMappings[$this->
Id] as $Name => $FieldId)
1122 if ($Field->Id() == $FieldId)
1124 throw new Exception(
1125 "Attempt to delete ".$Field->Name()
1126 .
", which is mapped as the standard ".$Name
1127 .
" in the ".$this->
Name().
" Schema.");
1131 $GLOBALS[
"AF"]->SignalEvent(
"EVENT_PRE_FIELD_DELETE",
1132 array(
"FieldId" => $Field->Id()) );
1147 # convert field name to ID if necessary 1148 if (!is_numeric($FieldId))
1150 $FieldName = $FieldId;
1152 if ($FieldId === FALSE)
1154 throw new InvalidArgumentException(
"Attempt to retrieve field" 1155 .
" with unknown name (".$FieldName.
").");
1159 # if caching is off or field is not already loaded 1160 if (!isset(self::$FieldCache[$FieldId]))
1165 # if field was from a different schema, bail 1166 if (self::$FieldCache[$FieldId]->SchemaId() != $this->
Id())
1168 throw new InvalidArgumentException(
1169 "Attempt to retrieve a field from a different schema");
1172 return self::$FieldCache[$FieldId];
1188 return ($FieldId === FALSE) ? NULL : $this->
GetField($FieldId);
1210 return is_numeric($Field)
1228 public function GetFields($FieldTypes = NULL, $OrderType = NULL,
1229 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
1231 # create empty array to pass back 1234 # for each field type in database 1235 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields" 1236 .
" WHERE SchemaId = ".intval($this->
Id)
1237 .(!$IncludeDisabledFields ?
" AND Enabled != 0" :
"")
1238 .(!$IncludeTempFields ?
" AND FieldId >= 0" :
""));
1239 while ($Record = $this->DB->FetchRow())
1241 # if field type is known 1244 # if no specific type requested or if field is of requested type 1245 if (($FieldTypes == NULL)
1249 # create field object and add to array to be passed back 1250 $Fields[$Record[
"FieldId"]] = $this->
GetField($Record[
"FieldId"]);
1255 # if field sorting requested 1256 if ($OrderType !== NULL)
1258 # update field comparison ordering if not set yet 1264 $this->FieldCompareType = $OrderType;
1266 # sort field array by requested order type 1267 uasort($Fields, array($this,
"CompareFieldOrder"));
1270 # return array of field objects to caller 1289 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
1291 $Fields = $this->
GetFields($FieldTypes, $OrderType,
1292 $IncludeDisabledFields, $IncludeTempFields);
1294 $FieldNames = array();
1295 foreach($Fields as $Field)
1297 $FieldNames[$Field->Id()] = $Field->Name();
1322 $SelectedFieldId = NULL, $IncludeNullOption = TRUE,
1323 $AddEntries = NULL, $AllowMultiple = FALSE, $Disabled = FALSE)
1325 # retrieve requested fields 1328 # transform field names to labels 1329 foreach ($FieldNames as $FieldId => $FieldName)
1331 $FieldNames[$FieldId] = $this->
GetField($FieldId)->GetDisplayName();
1334 # add in null entry if requested 1335 if ($IncludeNullOption)
1337 $FieldNames = array(
"" =>
"--") + $FieldNames;
1340 # add additional entries if supplied 1343 $FieldNames = $FieldNames + $AddEntries;
1346 # construct option list 1347 $OptList =
new HtmlOptionList($OptionListName, $FieldNames, $SelectedFieldId);
1348 $OptList->MultipleAllowed($AllowMultiple);
1351 $OptList->Size(min(self::MAX_OPT_LIST_SIZE, count($FieldNames)));
1353 $OptList->Disabled($Disabled);
1355 # return option list HTML to caller 1356 return $OptList->GetHtml();
1385 # sanitize qualifier ID or grab it from object 1386 $QualifierIdOrObject = is_object($QualifierIdOrObject)
1387 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
1389 # delete intersection records from database 1390 $this->DB->Query(
"DELETE FROM FieldQualifierInts" 1391 .
" WHERE QualifierId = ".$QualifierIdOrObject);
1401 # sanitize qualifier ID or grab it from object 1402 $QualifierIdOrObject = is_object($QualifierIdOrObject)
1403 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
1405 # determine whether any fields use qualifier as default 1406 $DefaultCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount" 1407 .
" FROM MetadataFields" 1408 .
" WHERE DefaultQualifier = ".$QualifierIdOrObject,
1411 # determine whether any fields are associated with qualifier 1412 $AssociationCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount" 1413 .
" FROM FieldQualifierInts" 1414 .
" WHERE QualifierId = ".$QualifierIdOrObject,
1417 # report whether qualifier is in use based on defaults and associations 1418 return (($DefaultCount + $AssociationCount) > 0) ? TRUE : FALSE;
1440 if (func_num_args() > 1)
1442 if (!isset(self::$FieldMappings[$this->
Id][$MappedName])
1443 || (self::$FieldMappings[$this->
Id][$MappedName] != $FieldId))
1445 if (($FieldId !== NULL) && !$this->
FieldExists($FieldId))
1447 throw new InvalidArgumentException(
"Attempt to set" 1448 .
" standard field mapping to invalid field ID" 1452 # if a mapping is set and is not NULL 1453 if (isset(self::$FieldMappings[$this->
Id][$MappedName]))
1455 $this->DB->Query(
"DELETE FROM StandardMetadataFieldMappings" 1456 .
" WHERE SchemaId = '".addslashes($this->
Id)
1457 .
"' AND Name = '".addslashes($MappedName).
"'");
1458 unset(self::$FieldMappings[$this->
Id][$MappedName]);
1461 if ($FieldId !== NULL)
1463 $this->DB->Query(
"INSERT INTO StandardMetadataFieldMappings" 1464 .
" (SchemaId, Name, FieldId) VALUES ('" 1465 .addslashes($this->
Id).
"', '".addslashes($MappedName)
1466 .
"', '".addslashes($FieldId).
"')");
1467 self::$FieldMappings[$this->Id][$MappedName] = $FieldId;
1471 return isset(self::$FieldMappings[$this->
Id][$MappedName])
1472 ? self::$FieldMappings[$this->Id][$MappedName] : NULL;
1483 $MappedName = array_search($FieldId, self::$FieldMappings[$this->
Id]);
1484 return ($MappedName === FALSE) ? NULL : $MappedName;
1520 $this->DB->Query(
"SELECT * FROM MetadataFields" 1521 .
" WHERE Owner IS NOT NULL AND LENGTH(Owner) > 0" 1522 .
" AND SchemaId = ".intval($this->
Id));
1524 while (FALSE !== ($Row = $this->DB->FetchRow()))
1526 $FieldId = $Row[
"FieldId"];
1527 $Fields[$FieldId] = $this->
GetField($FieldId);
1540 # if we were given a field id, check to see if it exists 1541 self::LoadFieldNamesCache();
1542 if (is_numeric($Field) &&
1543 array_key_exists($Field, self::$FieldNamesCache))
1548 # otherwise, try to look up this field 1551 $FieldId = self::GetCanonicalFieldIdentifier($Field);
1552 return array_key_exists($FieldId, self::$FieldNamesCache) ?
1555 catch (Exception $e)
1557 # if we can't find the field, then it doesn't exist 1583 # check to make sure any specified schema is valid 1584 self::LoadFieldNamesCache();
1585 if ($SchemaId !== NULL)
1587 if (!isset(self::$SchemaNamesCache[$SchemaId]))
1589 throw new InvalidArgumentException(
1590 "Invalid schema ID supplied (".$SchemaId.
").");
1594 # if field object was passed in 1597 # check to make sure field ID is within any specified schema 1598 if (($SchemaId !== NULL) && ($Field->SchemaId() != $SchemaId))
1600 throw new Exception(
"Supplied field (".$Field
1601 .
") is not within specified " 1602 .self::$SchemaNamesCache[$SchemaId]
1603 .
" schema (".$SchemaId.
")");
1606 # return identifier from field to caller 1607 return $Field->Id();
1609 # else if field ID was passed in 1610 elseif (is_numeric($Field))
1612 # check to make sure field ID is valid 1613 if (!isset(self::$FieldNamesCache[$Field]))
1615 throw new InvalidArgumentException(
1616 "Invalid field ID supplied (".$Field.
").");
1619 # check to make sure field ID is within any specified schema 1620 if (($SchemaId !== NULL)
1621 && (self::$FieldNamesCache[$Field][
"SchemaId"] != $SchemaId))
1623 throw new Exception(
"Supplied field ID (".$Field
1624 .
") is not within specified " 1625 .self::$SchemaNamesCache[$SchemaId]
1626 .
" schema (".$SchemaId.
")");
1629 # return supplied field ID to caller 1632 # else if field name was passed in 1633 elseif (is_string($Field))
1635 # look for field with specified name 1636 $FieldName = trim($Field);
1638 array_walk(self::$FieldNamesCache,
1639 function($Value, $Key, $FieldName) use (&$FieldId, $SchemaId)
1641 if (($Value[
"QualifiedFieldName"] == $FieldName)
1642 && (($SchemaId === NULL)
1643 || ($Value[
"SchemaId"] == $SchemaId)))
1649 # if field with specified name not found 1650 if ($FieldId === NULL)
1652 # log error and look for field with unqualified version of name 1653 # (NOTE: This is a temporary measure, to be removed once errors 1654 # are no longer regularly showing up in the log, in favor 1655 # of immediately throwing an exception if the name was 1658 array_walk(self::$FieldNamesCache,
1659 function($Value, $Key, $FieldName) use (&$FieldId)
1661 if ($Value[
"FieldName"] == $FieldName)
1666 if ($FieldId === NULL)
1668 throw new Exception(
1669 "No field found with the name \"".$FieldName.
"\".");
1674 "No field found with the name \"".$FieldName.
"\"." 1679 # return found field ID to caller 1682 # else error out because we were given an illegal field argument 1685 throw new InvalidArgumentException(
1686 "Illegal field argument supplied.");
1707 $Id = self::GetCanonicalFieldIdentifier($Field);
1709 # if we have a label for this field, return it 1710 self::LoadFieldNamesCache();
1711 if (isset(self::$FieldNamesCache[$Id]))
1713 $DisplayName = strlen(self::$FieldNamesCache[$Id][
"FieldLabel"]) ?
1714 self::$FieldNamesCache[$Id][
"FieldLabel"] :
1715 self::$FieldNamesCache[$Id][
"FieldName"] ;
1716 return self::$FieldNamesCache[$Id][
"SchemaPrefix"].$DisplayName;
1719 # otherwise return a blank string 1730 $DB->Query(
"SELECT DISTINCT Name FROM StandardMetadataFieldMappings");
1731 return $DB->FetchColumn(
"Name");
1744 # start out assuming we won't find any values to translate 1745 $ReturnValues = array();
1747 # try to grab the specified field 1752 catch (Exception $e)
1754 # field no longer exists, so there are no values to translate 1755 return $ReturnValues;
1758 # if incoming value is not an array 1759 if (!is_array($Values))
1761 # convert incoming value to an array 1762 $Values = array($Values);
1765 # for each incoming value 1766 foreach ($Values as $Value)
1768 # look up value for index 1769 if ($Field->Type() == self::MDFTYPE_FLAG)
1771 # (for flag fields the value index (0 or 1) is used in Database) 1774 $ReturnValues[] =
"=".$Value;
1777 elseif ($Field->Type() == self::MDFTYPE_NUMBER)
1779 # (for flag fields the value index (0 or 1) is used in Database) 1782 $ReturnValues[] =
">=".$Value;
1785 elseif ($Field->Type() == self::MDFTYPE_USER)
1787 $User =
new CWUser(intval($Value));
1790 $ReturnValues[] =
"=".$User->Get(
"UserName");
1793 elseif ($Field->Type() == self::MDFTYPE_OPTION)
1795 if (!isset($PossibleFieldValues))
1797 $PossibleFieldValues = $Field->GetPossibleValues();
1800 if (isset($PossibleFieldValues[$Value]))
1802 $ReturnValues[] =
"=".$PossibleFieldValues[$Value];
1807 $NewValue = $Field->GetValueForId($Value);
1808 if ($NewValue !== NULL)
1810 $ReturnValues[] =
"=".$NewValue;
1815 # return array of translated values to caller 1816 return $ReturnValues;
1825 return array_keys(self::GetAllSchemaNames());
1835 $DB->Query(
"SELECT SchemaId, Name FROM MetadataSchemas");
1836 return $DB->FetchColumn(
"Name",
"SchemaId");
1846 # fetch IDs of all metadata schemas 1847 $SchemaIds = self::GetAllSchemaIds();
1849 # construct objects from the IDs 1851 foreach ($SchemaIds as $SchemaId)
1856 # return schemas to caller 1868 # list of priv types we'll be checking 1870 "AuthoringPrivileges",
1871 "EditingPrivileges",
1872 "ViewingPrivileges");
1874 # iterate over each schema 1875 foreach (self::GetAllSchemas() as $Schema)
1877 # see if the provided field is checked in any of the 1878 # schema-level privs, returning TRUE if so 1879 foreach ($PrivTypes as $PrivType)
1881 if ($Schema->$PrivType()->ChecksField($FieldId))
1887 # otherwise, iterate over all the field-level privs, returning true 1888 # if any of those check the provided field 1889 foreach ($Schema->GetFields() as $Field)
1891 foreach ($PrivTypes as $PrivType)
1893 if ($Field->$PrivType()->ChecksField($FieldId))
1901 # nothing checks this field, return FALSE 1913 $Id =
$DB->Query(
"SELECT SchemaId FROM MetadataSchemas" 1914 .
" WHERE Name = '".addslashes($Name).
"'",
"SchemaId");
1915 return ($Id === FALSE) ? NULL : (int)$Id;
1925 if (is_callable($Callback))
1927 self::$OwnerListRetrievalFunction = $Callback;
1938 # if an owner list retrieval function and default schema exists 1939 if (self::$OwnerListRetrievalFunction
1940 && self::SchemaExistsWithId(self::SCHEMAID_DEFAULT))
1942 # retrieve the list of owners that currently exist 1943 $OwnerList = call_user_func(self::$OwnerListRetrievalFunction);
1945 # an array is expected 1946 if (is_array($OwnerList))
1950 # get each metadata field that is owned by a plugin 1951 $OwnedFields = $Schema->GetOwnedFields();
1953 # loop through each owned field 1954 foreach ($OwnedFields as $OwnedField)
1956 # the owner of the current field 1957 $Owner = $OwnedField->Owner();
1959 # if the owner of the field is in the list of owners that 1960 # currently exist, i.e., available plugins 1961 if (in_array($Owner, $OwnerList))
1963 # enable the field and reset its "enable on owner return" 1964 # flag if the "enable on owner return" flag is currently 1965 # set to true. in other words, re-enable the field since 1966 # the owner has returned to the list of existing owners 1967 if ($OwnedField->EnableOnOwnerReturn())
1969 $OwnedField->Enabled(TRUE);
1970 $OwnedField->EnableOnOwnerReturn(FALSE);
1974 # if the owner of the field is *not* in the list of owners 1975 # that currently exist, i.e., available plugins 1978 # first, see if the field is currently enabled since it 1979 # will determine whether the field is re-enabled when 1980 # the owner becomes available again 1981 $Enabled = $OwnedField->Enabled();
1983 # if the field is enabled, set its "enable on owner 1984 # return" flag to true and disable the field. nothing 1985 # needs to be done if the field is already disabled 1988 $OwnedField->EnableOnOwnerReturn($Enabled);
1989 $OwnedField->Enabled(FALSE);
2007 $this->FieldCompareDisplayOrder[$Field->Id()] = $Index++;
2014 $this->FieldCompareEditOrder[$Field->Id()] = $Index++;
2054 if ($this->FieldCompareType == self::MDFORDER_ALPHABETICAL)
2056 return ($FieldA->GetDisplayName() < $FieldB->GetDisplayName()) ? -1 : 1;
2059 if ($this->FieldCompareType == self::MDFORDER_EDITING)
2069 $PositionA = GetArrayValue($Order, $FieldA->Id(), 0);
2070 $PositionB = GetArrayValue($Order, $FieldB->Id(), 0);
2072 return $PositionA < $PositionB ? -1 : 1;
2081 self::$FieldCache = NULL;
2082 self::$FieldNamesCache = NULL;
2085 # ---- PRIVATE INTERFACE ------------------------------------------------- 2087 private $AuthoringPrivileges;
2088 private $EditingPrivileges;
2089 private $ErrorMsgs = array();
2090 private $FieldCompareType;
2092 private $NewFields = array();
2093 private $ViewingPrivileges;
2096 private static $FieldMappings;
2097 private static $ValueCache = NULL;
2099 private static $FieldCache = NULL;
2100 private static $FieldNamesCache;
2101 private static $SchemaNamesCache;
2118 private static function LoadFieldNamesCache()
2120 if (!isset(self::$FieldNamesCache))
2122 self::$SchemaNamesCache = self::GetAllSchemaNames();
2125 $DB->Query(
"SELECT SchemaId, FieldId, FieldName, Label FROM MetadataFields" 2126 # (NOTE: This ordering is a temporary measure, to be removed when the
2128 .
" ORDER BY SchemaId DESC");
2129 while ($Row =
$DB->FetchRow())
2131 $SchemaPrefix = ($Row[
"SchemaId"] == self::SCHEMAID_DEFAULT)
2132 ?
"" : self::$SchemaNamesCache[$Row[
"SchemaId"]].
": ";
2134 $TrimmedLabel = trim($Row[
"Label"]);
2135 $TrimmedName = trim($Row[
"FieldName"]);
2137 self::$FieldNamesCache[$Row[
"FieldId"]] = [
2138 "SchemaId" => $Row[
"SchemaId"],
2139 "SchemaPrefix" => $SchemaPrefix,
2140 "FieldName" => $TrimmedName,
2141 "QualifiedFieldName" => $SchemaPrefix.$TrimmedName,
2142 "FieldLabel" => $TrimmedLabel,
2155 private function ConvertXmlToPrivilegeSet($Xml)
2157 # clear any existing errors 2158 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
2159 { unset($this->ErrorMsgs[__METHOD__]); }
2161 # create new privilege set 2164 # for each XML child 2165 foreach ($Xml as $Tag => $Value)
2167 # take action based on element name 2170 case "PrivilegeSet":
2171 # convert child data to new set 2172 $NewSet = $this->ConvertXmlToPrivilegeSet($Value);
2174 # add new set to our privilege set 2175 $PrivSet->AddSet($NewSet);
2178 case "AddCondition":
2179 # start with default values for optional parameters 2180 unset($ConditionField);
2181 $ConditionValue = NULL;
2182 $ConditionOperator =
"==";
2184 # pull out parameters 2185 foreach ($Value as $ParamName => $ParamValue)
2187 $ParamValue = trim($ParamValue);
2191 $ConditionField = $this->
GetField($ParamValue);
2192 if ($ConditionField === NULL)
2194 # record error about unknown field 2195 $this->ErrorMsgs[__METHOD__][] =
2196 "Unknown metadata field name found" 2197 .
" in AddCondition (".$ParamValue.
").";
2205 $ConditionValue = (string)$ParamValue;
2207 if ($ConditionValue ==
"NULL")
2209 $ConditionValue = NULL;
2211 elseif ($ConditionValue ==
"TRUE")
2213 $ConditionValue = TRUE;
2215 elseif ($ConditionValue ==
"FALSE")
2217 $ConditionValue = FALSE;
2222 $ConditionOperator = (string)$ParamValue;
2226 # record error about unknown parameter name 2227 $this->ErrorMsgs[__METHOD__][] =
2228 "Unknown tag found in AddCondition (" 2238 if (!isset($ConditionField))
2240 # record error about no field value 2241 $this->ErrorMsgs[__METHOD__][] =
2242 "No metadata field specified in AddCondition.";
2248 # if this is a vocabulary field 2251 if ($Factory !== NULL)
2253 # look up the id of the provided value 2254 $ConditionValue = $Factory->GetItemIdByName(
2257 # if none was found, error out 2258 if ($ConditionValue === FALSE)
2260 $this->ErrorMsgs[__METHOD__][] =
2261 "Invalid value for field specified in AddCondition.";
2266 # add conditional to privilege set 2267 $PrivSet->AddCondition($ConditionField,
2268 $ConditionValue, $ConditionOperator);
2272 # strip any excess whitespace off of value 2273 $Value = trim($Value);
2275 # if child looks like valid method name 2276 if (method_exists(
"PrivilegeSet", $Tag))
2278 # convert constants if needed 2279 if (defined($Value))
2281 $Value = constant($Value);
2283 # convert booleans if needed 2284 elseif (strtoupper($Value) ==
"TRUE")
2288 elseif (strtoupper($Value) ==
"FALSE")
2292 # convert privilege flag names if needed and appropriate 2293 elseif (preg_match(
"/Privilege$/", $Tag))
2296 if (!isset($Privileges))
2299 $Privileges = $PFactory->GetPrivileges(TRUE, FALSE);
2301 if (in_array($Value, $Privileges))
2303 $Value = array_search($Value, $Privileges);
2307 # set value using child data 2308 $PrivSet->$Tag((
string)$Value);
2312 # record error about bad tag 2313 $this->ErrorMsgs[__METHOD__][] =
2314 "Unknown tag encountered (".$Tag.
").";
2323 # return new privilege set to caller 2336 return $this->DB->UpdateValue(
"MetadataSchemas", $ColumnName, $NewValue,
2337 "SchemaId = ".intval($this->
Id),
2338 self::$ValueCache[$this->
Id]);
GetHighestItemId($IgnoreSqlCondition=FALSE)
Retrieve highest item ID in use.
const LOGLVL_ERROR
ERROR error logging level.
GetItemIdByName($Name, $IgnoreCase=FALSE)
Retrieve item ID by name.
SQL database abstraction object with smart query caching.
Factory which extracts all defined privileges from the database.
static GetMyCaller()
Get string with file and line number for call to current function.
Set of privileges used to access resource information or other parts of the system.
ItemExists($ItemId, $IgnoreSqlCondition=FALSE)
Check that item exists with specified ID.
static GetBacktraceAsString($IncludeArgs=TRUE)
Get backtrace as a string.
ClearCaches()
Clear item information caches.
Represents a "resource" in CWIS.
static Singularize($Word)
Singularize an English word.
Common factory class for item manipulation.
NameIsInUse($Name, $IgnoreCase=FALSE)
Check whether item name is currently in use.
Factory for Resource objects.
CWIS-specific user class.
Convenience class for generating an HTML select/option form element.