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 ?>