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 77 public function __construct($SchemaId = self::SCHEMAID_DEFAULT)
79 # set up item factory base class 80 parent::__construct(
"MetadataField",
"MetadataFields",
81 "FieldId",
"FieldName", FALSE,
82 "SchemaId = ".intval($SchemaId));
84 # make sure schema info cache is loaded 85 if (self::$ValueCache === NULL)
87 $this->DB->Query(
"SELECT * FROM MetadataSchemas");
88 self::$ValueCache = array();
89 foreach ($this->DB->FetchRows() as $Row)
91 self::$ValueCache[$Row[
"SchemaId"]] = $Row;
95 # if standard field mappings have not yet been loaded 96 if (!isset(self::$FieldMappings))
98 # load metadata field IDs to check against 99 $this->DB->Query(
"SELECT SchemaId, FieldId" 100 .
" FROM MetadataFields");
101 $FieldSchemaIds = $this->DB->FetchColumn(
"SchemaId",
"FieldId");
103 # for each standard field mapping 104 $this->DB->Query(
"SELECT * FROM StandardMetadataFieldMappings");
105 foreach ($this->DB->FetchRows() as $Row)
107 # if mapping is for a valid field in appropriate schema 108 if (isset($FieldSchemaIds[$Row[
"FieldId"]])
109 && ($FieldSchemaIds[$Row[
"FieldId"]] == $Row[
"SchemaId"]))
112 self::$FieldMappings[$Row[
"SchemaId"]][$Row[
"Name"]] =
118 throw new Exception(
"Standard field mapping for" 119 .
" \"".$Row[
"Name"].
"\" found with" 120 .
" invalid schema/field ID combination" 121 .
" (".$Row[
"SchemaId"].
"/".$Row[
"FieldId"].
").");
126 # make sure specified schema ID is valid 127 if (!isset(self::$ValueCache[$SchemaId]))
129 throw new InvalidArgumentException(
"Attempt to load metadata schema" 130 .
" with invalid ID (".$SchemaId.
") at " 131 .StdLib::GetMyCaller().
".");
134 # load schema info from cache 135 $Info = self::$ValueCache[$SchemaId];
136 $this->
Id = $SchemaId;
140 $this->
ViewPage = $Info[
"ViewPage"];
141 if (!isset(self::$FieldMappings[$this->
Id]))
143 self::$FieldMappings[$this->Id] = array();
158 # retrieve all constants for class 159 $Reflect =
new ReflectionClass(get_class());
160 $Constants = $Reflect->getConstants();
163 foreach ($Constants as $CName => $CValue)
165 # if value matches and prefix (if supplied) matches 166 if (($CValue == $Value)
167 && (($Prefix === NULL) || (strpos($CName, $Prefix) === 0)))
169 # return name to caller 174 # report to caller that no matching constant was found 200 $ResourceName = NULL)
202 # supply privilege settings if none provided 203 if ($AuthorPrivs === NULL) { $AuthorPrivs =
new PrivilegeSet(); }
204 if ($EditPrivs === NULL) { $EditPrivs =
new PrivilegeSet(); }
205 if ($ViewPrivs === NULL) { $ViewPrivs =
new PrivilegeSet(); }
207 # add schema to database 209 if (strtoupper($Name) ==
"RESOURCES")
211 $Id = self::SCHEMAID_DEFAULT;
213 elseif (strtoupper($Name) ==
"USER")
215 $Id = self::SCHEMAID_USER;
219 $Id =
$DB->Query(
"SELECT SchemaId FROM MetadataSchemas" 220 .
" ORDER BY SchemaId DESC LIMIT 1",
"SchemaId") + 1;
222 $DB->Query(
"INSERT INTO MetadataSchemas" 223 .
" (SchemaId, Name, ViewPage," 224 .
" AuthoringPrivileges, EditingPrivileges, ViewingPrivileges)" 225 .
" VALUES (".intval($Id).
"," 226 .
"'".addslashes($Name).
"'," 227 .
"'".
$DB->EscapeString($ViewPage).
"'," 228 .
"'".
$DB->EscapeString($AuthorPrivs->Data()).
"'," 229 .
"'".
$DB->EscapeString($EditPrivs->Data()).
"'," 230 .
"'".
$DB->EscapeString($ViewPrivs->Data()).
"')");
232 # clear schema data cache so it will be reloaded 233 self::$ValueCache = NULL;
235 # construct the new schema 238 # set schema name if none supplied 241 $Schema->Name(
"Metadata Schema ".$Id);
244 # set the resource name if one is supplied 245 if ($ResourceName === NULL)
249 $Schema->ResourceName($ResourceName);
251 # create display and edit orders 255 # return the new schema 265 # delete resources associated with schema 267 $ResourceIds = $RFactory->GetItemIds();
268 foreach ($ResourceIds as $ResourceId)
270 $Resource =
new Resource($ResourceId);
274 # unmap all the mapped fields 275 $MappedNames = array_keys(self::$FieldMappings[$this->
Id]);
276 foreach ($MappedNames as $MappedName)
281 # delete fields associated with schema 282 $Fields = $this->
GetFields(NULL, NULL, TRUE, TRUE);
283 foreach ($Fields as $FieldId => $Field)
288 # delete metadata field orders associated with schema 294 # remove schema info from database 295 $this->DB->Query(
"DELETE FROM MetadataSchemas WHERE SchemaId = " 306 if ($SchemaId === NULL) {
return FALSE; }
308 $DB->Query(
"SELECT * FROM MetadataSchemas" 309 .
" WHERE SchemaId = ".intval($SchemaId));
310 return (
$DB->NumRowsSelected() > 0) ? TRUE : FALSE;
320 # return value to caller 321 return intval($this->
Id);
343 $AName = $this->
UpdateValue(
"AbbreviatedName", $NewValue);
346 $AName = strtoupper(substr($this->
Name(), 0, 1));
358 $RName = $this->
UpdateValue(
"ResourceName", $NewValue);
361 $RName = self::RESOURCENAME_DEFAULT;
383 # if new privileges supplied 384 if ($NewValue !== NULL)
386 # store new privileges in database 387 $this->
UpdateValue(
"AuthoringPrivileges", $NewValue->Data());
391 # return current value to caller 392 return $this->AuthoringPrivileges;
402 # if new privileges supplied 403 if ($NewValue !== NULL)
405 # store new privileges in database 406 $this->
UpdateValue(
"EditingPrivileges", $NewValue->Data());
410 # return current value to caller 411 return $this->EditingPrivileges;
421 # if new privileges supplied 422 if ($NewValue !== NULL)
424 # store new privileges in database 425 $this->
UpdateValue(
"ViewingPrivileges", $NewValue->Data());
429 # return current value to caller 430 return $this->ViewingPrivileges;
442 # get authoring privilege set for schema 445 # user can author if privileges are greater than resource set 446 $CanAuthor = $AuthorPrivs->MeetsRequirements($User);
448 # allow plugins to modify result of permission check 449 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
450 "EVENT_RESOURCE_AUTHOR_PERMISSION_CHECK", array(
453 "CanAuthor" => $CanAuthor));
454 $CanAuthor = $SignalResult[
"CanAuthor"];
456 # report back to caller whether user can author field 469 # get editing privilege set for schema 472 # user can edit if privileges are greater than resource set 473 $CanEdit = $EditPrivs->MeetsRequirements($User);
475 # allow plugins to modify result of permission check 476 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
477 "EVENT_RESOURCE_EDIT_PERMISSION_CHECK", array(
480 "CanEdit" => $CanEdit,
481 "Schema" => $this, ));
482 $CanEdit = $SignalResult[
"CanEdit"];
484 # report back to caller whether user can edit field 497 # get viewing privilege set for schema 500 # user can view if privileges are greater than resource set 501 $CanView = $ViewPrivs->MeetsRequirements($User);
503 # allow plugins to modify result of permission check 504 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
505 "EVENT_RESOURCE_VIEW_PERMISSION_CHECK", array(
508 "CanView" => $CanView,
509 "Schema" => $this, ));
510 $CanView = $SignalResult[
"CanView"];
512 # report back to caller whether user can view field 523 # get the query/GET parameters for the view page 524 $Query = parse_url($this->
ViewPage(), PHP_URL_QUERY);
526 # the URL couldn't be parsed 527 if (!is_string($Query))
532 # parse the GET parameters out of the query string 533 $GetVars = ParseQueryString($Query);
535 # search for the ID parameter 536 $Result = array_search(
"\$ID", $GetVars);
538 return $Result !== FALSE ? $Result : NULL;
555 # get the query/GET parameters for the view page 556 $Query = parse_url($this->
ViewPage(), PHP_URL_QUERY);
558 # can't perform matching if the URL couldn't be parsed 559 if (!is_string($Query))
564 # parse the GET parameters out of the query string 565 $GetVars = ParseQueryString($Query);
567 # now, get the query/GET parameters from the path given 568 $PathQuery = parse_url($Path, PHP_URL_QUERY);
570 # can't perform matching if the URL couldn't be parsed 571 if (!is_string($PathQuery))
576 # parse the GET parameters out of the path's query string 577 $PathGetVars = ParseQueryString($PathQuery);
579 # make sure the given path GET parameters contain at least the GET 580 # parameters from the view page and that all non-variable parameters are 581 # equal. the path GET parameters may contain more, which is okay 582 foreach ($GetVars as $GetVarName => $GetVarValue)
584 # there's a required parameter that is not included in the path GET 586 if (!array_key_exists($GetVarName, $PathGetVars))
591 # require the path's value to be equal to the view page's value if 592 # the view page's value is not a variable, 593 if ($PathGetVars[$GetVarName] != $GetVarValue
594 && (!strlen($GetVarValue) || $GetVarValue{0} !=
"$"))
600 # the path matches the view page path 614 $FieldName, $FieldType, $Optional = TRUE, $DefaultValue = NULL)
616 # clear any existing error messages 617 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
618 { unset($this->ErrorMsgs[__METHOD__]); }
624 $FieldName, $Optional, $DefaultValue);
626 catch (Exception $Exception)
628 $this->ErrorMsgs[__METHOD__][] = $Exception->getMessage();
632 # clear internal caches to make sure new field is recognized going forward 635 # return new field to caller 655 # clear loading status 657 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
658 { unset($this->ErrorMsgs[__METHOD__]); }
660 # check that file exists and is readable 661 if (!file_exists($FileName))
663 $this->ErrorMsgs[__METHOD__][] =
"Could not find XML file '" 667 elseif (!is_readable($FileName))
669 $this->ErrorMsgs[__METHOD__][] =
"Could not read from XML file '" 675 libxml_use_internal_errors(TRUE);
676 $XmlData = simplexml_load_file($FileName);
677 $Errors = libxml_get_errors();
678 libxml_use_internal_errors(FALSE);
681 if ($XmlData === FALSE)
683 # retrieve XML error messages 684 foreach ($Errors as $Err)
686 $ErrType = ($Err->level == LIBXML_ERR_WARNING) ?
"Warning" 687 : (($Err->level == LIBXML_ERR_WARNING) ?
"Error" 689 $this->ErrorMsgs[__METHOD__][] =
"XML ".$ErrType.
": ".$Err->message
690 .
" (".$Err->file.
":".$Err->line.
",".$Err->column.
")";
693 # else if no metadata fields found record error message 694 elseif (!count($XmlData->MetadataField))
696 $this->ErrorMsgs[__METHOD__][] =
"No metadata fields found.";
698 # else process metadata fields 701 # for each metadata field entry found 704 foreach ($XmlData->MetadataField as $FieldXml)
708 # pull out field type if present 709 if (isset($FieldXml->Type))
711 $FieldType =
"MetadataSchema::".$FieldXml->Type;
712 if (!defined($FieldType))
714 $FieldType =
"MetadataSchema::MDFTYPE_" 715 .strtoupper(preg_replace(
"/\\s+/",
"",
720 # if required values are missing 721 if (!isset($FieldXml->Name) || !isset($FieldXml->Type)
722 || !defined($FieldType))
724 # add error message about required value missing 725 if (!isset($FieldXml->Name))
727 $this->ErrorMsgs[__METHOD__][] =
728 "Field name not found (MetadataField #" 731 if (!isset($FieldXml->Type) || !defined($FieldType))
733 $this->ErrorMsgs[__METHOD__][] =
734 "Valid type not found for field '" 735 .$FieldXml->Name.
"' (MetadataField #" 739 # else if there is not already a field with this name 740 elseif (!$this->
NameIsInUse(trim($FieldXml->Name)))
743 $Field = $this->
AddField($FieldXml->Name, constant($FieldType));
745 # if field creation failed 748 # add any error message to our error list 750 foreach ($ErrorMsgs as $Msg)
752 $this->ErrorMsgs[__METHOD__][] =
758 # add field to list of created fields 761 # assume no vocabulary to load 764 # for other field attributes 765 foreach ($FieldXml as $MethodName => $Value)
767 # if tags look valid and have not already been set 768 if (method_exists($Field, $MethodName)
769 && ($MethodName !=
"Name")
770 && ($MethodName !=
"Type"))
772 # if tag indicates privilege set 773 if (preg_match(
"/^[a-z]+Privileges\$/i",
776 # save element for later processing 777 $PrivilegesToSet[$Field->Id()][$MethodName] = $Value;
781 # condense down any extraneous whitespace 782 $Value = preg_replace(
"/\s+/",
" ", trim($Value));
784 # set value for field 785 $Field->$MethodName($Value);
788 elseif ($MethodName ==
"VocabularyFile")
790 $VocabToLoad = $Value;
794 # save the temp ID so that any privileges to set 795 # can be mapped to the actual ID when the field is 797 $TempId = $Field->Id();
799 # make new field permanent 800 $Field->IsTempItem(FALSE);
802 # load any vocabularies 803 if ($VocabToLoad !== NULL)
805 $Field->LoadVocabulary($VocabToLoad);
808 # map privileges to set to the permanent field ID 809 if (isset($PrivilegesToSet) &&
810 isset($PrivilegesToSet[$TempId]) )
812 # copy the privileges over 813 $PrivilegesToSet[$Field->Id()] =
814 $PrivilegesToSet[$TempId];
816 # remove the values for the temp ID 817 unset($PrivilegesToSet[$TempId]);
823 # if we have schema-level privileges to set 824 if (count($XmlData->SchemaPrivileges))
826 foreach ($XmlData->SchemaPrivileges->children() as $PrivName => $PrivXml)
828 # if our current value for this privset is empty, 829 # take the one from the file 830 if ($this->$PrivName()->ComparisonCount() == 0)
832 # extract the values to set from the XML 833 $Value = $this->ConvertXmlToPrivilegeSet($PrivXml);
835 $this->$PrivName($Value);
840 # if we have privileges to set 841 if (isset($PrivilegesToSet))
843 # for each field with privileges 844 foreach ($PrivilegesToSet as $FieldId => $Privileges)
846 # load the field for which to set the privileges 849 # for each set of privileges for field 850 foreach ($Privileges as $MethodName => $Value)
852 # convert privilege value 853 $Value = $this->ConvertXmlToPrivilegeSet($Value);
855 # if conversion failed 858 # add resulting error messages to our list 860 "ConvertXmlToPrivilegeSet");
861 foreach ($ErrorMsgs as $Msg)
863 $this->ErrorMsgs[__METHOD__][] =
864 $Msg.
" (ConvertXmlToPrivilegeSet)";
869 # set value for field 870 $Field->$MethodName($Value);
876 # if errors were found during creation 877 if (array_key_exists(__METHOD__, $this->ErrorMsgs) || $TestRun)
879 # remove any fields that were created 888 # set owner for new fields (if supplied) 893 $Field->Owner($Owner);
897 # if there were standard field mappings included 898 if (isset($XmlData->StandardFieldMapping))
900 # for each standard field mapping found 901 foreach ($XmlData->StandardFieldMapping as $MappingXml)
903 # if required values are supplied 904 if (isset($MappingXml->Name)
905 && isset($MappingXml->StandardName))
907 # get ID for specified field 908 $FieldName = (string)$MappingXml->Name;
909 $StandardName = (
string)$MappingXml->StandardName;
912 # if field ID was found 913 if ($FieldId !== FALSE)
915 # set standard field mapping 917 $StandardName, $FieldId);
921 # log error about field not found 922 $this->ErrorMsgs[__METHOD__][] =
923 "Field not found with name '".$FieldName
924 .
"' to map to standard field name '" 930 # log error about missing value 931 if (!isset($MappingXml->Name))
933 $this->ErrorMsgs[__METHOD__][] =
934 "Field name missing for standard" 937 if (!isset($MappingXml->StandardName))
939 $this->ErrorMsgs[__METHOD__][] =
940 "Standard field name missing for" 941 .
" standard field mapping.";
949 # report success or failure based on whether errors were recorded 950 return (array_key_exists(__METHOD__, $this->ErrorMsgs)) ? FALSE : TRUE;
960 return $this->NewFields;
974 if ($Method === NULL)
976 return $this->ErrorMsgs;
980 if (!method_exists($this, $Method))
982 throw new Exception(
"Error messages requested for non-existent" 983 .
" method (".$Method.
").");
985 return array_key_exists(__CLASS__.
"::".$Method, $this->ErrorMsgs)
986 ? $this->ErrorMsgs[__CLASS__.
"::".$Method] : array();
1001 # assume field addition will fail 1002 $Field = self::MDFSTAT_ERROR;
1004 # add XML prefixes if needed 1006 if (!preg_match(
"/^<\?xml/i", $Xml))
1008 if (!preg_match(
"/^<document>/i", $Xml))
1010 $Xml =
"<document>".$Xml.
"</document>";
1012 $Xml =
"<?xml version='1.0'?".
">".$Xml;
1016 $XmlData = simplexml_load_string($Xml);
1018 # if required values are present 1019 if (is_object($XmlData)
1020 && isset($XmlData->Name)
1021 && isset($XmlData->Type)
1022 && constant(
"MetadataSchema::".$XmlData->Type))
1024 # create the metadata field 1027 constant(
"MetadataSchema::".$XmlData->Type));
1029 # if field creation succeeded 1032 # for other field attributes 1033 foreach ($XmlData as $MethodName => $Value)
1035 # if they look valid and have not already been set 1036 if (method_exists($Field, $MethodName)
1037 && ($MethodName !=
"Name")
1038 && ($MethodName !=
"Type"))
1040 # if tag indicates privilege set 1041 if (preg_match(
"/^[a-z]+Privileges\$/i",
1044 # save element for later processing 1045 $PrivilegesToSet[$MethodName] = $Value;
1049 # condense down any extraneous whitespace 1050 $Value = preg_replace(
"/\s+/",
" ", trim($Value));
1052 # set value for field 1053 $Field->$MethodName($Value);
1058 # make new field permanent 1059 $Field->IsTempItem(FALSE);
1061 # if we have privileges to set 1062 if (isset($PrivilegesToSet))
1064 # for each set of privileges for field 1065 foreach ($PrivilegesToSet as $MethodName => $Value)
1067 # convert privilege value 1068 $Value = $this->ConvertXmlToPrivilegeSet($Value);
1070 # if conversion failed 1071 if ($Value === NULL)
1073 # add resulting error messages to our list 1075 "ConvertXmlToPrivilegeSet");
1076 foreach ($ErrorMsgs as $Msg)
1078 $this->ErrorMsgs[__METHOD__][] =
1079 $Msg.
" (ConvertXmlToPrivilegeSet)";
1084 # set value for field 1085 $Field->$MethodName($Value);
1092 # return new field (if any) to caller 1103 $Field = $this->
GetField($FieldId);
1104 if ($Field === NULL)
1109 # verify that this field is not mapped prior to dropping it 1110 foreach (self::$FieldMappings[$this->
Id] as $Name => $FieldId)
1112 if ($Field->Id() == $FieldId)
1114 throw new Exception(
1115 "Attempt to delete ".$Field->Name()
1116 .
", which is mapped as the standard ".$Name
1117 .
" in the ".$this->
Name().
" Schema.");
1121 $GLOBALS[
"AF"]->SignalEvent(
"EVENT_PRE_FIELD_DELETE",
1122 array(
"FieldId" => $Field->Id()) );
1136 # convert field name to ID if necessary 1137 if (!is_numeric($FieldId))
1139 $FieldName = $FieldId;
1141 if ($FieldId === FALSE)
1143 throw new InvalidArgumentException(
"Attempt to retrieve field" 1144 .
" with unknown name (".$FieldName.
").");
1148 # if caching is off or field is not already loaded 1149 if (!isset(self::$FieldCache[$FieldId]))
1154 # if field was from a different schema, bail 1155 if (self::$FieldCache[$FieldId]->SchemaId() != $this->
Id())
1157 throw new InvalidArgumentException(
1158 "Attempt to retrieve a field from a different schema");
1161 return self::$FieldCache[$FieldId];
1176 return ($FieldId === FALSE) ? NULL : $this->
GetField($FieldId);
1198 return is_numeric($Field)
1216 public function GetFields($FieldTypes = NULL, $OrderType = NULL,
1217 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
1219 # create empty array to pass back 1222 # for each field type in database 1223 $this->DB->Query(
"SELECT FieldId, FieldType FROM MetadataFields" 1224 .
" WHERE SchemaId = ".intval($this->
Id)
1225 .(!$IncludeDisabledFields ?
" AND Enabled != 0" :
"")
1226 .(!$IncludeTempFields ?
" AND FieldId >= 0" :
""));
1227 while ($Record = $this->DB->FetchRow())
1229 # if field type is known 1232 # if no specific type requested or if field is of requested type 1233 if (($FieldTypes == NULL)
1237 # create field object and add to array to be passed back 1238 $Fields[$Record[
"FieldId"]] = $this->
GetField($Record[
"FieldId"]);
1243 # if field sorting requested 1244 if ($OrderType !== NULL)
1246 # update field comparison ordering if not set yet 1252 $this->FieldCompareType = $OrderType;
1254 # sort field array by requested order type 1255 uasort($Fields, array($this,
"CompareFieldOrder"));
1258 # return array of field objects to caller 1277 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE)
1279 $Fields = $this->
GetFields($FieldTypes, $OrderType,
1280 $IncludeDisabledFields, $IncludeTempFields);
1282 $FieldNames = array();
1283 foreach($Fields as $Field)
1285 $FieldNames[$Field->Id()] = $Field->Name();
1310 $SelectedFieldId = NULL, $IncludeNullOption = TRUE,
1311 $AddEntries = NULL, $AllowMultiple = FALSE, $Disabled = FALSE)
1313 # retrieve requested fields 1316 # transform field names to labels 1317 foreach ($FieldNames as $FieldId => $FieldName)
1319 $FieldNames[$FieldId] = $this->
GetField($FieldId)->GetDisplayName();
1322 # add in null entry if requested 1323 if ($IncludeNullOption)
1325 $FieldNames = array(
"" =>
"--") + $FieldNames;
1328 # add additional entries if supplied 1331 $FieldNames = $FieldNames + $AddEntries;
1334 # construct option list 1335 $OptList =
new HtmlOptionList($OptionListName, $FieldNames, $SelectedFieldId);
1336 $OptList->MultipleAllowed($AllowMultiple);
1337 $OptList->Disabled($Disabled);
1339 # return option list HTML to caller 1340 return $OptList->GetHtml();
1369 # sanitize qualifier ID or grab it from object 1370 $QualifierIdOrObject = is_object($QualifierIdOrObject)
1371 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
1373 # delete intersection records from database 1374 $this->DB->Query(
"DELETE FROM FieldQualifierInts" 1375 .
" WHERE QualifierId = ".$QualifierIdOrObject);
1385 # sanitize qualifier ID or grab it from object 1386 $QualifierIdOrObject = is_object($QualifierIdOrObject)
1387 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
1389 # determine whether any fields use qualifier as default 1390 $DefaultCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount" 1391 .
" FROM MetadataFields" 1392 .
" WHERE DefaultQualifier = ".$QualifierIdOrObject,
1395 # determine whether any fields are associated with qualifier 1396 $AssociationCount = $this->DB->Query(
"SELECT COUNT(*) AS RecordCount" 1397 .
" FROM FieldQualifierInts" 1398 .
" WHERE QualifierId = ".$QualifierIdOrObject,
1401 # report whether qualifier is in use based on defaults and associations 1402 return (($DefaultCount + $AssociationCount) > 0) ? TRUE : FALSE;
1424 if (func_num_args() > 1)
1426 if (!isset(self::$FieldMappings[$this->
Id][$MappedName])
1427 || (self::$FieldMappings[$this->
Id][$MappedName] != $FieldId))
1429 if (($FieldId !== NULL) && !$this->
FieldExists($FieldId))
1431 throw new InvalidArgumentException(
"Attempt to set" 1432 .
" standard field mapping to invalid field ID" 1436 # if a mapping is set and is not NULL 1437 if (isset(self::$FieldMappings[$this->
Id][$MappedName]))
1439 $this->DB->Query(
"DELETE FROM StandardMetadataFieldMappings" 1440 .
" WHERE SchemaId = '".addslashes($this->
Id)
1441 .
"' AND Name = '".addslashes($MappedName).
"'");
1442 unset(self::$FieldMappings[$this->
Id][$MappedName]);
1445 if ($FieldId !== NULL)
1447 $this->DB->Query(
"INSERT INTO StandardMetadataFieldMappings" 1448 .
" (SchemaId, Name, FieldId) VALUES ('" 1449 .addslashes($this->
Id).
"', '".addslashes($MappedName)
1450 .
"', '".addslashes($FieldId).
"')");
1451 self::$FieldMappings[$this->Id][$MappedName] = $FieldId;
1455 return isset(self::$FieldMappings[$this->
Id][$MappedName])
1456 ? self::$FieldMappings[$this->Id][$MappedName] : NULL;
1467 $MappedName = array_search($FieldId, self::$FieldMappings[$this->
Id]);
1468 return ($MappedName === FALSE) ? NULL : $MappedName;
1504 $this->DB->Query(
"SELECT * FROM MetadataFields" 1505 .
" WHERE Owner IS NOT NULL AND LENGTH(Owner) > 0" 1506 .
" AND SchemaId = ".intval($this->
Id));
1508 while (FALSE !== ($Row = $this->DB->FetchRow()))
1510 $FieldId = $Row[
"FieldId"];
1511 $Fields[$FieldId] = $this->
GetField($FieldId);
1524 # if we were given a field id, check to see if it exists 1525 self::LoadFieldNamesCache();
1526 if (is_numeric($Field) &&
1527 array_key_exists($Field, self::$FieldNamesCache))
1532 # otherwise, try to look up this field 1535 $FieldId = self::GetCanonicalFieldIdentifier($Field);
1536 return array_key_exists($FieldId, self::$FieldNamesCache) ?
1539 catch (Exception $e)
1541 # if we can't find the field, then it doesn't exist 1567 # check to make sure any specified schema is valid 1568 self::LoadFieldNamesCache();
1569 if ($SchemaId !== NULL)
1571 if (!isset(self::$SchemaNamesCache[$SchemaId]))
1573 throw new InvalidArgumentException(
1574 "Invalid schema ID supplied (".$SchemaId.
").");
1578 # if field object was passed in 1581 # check to make sure field ID is within any specified schema 1582 if (($SchemaId !== NULL) && ($Field->SchemaId() != $SchemaId))
1584 throw new Exception(
"Supplied field (".$Field
1585 .
") is not within specified " 1586 .self::$SchemaNamesCache[$SchemaId]
1587 .
" schema (".$SchemaId.
")");
1590 # return identifier from field to caller 1591 return $Field->Id();
1593 # else if field ID was passed in 1594 elseif (is_numeric($Field))
1596 # check to make sure field ID is valid 1597 if (!isset(self::$FieldNamesCache[$Field]))
1599 throw new InvalidArgumentException(
1600 "Invalid field ID supplied (".$Field.
").");
1603 # check to make sure field ID is within any specified schema 1604 if (($SchemaId !== NULL)
1605 && (self::$FieldNamesCache[$Field][
"SchemaId"] != $SchemaId))
1607 throw new Exception(
"Supplied field ID (".$Field
1608 .
") is not within specified " 1609 .self::$SchemaNamesCache[$SchemaId]
1610 .
" schema (".$SchemaId.
")");
1613 # return supplied field ID to caller 1616 # else if field name was passed in 1617 elseif (is_string($Field))
1619 # look for field with specified name 1620 $FieldName = trim($Field);
1622 array_walk(self::$FieldNamesCache,
1623 function($Value, $Key, $FieldName) use (&$FieldId, $SchemaId)
1625 if (($Value[
"QualifiedFieldName"] == $FieldName)
1626 && (($SchemaId === NULL)
1627 || ($Value[
"SchemaId"] == $SchemaId)))
1633 # if field with specified name not found 1634 if ($FieldId === NULL)
1636 # log error and look for field with unqualified version of name 1637 # (NOTE: This is a temporary measure, to be removed once errors 1638 # are no longer regularly showing up in the log, in favor 1639 # of immediately throwing an exception if the name was 1642 array_walk(self::$FieldNamesCache,
1643 function($Value, $Key, $FieldName) use (&$FieldId)
1645 if ($Value[
"FieldName"] == $FieldName)
1650 if ($FieldId === NULL)
1652 throw new Exception(
1653 "No field found with the name \"".$FieldName.
"\".");
1658 "No field found with the name \"".$FieldName.
"\"." 1663 # return found field ID to caller 1666 # else error out because we were given an illegal field argument 1669 throw new InvalidArgumentException(
1670 "Illegal field argument supplied.");
1691 $Id = self::GetCanonicalFieldIdentifier($Field);
1693 # if we have a label for this field, return it 1694 self::LoadFieldNamesCache();
1695 if (isset(self::$FieldNamesCache[$Id]))
1697 $DisplayName = strlen(self::$FieldNamesCache[$Id][
"FieldLabel"]) ?
1698 self::$FieldNamesCache[$Id][
"FieldLabel"] :
1699 self::$FieldNamesCache[$Id][
"FieldName"] ;
1700 return self::$FieldNamesCache[$Id][
"SchemaPrefix"].$DisplayName;
1703 # otherwise return a blank string 1714 $DB->Query(
"SELECT DISTINCT Name FROM StandardMetadataFieldMappings");
1715 return $DB->FetchColumn(
"Name");
1728 # start out assuming we won't find any values to translate 1729 $ReturnValues = array();
1731 # try to grab the specified field 1736 catch (Exception $e)
1738 # field no longer exists, so there are no values to translate 1739 return $ReturnValues;
1742 # if incoming value is not an array 1743 if (!is_array($Values))
1745 # convert incoming value to an array 1746 $Values = array($Values);
1749 # for each incoming value 1750 foreach ($Values as $Value)
1752 # look up value for index 1753 if ($Field->Type() == self::MDFTYPE_FLAG)
1755 # (for flag fields the value index (0 or 1) is used in Database) 1758 $ReturnValues[] =
"=".$Value;
1761 elseif ($Field->Type() == self::MDFTYPE_NUMBER)
1763 # (for flag fields the value index (0 or 1) is used in Database) 1766 $ReturnValues[] =
">=".$Value;
1769 elseif ($Field->Type() == self::MDFTYPE_USER)
1771 $User =
new CWUser(intval($Value));
1774 $ReturnValues[] =
"=".$User->Get(
"UserName");
1777 elseif ($Field->Type() == self::MDFTYPE_OPTION)
1779 if (!isset($PossibleFieldValues))
1781 $PossibleFieldValues = $Field->GetPossibleValues();
1784 if (isset($PossibleFieldValues[$Value]))
1786 $ReturnValues[] =
"=".$PossibleFieldValues[$Value];
1791 $NewValue = $Field->GetValueForId($Value);
1792 if ($NewValue !== NULL)
1794 $ReturnValues[] =
"=".$NewValue;
1799 # return array of translated values to caller 1800 return $ReturnValues;
1809 return array_keys(self::GetAllSchemaNames());
1819 $DB->Query(
"SELECT SchemaId, Name FROM MetadataSchemas");
1820 return $DB->FetchColumn(
"Name",
"SchemaId");
1830 # fetch IDs of all metadata schemas 1831 $SchemaIds = self::GetAllSchemaIds();
1833 # construct objects from the IDs 1835 foreach ($SchemaIds as $SchemaId)
1840 # return schemas to caller 1852 # list of priv types we'll be checking 1854 "AuthoringPrivileges",
1855 "EditingPrivileges",
1856 "ViewingPrivileges");
1858 # iterate over each schema 1859 foreach (self::GetAllSchemas() as $Schema)
1861 # see if the provided field is checked in any of the 1862 # schema-level privs, returning TRUE if so 1863 foreach ($PrivTypes as $PrivType)
1865 if ($Schema->$PrivType()->ChecksField($FieldId))
1871 # otherwise, iterate over all the field-level privs, returning true 1872 # if any of those check the provided field 1873 foreach ($Schema->GetFields() as $Field)
1875 foreach ($PrivTypes as $PrivType)
1877 if ($Field->$PrivType()->ChecksField($FieldId))
1885 # nothing checks this field, return FALSE 1897 $Id =
$DB->Query(
"SELECT SchemaId FROM MetadataSchemas" 1898 .
" WHERE Name = '".addslashes($Name).
"'",
"SchemaId");
1899 return ($Id === FALSE) ? NULL : $Id;
1909 if (is_callable($Callback))
1911 self::$OwnerListRetrievalFunction = $Callback;
1922 # if an owner list retrieval function and default schema exists 1923 if (self::$OwnerListRetrievalFunction
1924 && self::SchemaExistsWithId(self::SCHEMAID_DEFAULT))
1926 # retrieve the list of owners that currently exist 1927 $OwnerList = call_user_func(self::$OwnerListRetrievalFunction);
1929 # an array is expected 1930 if (is_array($OwnerList))
1934 # get each metadata field that is owned by a plugin 1935 $OwnedFields = $Schema->GetOwnedFields();
1937 # loop through each owned field 1938 foreach ($OwnedFields as $OwnedField)
1940 # the owner of the current field 1941 $Owner = $OwnedField->Owner();
1943 # if the owner of the field is in the list of owners that 1944 # currently exist, i.e., available plugins 1945 if (in_array($Owner, $OwnerList))
1947 # enable the field and reset its "enable on owner return" 1948 # flag if the "enable on owner return" flag is currently 1949 # set to true. in other words, re-enable the field since 1950 # the owner has returned to the list of existing owners 1951 if ($OwnedField->EnableOnOwnerReturn())
1953 $OwnedField->Enabled(TRUE);
1954 $OwnedField->EnableOnOwnerReturn(FALSE);
1958 # if the owner of the field is *not* in the list of owners 1959 # that currently exist, i.e., available plugins 1962 # first, see if the field is currently enabled since it 1963 # will determine whether the field is re-enabled when 1964 # the owner becomes available again 1965 $Enabled = $OwnedField->Enabled();
1967 # if the field is enabled, set its "enable on owner 1968 # return" flag to true and disable the field. nothing 1969 # needs to be done if the field is already disabled 1972 $OwnedField->EnableOnOwnerReturn($Enabled);
1973 $OwnedField->Enabled(FALSE);
1991 $this->FieldCompareDisplayOrder[$Field->Id()] = $Index++;
1998 $this->FieldCompareEditOrder[$Field->Id()] = $Index++;
2038 if ($this->FieldCompareType == self::MDFORDER_ALPHABETICAL)
2040 return ($FieldA->GetDisplayName() < $FieldB->GetDisplayName()) ? -1 : 1;
2043 if ($this->FieldCompareType == self::MDFORDER_EDITING)
2053 $PositionA = GetArrayValue($Order, $FieldA->Id(), 0);
2054 $PositionB = GetArrayValue($Order, $FieldB->Id(), 0);
2056 return $PositionA < $PositionB ? -1 : 1;
2065 self::$FieldCache = NULL;
2066 self::$FieldNamesCache = NULL;
2069 # ---- PRIVATE INTERFACE ------------------------------------------------- 2071 private $AuthoringPrivileges;
2072 private $EditingPrivileges;
2073 private $ErrorMsgs = array();
2074 private $FieldCompareType;
2076 private $NewFields = array();
2077 private $ViewingPrivileges;
2080 private static $FieldMappings;
2081 private static $ValueCache = NULL;
2083 private static $FieldCache = NULL;
2084 private static $FieldNamesCache;
2085 private static $SchemaNamesCache;
2102 private static function LoadFieldNamesCache()
2104 if (!isset(self::$FieldNamesCache))
2106 self::$SchemaNamesCache = self::GetAllSchemaNames();
2109 $DB->Query(
"SELECT SchemaId, FieldId, FieldName, Label FROM MetadataFields" 2110 # (NOTE: This ordering is a temporary measure, to be removed when the
2112 .
" ORDER BY SchemaId DESC");
2113 while ($Row =
$DB->FetchRow())
2115 $SchemaPrefix = ($Row[
"SchemaId"] == self::SCHEMAID_DEFAULT)
2116 ?
"" : self::$SchemaNamesCache[$Row[
"SchemaId"]].
": ";
2118 $TrimmedLabel = trim($Row[
"Label"]);
2119 $TrimmedName = trim($Row[
"FieldName"]);
2121 self::$FieldNamesCache[$Row[
"FieldId"]] = [
2122 "SchemaId" => $Row[
"SchemaId"],
2123 "SchemaPrefix" => $SchemaPrefix,
2124 "FieldName" => $TrimmedName,
2125 "QualifiedFieldName" => $SchemaPrefix.$TrimmedName,
2126 "FieldLabel" => $TrimmedLabel,
2139 private function ConvertXmlToPrivilegeSet($Xml)
2141 # clear any existing errors 2142 if (array_key_exists(__METHOD__, $this->ErrorMsgs))
2143 { unset($this->ErrorMsgs[__METHOD__]); }
2145 # create new privilege set 2148 # for each XML child 2149 foreach ($Xml as $Tag => $Value)
2151 # take action based on element name 2154 case "PrivilegeSet":
2155 # convert child data to new set 2156 $NewSet = $this->ConvertXmlToPrivilegeSet($Value);
2158 # add new set to our privilege set 2159 $PrivSet->AddSet($NewSet);
2162 case "AddCondition":
2163 # start with default values for optional parameters 2164 unset($ConditionField);
2165 $ConditionValue = NULL;
2166 $ConditionOperator =
"==";
2168 # pull out parameters 2169 foreach ($Value as $ParamName => $ParamValue)
2171 $ParamValue = trim($ParamValue);
2175 $ConditionField = $this->
GetField($ParamValue);
2176 if ($ConditionField === NULL)
2178 # record error about unknown field 2179 $this->ErrorMsgs[__METHOD__][] =
2180 "Unknown metadata field name found" 2181 .
" in AddCondition (".$ParamValue.
").";
2189 $ConditionValue = (string)$ParamValue;
2191 if ($ConditionValue ==
"NULL")
2193 $ConditionValue = NULL;
2195 elseif ($ConditionValue ==
"TRUE")
2197 $ConditionValue = TRUE;
2199 elseif ($ConditionValue ==
"FALSE")
2201 $ConditionValue = FALSE;
2206 $ConditionOperator = (string)$ParamValue;
2210 # record error about unknown parameter name 2211 $this->ErrorMsgs[__METHOD__][] =
2212 "Unknown tag found in AddCondition (" 2222 if (!isset($ConditionField))
2224 # record error about no field value 2225 $this->ErrorMsgs[__METHOD__][] =
2226 "No metadata field specified in AddCondition.";
2232 # if this is a vocabulary field 2235 if ($Factory !== NULL)
2237 # look up the id of the provided value 2238 $ConditionValue = $Factory->GetItemIdByName(
2241 # if none was found, error out 2242 if ($ConditionValue === NULL)
2244 $this->ErrorMsgs[__METHOD__][] =
2245 "Invalid value for field specified in AddCondition.";
2250 # add conditional to privilege set 2251 $PrivSet->AddCondition($ConditionField,
2252 $ConditionValue, $ConditionOperator);
2256 # strip any excess whitespace off of value 2257 $Value = trim($Value);
2259 # if child looks like valid method name 2260 if (method_exists(
"PrivilegeSet", $Tag))
2262 # convert constants if needed 2263 if (defined($Value))
2265 $Value = constant($Value);
2267 # convert booleans if needed 2268 elseif (strtoupper($Value) ==
"TRUE")
2272 elseif (strtoupper($Value) ==
"FALSE")
2276 # convert privilege flag names if needed and appropriate 2277 elseif (preg_match(
"/Privilege$/", $Tag))
2280 if (!isset($Privileges))
2283 $Privileges = $PFactory->GetPrivileges(TRUE, FALSE);
2285 if (in_array($Value, $Privileges))
2287 $Value = array_search($Value, $Privileges);
2291 # set value using child data 2292 $PrivSet->$Tag((
string)$Value);
2296 # record error about bad tag 2297 $this->ErrorMsgs[__METHOD__][] =
2298 "Unknown tag encountered (".$Tag.
").";
2307 # return new privilege set to caller 2320 return $this->DB->UpdateValue(
"MetadataSchemas", $ColumnName, $NewValue,
2321 "SchemaId = ".intval($this->
Id),
2322 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.