MetadataSchema.php
Go to the documentation of this file.
00001 <?PHP 00002 00003 # 00004 # FILE: MetadataSchema.php 00005 # 00006 # Copyright 2002-2010 Edward Almasy and Internet Scout 00007 # http://scout.wisc.edu 00008 # 00009 00010 class MetadataSchema extends ItemFactory { 00011 00012 # ---- PUBLIC INTERFACE -------------------------------------------------- 00013 00014 # types of field ordering 00015 const MDFORDER_DISPLAY = 1; 00016 const MDFORDER_EDITING = 2; 00017 const MDFORDER_ALPHABETICAL = 3; 00018 00019 # metadata field types 00020 # (must parallel MetadataFields.FieldType declaration in install/CreateTables.sql 00021 # and MetadataField::$FieldTypeDBEnums declaration below) 00022 const MDFTYPE_TEXT = 1; 00023 const MDFTYPE_PARAGRAPH = 2; 00024 const MDFTYPE_NUMBER = 4; 00025 const MDFTYPE_DATE = 8; 00026 const MDFTYPE_TIMESTAMP = 16; 00027 const MDFTYPE_FLAG = 32; 00028 const MDFTYPE_TREE = 64; 00029 const MDFTYPE_CONTROLLEDNAME = 128; 00030 const MDFTYPE_OPTION = 256; 00031 const MDFTYPE_USER = 512; 00032 const MDFTYPE_IMAGE = 1024; 00033 const MDFTYPE_FILE = 2048; 00034 const MDFTYPE_URL = 4096; 00035 const MDFTYPE_POINT = 8192; 00036 00037 # error status codes 00038 const MDFSTAT_OK = 1; 00039 const MDFSTAT_DUPLICATENAME = 2; 00040 const MDFSTAT_DUPLICATEDBCOLUMN = 4; 00041 const MDFSTAT_ILLEGALNAME = 8; 00042 const MDFSTAT_FIELDDOESNOTEXIST = 16; 00043 00044 # object constructor 00045 function MetadataSchema() 00046 { 00047 # set up item factory base class 00048 $this->ItemFactory( 00049 "MetadataField", "MetadataFields", "FieldId", "FieldName"); 00050 00051 # start with field info caching enabled 00052 $this->CachingOn = TRUE; 00053 } 00054 00055 # turn internal caching of field info on or off 00056 function CacheData($NewValue) 00057 { 00058 $this->CachingOn = $NewValue; 00059 } 00060 00061 # add new metadata field 00062 function AddField($FieldName, $FieldType, $Optional = TRUE, $DefaultValue = NULL) 00063 { 00064 # create new field 00065 $Field = new MetadataField(NULL, $FieldName, $FieldType, $Optional, $DefaultValue); 00066 00067 # save error code if create failed and return NULL 00068 if ($Field->Status() != MetadataSchema::MDFSTAT_OK) 00069 { 00070 $this->ErrorStatus = $Field->Status(); 00071 $Field = NULL; 00072 } 00073 00074 # return new field to caller 00075 return $Field; 00076 } 00077 00078 # delete metadata field 00079 function DropField($FieldId) 00080 { 00081 $Field = new MetadataField($FieldId); 00082 $Field->Drop(); 00083 } 00084 00085 # retrieve field by ID 00086 function GetField($FieldId) 00087 { 00088 static $Fields; 00089 00090 # if caching is off or field is already loaded 00091 if (($this->CachingOn != TRUE) || !isset($Fields[$FieldId])) 00092 { 00093 # retrieve field 00094 $Fields[$FieldId] = new MetadataField($FieldId); 00095 } 00096 00097 # return field to caller 00098 return $Fields[$FieldId]; 00099 } 00100 00107 function GetFieldByName($FieldName, $IgnoreCase = FALSE) 00108 { 00109 $FieldId = $this->GetFieldIdByName($FieldName, $IgnoreCase); 00110 return ($FieldId === NULL) ? NULL : $this->GetField($FieldId); 00111 } 00112 00120 function GetFieldIdByName($FieldName, $IgnoreCase = FALSE) 00121 { 00122 static $FieldIdsByName; 00123 00124 # if caching is off or field ID is already loaded 00125 if (($this->CachingOn != TRUE) || !isset($FieldIdsByName[$FieldName])) 00126 { 00127 # retrieve field ID from DB 00128 $Condition = $IgnoreCase 00129 ? "WHERE LOWER(FieldName) = '".addslashes(strtolower($FieldName))."'" 00130 : "WHERE FieldName = '".addslashes($FieldName)."'"; 00131 $FieldIdsByName[$FieldName] = $this->DB->Query( 00132 "SELECT FieldId FROM MetadataFields ".$Condition, "FieldId"); 00133 } 00134 00135 return $FieldIdsByName[$FieldName]; 00136 } 00137 00138 # check whether field with specified name exists 00139 function FieldExists($FieldName) { return $this->NameIsInUse($FieldName); } 00140 00141 # retrieve array of fields 00142 function GetFields($FieldTypes = NULL, $OrderType = NULL, 00143 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE) 00144 { 00145 # create empty array to pass back 00146 $Fields = array(); 00147 00148 # for each field type in database 00149 if ($IncludeTempFields && $IncludeDisabledFields) 00150 { 00151 $this->DB->Query("SELECT FieldId, FieldType FROM MetadataFields"); 00152 } 00153 else 00154 { 00155 if ($IncludeTempFields) 00156 { 00157 $this->DB->Query("SELECT FieldId, FieldType FROM MetadataFields WHERE Enabled != 0"); 00158 } 00159 elseif ($IncludeDisabledFields) 00160 { 00161 $this->DB->Query("SELECT FieldId, FieldType FROM MetadataFields WHERE FieldId >= 0"); 00162 } 00163 else 00164 { 00165 $this->DB->Query("SELECT FieldId, FieldType FROM MetadataFields WHERE FieldId >= 0 AND Enabled != 0"); 00166 } 00167 } 00168 while ($Record = $this->DB->FetchRow()) 00169 { 00170 # if no specific type requested or if field is of requested type 00171 if (($FieldTypes == NULL) 00172 || (MetadataField::$FieldTypePHPEnums[$Record["FieldType"]] & $FieldTypes)) 00173 { 00174 # create field object and add to array to be passed back 00175 $Fields[$Record["FieldId"]] = new MetadataField($Record["FieldId"]); 00176 } 00177 } 00178 00179 # if field sorting requested 00180 if ($OrderType !== NULL) 00181 { 00182 # sort field array by requested order type 00183 $this->FieldCompareType = $OrderType; 00184 $this->FieldOrderError = FALSE; 00185 uasort($Fields, array($this, "CompareFieldOrder")); 00186 00187 # if field order error detected 00188 if ($this->FieldOrderError) 00189 { 00190 # repair (reset) field order 00191 $OrderIndex = 1; 00192 foreach ($Fields as $Field) 00193 { 00194 $Field->OrderPosition($OrderType, $OrderIndex); 00195 $OrderIndex++; 00196 } 00197 } 00198 } 00199 00200 # return array of field objects to caller 00201 return $Fields; 00202 } 00203 00204 # callback function for sorting fields 00205 function CompareFieldOrder($FieldA, $FieldB) 00206 { 00207 if ($this->FieldCompareType == MetadataSchema::MDFORDER_ALPHABETICAL) 00208 { 00209 return ($FieldA->Name() < $FieldB->Name()) ? -1 : 1; 00210 } 00211 else 00212 { 00213 if ($FieldA->OrderPosition($this->FieldCompareType) 00214 == $FieldB->OrderPosition($this->FieldCompareType)) 00215 { 00216 $this->FieldOrderError = TRUE; 00217 return 0; 00218 } 00219 else 00220 { 00221 return ($FieldA->OrderPosition($this->FieldCompareType) 00222 < $FieldB->OrderPosition($this->FieldCompareType)) ? -1 : 1; 00223 } 00224 } 00225 } 00226 00227 function GetFieldNames($FieldTypes = NULL, $OrderType = NULL, 00228 $IncludeDisabledFields = FALSE, $IncludeTempFields = FALSE) 00229 { 00230 global $DB; 00231 00232 $FieldNames=array(); 00233 $Fields = $this->GetFields($FieldTypes, $OrderType, $IncludeDisabledFields, $IncludeTempFields); 00234 00235 foreach($Fields as $Field) 00236 { 00237 $DB->Query("SELECT FieldName FROM MetadataFields WHERE FieldId=".$Field->Id()); 00238 $FieldNames[ $Field->Id() ] = $DB->FetchField("FieldName"); 00239 } 00240 00241 return $FieldNames; 00242 } 00243 00253 function GetFieldsAsOptionList( 00254 $OptionListName, $FieldTypes = NULL, $SelectedFieldId = NULL) 00255 { 00256 # retrieve requested fields 00257 $FieldNames = $this->GetFieldNames($FieldTypes); 00258 00259 # begin HTML option list 00260 $Html = "<select name=\"".$OptionListName."\">\n"; 00261 $Html .= "<option value=\"-1\">--</option>\n"; 00262 00263 # for each metadata field 00264 foreach ($FieldNames as $Id => $Name) 00265 { 00266 # add entry for field to option list 00267 $Html .= "<option value=\"".$Id."\""; 00268 if ($Id == $SelectedFieldId) { $Html .= " selected"; } 00269 $Html .= ">".htmlspecialchars($Name)."</option>\n"; 00270 } 00271 00272 # end HTML option list 00273 $Html .= "</select>\n"; 00274 00275 # return constructed HTML to caller 00276 return $Html; 00277 } 00278 00279 # retrieve array of field types (enumerated type => field name) 00280 function GetFieldTypes() 00281 { 00282 return MetadataField::$FieldTypeDBEnums; 00283 } 00284 00285 # retrieve array of field types that user can create (enumerated type => field name) 00286 function GetAllowedFieldTypes() 00287 { 00288 return MetadataField::$FieldTypeDBAllowedEnums; 00289 } 00290 00291 # remove all metadata field associations for a given qualifier 00292 function RemoveQualifierAssociations($QualifierIdOrObject) 00293 { 00294 # sanitize qualifier ID or grab it from object 00295 $QualifierIdOrObject = is_object($QualifierIdOrObject) 00296 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject); 00297 00298 # delete intersection records from database 00299 $this->DB->Query("DELETE FROM FieldQualifierInts WHERE QualifierId = " 00300 .$QualifierIdOrObject); 00301 } 00302 00303 # return whether qualifier is in use by metadata field 00304 function QualifierIsInUse($QualifierIdOrObject) 00305 { 00306 # sanitize qualifier ID or grab it from object 00307 $QualifierIdOrObject = is_object($QualifierIdOrObject) 00308 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject); 00309 00310 # determine whether any fields use qualifier as default 00311 $DefaultCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM MetadataFields" 00312 ." WHERE DefaultQualifier = ".$QualifierIdOrObject, 00313 "RecordCount"); 00314 00315 # determine whether any fields are associated with qualifier 00316 $AssociationCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM FieldQualifierInts" 00317 ." WHERE QualifierId = ".$QualifierIdOrObject, 00318 "RecordCount"); 00319 00320 # report whether qualifier is in use based on defaults and associations 00321 return (($DefaultCount + $AssociationCount) > 0) ? TRUE : FALSE; 00322 } 00323 00324 # move fields up or down in field order 00325 function MoveUpInOrder($FieldIdOrObj, $OrderType) 00326 { 00327 $this->MoveFieldInOrder($FieldIdOrObj, $OrderType, FALSE); 00328 } 00329 function MoveDownInOrder($FieldIdOrObj, $OrderType) 00330 { 00331 $this->MoveFieldInOrder($FieldIdOrObj, $OrderType, TRUE); 00332 } 00333 00334 # return highest field ID currently in use 00335 function GetHighestFieldId() { return $this->GetHighestItemId(); } 00336 00344 static function StdNameToFieldMapping($MappedName, $FieldId = NULL) 00345 { 00346 if ($FieldId !== NULL) 00347 { 00348 self::$FieldMappings[$MappedName] = $FieldId; 00349 } 00350 return isset(self::$FieldMappings[$MappedName]) 00351 ? self::$FieldMappings[$MappedName] : NULL; 00352 } 00353 00360 static function FieldToStdNameMapping($FieldId) 00361 { 00362 foreach (self::$FieldMappings as $MappedName => $MappedFieldId) 00363 { 00364 if ($MappedFieldId == $FieldId) 00365 { 00366 return $MappedName; 00367 } 00368 } 00369 return NULL; 00370 } 00371 00379 function GetFieldByMappedName($MappedName) 00380 { 00381 return ($this->StdNameToFieldMapping($MappedName) == NULL) ? NULL 00382 : $this->GetField($this->StdNameToFieldMapping($MappedName)); 00383 } 00384 00385 00386 # ---- PRIVATE INTERFACE ------------------------------------------------- 00387 00388 private $FieldCompareType; 00389 private $FieldOrderError; 00390 private $CachingOn; 00391 private static $FieldMappings; 00392 00393 private function MoveFieldInOrder($FieldIdOrObj, $OrderType, $MoveFieldDown) 00394 { 00395 # grab field ID 00396 $FieldId = is_object($FieldIdOrObj) ? $Field->Id() : $FieldIdOrObj; 00397 00398 # retrieve array of fields 00399 $Fields = $this->GetFields(NULL, $OrderType); 00400 00401 # reverse array of fields if we are moving field down 00402 if ($MoveFieldDown) 00403 { 00404 $Fields = array_reverse($Fields); 00405 } 00406 00407 # for each field in order 00408 $PreviousField = NULL; 00409 foreach ($Fields as $Field) 00410 { 00411 # if field is the field to be moved 00412 if ($Field->Id() == $FieldId) 00413 { 00414 # if we have a previous field 00415 if ($PreviousField !== NULL) 00416 { 00417 # swap field with previous field according to order type 00418 $TempVal = $Field->OrderPosition($OrderType); 00419 $Field->OrderPosition($OrderType, $PreviousField->OrderPosition($OrderType)); 00420 $PreviousField->OrderPosition($OrderType, $TempVal); 00421 } 00422 } 00423 00424 # save field for next iteration 00425 $PreviousField = $Field; 00426 } 00427 } 00428 } 00429 00430 ?>