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