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 
00255     function GetFieldsAsOptionList($OptionListName, $FieldTypes = NULL, 
00256             $SelectedFieldId = NULL, $IncludeNullOption = TRUE)
00257     {
00258         # retrieve requested fields
00259         $FieldNames = $this->GetFieldNames($FieldTypes);
00260 
00261         # begin HTML option list
00262         $Html = "<select name=\"".$OptionListName."\">\n";
00263         if ($IncludeNullOption)
00264         {
00265             $Html .= "<option value=\"-1\">--</option>\n";
00266         }
00267 
00268         # for each metadata field
00269         foreach ($FieldNames as $Id => $Name)
00270         {
00271             # add entry for field to option list
00272             $Html .= "<option value=\"".$Id."\"";
00273             if ($Id == $SelectedFieldId) {  $Html .= " selected";  }
00274             $Html .= ">".htmlspecialchars($Name)."</option>\n";
00275         }
00276 
00277         # end HTML option list
00278         $Html .= "</select>\n";
00279 
00280         # return constructed HTML to caller
00281         return $Html;
00282     }
00283 
00284     # retrieve array of field types (enumerated type => field name)
00285     function GetFieldTypes()
00286     {
00287         return MetadataField::$FieldTypeDBEnums;
00288     }
00289 
00290     # retrieve array of field types that user can create (enumerated type => field name)
00291     function GetAllowedFieldTypes()
00292     {
00293         return MetadataField::$FieldTypeDBAllowedEnums;
00294     }
00295 
00296     # remove all metadata field associations for a given qualifier
00297     function RemoveQualifierAssociations($QualifierIdOrObject)
00298     {
00299         # sanitize qualifier ID or grab it from object
00300         $QualifierIdOrObject = is_object($QualifierIdOrObject)
00301                 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
00302 
00303         # delete intersection records from database
00304         $this->DB->Query("DELETE FROM FieldQualifierInts WHERE QualifierId = "
00305                          .$QualifierIdOrObject);
00306     }
00307 
00308     # return whether qualifier is in use by metadata field
00309     function QualifierIsInUse($QualifierIdOrObject)
00310     {
00311         # sanitize qualifier ID or grab it from object
00312         $QualifierIdOrObject = is_object($QualifierIdOrObject)
00313                 ? $QualifierIdOrObject->Id() : intval($QualifierIdOrObject);
00314 
00315         # determine whether any fields use qualifier as default
00316         $DefaultCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM MetadataFields"
00317                                          ." WHERE DefaultQualifier = ".$QualifierIdOrObject,
00318                                          "RecordCount");
00319 
00320         # determine whether any fields are associated with qualifier
00321         $AssociationCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM FieldQualifierInts"
00322                                          ." WHERE QualifierId = ".$QualifierIdOrObject,
00323                                          "RecordCount");
00324 
00325         # report whether qualifier is in use based on defaults and associations
00326         return (($DefaultCount + $AssociationCount) > 0) ? TRUE : FALSE;
00327     }
00328 
00329     # move fields up or down in field order
00330     function MoveUpInOrder($FieldIdOrObj, $OrderType)
00331     {
00332         $this->MoveFieldInOrder($FieldIdOrObj, $OrderType, FALSE);
00333     }
00334     function MoveDownInOrder($FieldIdOrObj, $OrderType)
00335     {
00336         $this->MoveFieldInOrder($FieldIdOrObj, $OrderType, TRUE);
00337     }
00338 
00339     # return highest field ID currently in use
00340     function GetHighestFieldId() {  return $this->GetHighestItemId();  }
00341 
00349     static function StdNameToFieldMapping($MappedName, $FieldId = NULL)
00350     {
00351         if ($FieldId !== NULL)
00352         {
00353             self::$FieldMappings[$MappedName] = $FieldId;
00354         }
00355         return isset(self::$FieldMappings[$MappedName]) 
00356                 ? self::$FieldMappings[$MappedName] : NULL;
00357     }
00358 
00365     static function FieldToStdNameMapping($FieldId)
00366     {
00367         foreach (self::$FieldMappings as $MappedName => $MappedFieldId)
00368         {
00369             if ($MappedFieldId == $FieldId)
00370             {
00371                 return $MappedName;
00372             }
00373         }
00374         return NULL;
00375     }
00376 
00384     function GetFieldByMappedName($MappedName)
00385     {
00386         return ($this->StdNameToFieldMapping($MappedName) == NULL) ? NULL
00387                 : $this->GetField($this->StdNameToFieldMapping($MappedName));
00388     }
00389 
00390 
00391     # ---- PRIVATE INTERFACE -------------------------------------------------
00392 
00393     private $FieldCompareType;
00394     private $FieldOrderError;
00395     private $CachingOn;
00396     private static $FieldMappings;
00397 
00398     private function MoveFieldInOrder($FieldIdOrObj, $OrderType, $MoveFieldDown)
00399     {
00400         # grab field ID
00401         $FieldId = is_object($FieldIdOrObj) ? $Field->Id() : $FieldIdOrObj;
00402 
00403         # retrieve array of fields
00404         $Fields = $this->GetFields(NULL, $OrderType);
00405 
00406         # reverse array of fields if we are moving field down
00407         if ($MoveFieldDown)
00408         {
00409             $Fields = array_reverse($Fields);
00410         }
00411 
00412         # for each field in order
00413         $PreviousField = NULL;
00414         foreach ($Fields as $Field)
00415         {
00416             # if field is the field to be moved
00417             if ($Field->Id() == $FieldId)
00418             {
00419                 # if we have a previous field
00420                 if ($PreviousField !== NULL)
00421                 {
00422                     # swap field with previous field according to order type
00423                     $TempVal = $Field->OrderPosition($OrderType);
00424                     $Field->OrderPosition($OrderType, $PreviousField->OrderPosition($OrderType));
00425                     $PreviousField->OrderPosition($OrderType, $TempVal);
00426                 }
00427             }
00428 
00429             # save field for next iteration
00430             $PreviousField = $Field;
00431         }
00432     }
00433 }
00434 
00435 ?>