Resource.php

Go to the documentation of this file.
00001 <?PHP
00002 #
00003 #   FILE:  Resource.php
00004 #
00005 #   Part of the Collection Workflow Integration System (CWIS)
00006 #   Copyright 2011 Edward Almasy and Internet Scout Project
00007 #   http://scout.wisc.edu/
00008 #
00009 
00013 class Resource {
00014 
00015     # ---- PUBLIC INTERFACE --------------------------------------------------
00016 
00022     function Resource($ResourceId = NULL)
00023     {
00024         $this->DB = new SPTDatabase();
00025         $DB = $this->DB;
00026         $this->Schema = new MetadataSchema();
00027 
00028         # if resource ID supplied
00029         if ($ResourceId !== NULL)
00030         {
00031             # save resource ID
00032             $this->Id = intval($ResourceId);
00033 
00034             # locate resource in database
00035             $DB->Query("SELECT * FROM Resources WHERE ResourceId = ".$this->Id);
00036 
00037             # if unable to locate resource
00038             $Record = $DB->FetchRow();
00039             if ($Record == FALSE)
00040             {
00041                 # set status to -1 to indicate that creation failed
00042                 $this->LastStatus = -1;
00043             }
00044             else
00045             {
00046                 # load in attributes from database
00047                 $this->DBFields = $Record;
00048                 $this->CumulativeRating = $Record["CumulativeRating"];
00049 
00050                 # set status to 1 to indicate that creation succeeded
00051                 $this->LastStatus = 1;
00052             }
00053         }
00054         else
00055         {
00056             # clean out any temp resource records more than three days old
00057             $RFactory = new ResourceFactory();
00058             $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
00059 
00060             # lock DB tables to prevent next ID from being grabbed
00061             $DB->Query(
00062                 "LOCK TABLES Resources write, APUsers read, ".
00063                 "APSessions write, APSessionData write");
00064 
00065             # find next temp resource ID
00066             $this->Id = $RFactory->GetNextTempItemId();
00067 
00068             # write out new resource record with temp resource ID and user ID
00069             global $User;
00070             $DB->Query("INSERT INTO Resources (ResourceId, AddedById,"
00071                     ." LastModifiedById, DateLastModified, DateOfRecordCreation)"
00072                        ." VALUES (".$this->Id.", "
00073                                    .$User->Get("UserId").", "
00074                                    .$User->Get("UserId").", "
00075                                    ."NOW(), NOW())");
00076 
00077             # release DB tables
00078             $DB->Query("UNLOCK TABLES");
00079 
00080             # load in attributes from database
00081             $DB->Query("SELECT * FROM Resources WHERE ResourceId = ".$this->Id);
00082             $this->DBFields = $DB->FetchRow();
00083             $this->CumulativeRating = $this->DBFields["CumulativeRating"];
00084 
00085             # set any default values
00086             $Schema = new MetadataSchema();
00087             $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
00088                     |MetadataSchema::MDFTYPE_TEXT
00089                     |MetadataSchema::MDFTYPE_FLAG
00090                     |MetadataSchema::MDFTYPE_NUMBER
00091                     |MetadataSchema::MDFTYPE_POINT);
00092             foreach ($Fields as $Field)
00093             {
00094                 $DefaultValue = $Field->DefaultValue();
00095 
00096                 # flip option default values to get into the form that
00097                 # Resource::Set() expects
00098                 if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
00099                     && is_array($DefaultValue))
00100                 {
00101                     $DefaultValue = array_flip($DefaultValue);
00102                 }
00103 
00104                 $this->SetByField($Field, $DefaultValue);
00105             }
00106 
00107             # Update timestamps as required:
00108             $TimestampFields = $Schema->GetFields(
00109                 MetadataSchema::MDFTYPE_TIMESTAMP);
00110             foreach ($TimestampFields as $Field)
00111             {
00112                 if ($Field->UpdateMethod() ==
00113                     MetadataField::UPDATEMETHOD_ONRECORDCREATE)
00114                 {
00115                     $this->SetByField($Field, "now");
00116                 }
00117             }
00118 
00119             # signal resource creation
00120             $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
00121                     "Resource" => $this,
00122                     ));
00123 
00124             # set status to 1 to indicate that creation succeeded
00125             $this->LastStatus = 1;
00126         }
00127     }
00128 
00133     function Delete()
00134     {
00135         global $SysConfig;
00136 
00137         # signal that resource deletion is about to occur
00138         global $AF;
00139         $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
00140                 "Resource" => $this,
00141                 ));
00142 
00143         # grab list of classifications
00144         $Classifications = $this->Classifications();
00145 
00146         # delete resource/classification intersections
00147         $DB = $this->DB;
00148         $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
00149 
00150         # for each classification type
00151         foreach ($Classifications as $ClassType => $ClassesOfType)
00152         {
00153             # for each classification of that type
00154             foreach ($ClassesOfType as $ClassId => $ClassName)
00155             {
00156                 # recalculate resource count for classification
00157                 $Class = new Classification($ClassId);
00158                 $Class->RecalcResourceCount();
00159             }
00160         }
00161 
00162         # delete resource/name intersections
00163         $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
00164 
00165         # delete any associated images not in use by other resources
00166         $Fields = $this->Schema->GetFields(MetadataSchema::MDFTYPE_IMAGE);
00167         foreach ($Fields as $Field)
00168         {
00169             $ImageId = $DB->Query("SELECT `".$Field->DBFieldName()
00170                                   ."` FROM Resources WHERE ResourceId = ".$this->Id(),
00171                                   $Field->DBFieldName());
00172             if ($ImageId > 0)
00173             {
00174                 $ImageCount = $DB->Query("SELECT COUNT(*) AS ImageCount FROM Resources"
00175                                          ." WHERE ".$Field->DBFieldName()." = ".$ImageId,
00176                                          "ImageCount");
00177                 if ($ImageCount < 2)
00178                 {
00179                     $Image = new SPTImage($ImageId);
00180                     $Image->Delete();
00181                 }
00182             }
00183         }
00184 
00185         # delete any associated files
00186         $Factory = new FileFactory(NULL);
00187         $Files = $Factory->GetFilesForResource($this->Id());
00188         foreach ($Files as $File)
00189         {
00190             $File->Delete();
00191         }
00192 
00193         # delete resource record from database
00194         $DB->Query("DELETE FROM Resources WHERE ResourceId = ".$this->Id());
00195 
00196         # drop item from search engine and recommender system
00197         if ($SysConfig->SearchDBEnabled())
00198         {
00199             $SearchEngine = new SPTSearchEngine();
00200             $SearchEngine->DropItem($this->Id());
00201         }
00202         if ($SysConfig->RecommenderDBEnabled())
00203         {
00204             $Recommender = new SPTRecommender();
00205             $Recommender->DropItem($this->Id());
00206         }
00207 
00208         # delete any resource comments
00209         $DB->Query("DELETE FROM Messages WHERE ParentId = ".$this->Id);
00210     }
00211 
00216     function Status() {  return $this->LastStatus;  }
00217 
00222     function Id() {  return $this->Id;  }
00223 
00229     function IsTempResource($NewSetting = NULL)
00230     {
00231         # if new temp resource setting supplied
00232         if (!is_null($NewSetting))
00233         {
00234             # if caller requested to switch
00235             $DB = $this->DB;
00236             if ((($this->Id() < 0) && ($NewSetting == FALSE))
00237                     || (($this->Id() >= 0) && ($NewSetting == TRUE)))
00238             {
00239                 # lock DB tables to prevent next ID from being grabbed
00240                 $DB->Query("LOCK TABLES Resources write");
00241 
00242                 # get next resource ID as appropriate
00243                 $OldResourceId = $this->Id;
00244                 $Factory = new ResourceFactory();
00245                 if ($NewSetting == TRUE)
00246                 {
00247                     $this->Id = $Factory->GetNextTempItemId();
00248                 }
00249                 else
00250                 {
00251                     $this->Id = $Factory->GetNextItemId();
00252                 }
00253 
00254                 # change resource ID
00255                 $DB->Query("UPDATE Resources SET ResourceId = ".
00256                     $this->Id.  " WHERE ResourceId = ".$OldResourceId);
00257 
00258                 # release DB tables
00259                 $DB->Query("UNLOCK TABLES");
00260 
00261                 # change associations
00262                 unset($this->ClassificationCache);
00263                 $DB->Query("UPDATE ResourceClassInts SET ResourceId = ".
00264                     $this->Id.  " WHERE ResourceId = ".$OldResourceId);
00265                 unset($this->ControlledNameCache);
00266                 unset($this->ControlledNameVariantCache);
00267                 $DB->Query("UPDATE ResourceNameInts SET ResourceId = ".
00268                     $this->Id.  " WHERE ResourceId = ".$OldResourceId);
00269                 $DB->Query("UPDATE Files SET ResourceId = ".
00270                     $this->Id.  " WHERE ResourceId = ".$OldResourceId);
00271 
00272                 # signal event as appropriate
00273                 if ($NewSetting === FALSE)
00274                 {
00275                     $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_ADD", array(
00276                             "Resource" => $this,
00277                             ));
00278                 }
00279             }
00280         }
00281 
00282         # report to caller whether we are a temp resource
00283         return ($this->Id() < 0) ? TRUE : FALSE;
00284     }
00285 
00286 
00287     # --- Generic Attribute Retrieval Methods -------------------------------
00288 
00303     function Get($FieldNameOrObject, $ReturnObject = FALSE, $IncludeVariants = FALSE)
00304     {
00305         # load field object if needed
00306         $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
00307                 : $this->Schema->GetFieldByName($FieldNameOrObject);
00308 
00309         # return no value found if we don't have a valid field
00310         if ((get_class($Field) != "MetadataField")
00311                 || ($Field->Status() != MetadataSchema::MDFSTAT_OK))
00312                 {  return NULL;  }
00313 
00314         # grab database field name
00315         $DBFieldName = $Field->DBFieldName();
00316 
00317         # format return value based on field type
00318         switch ($Field->Type())
00319         {
00320             case MetadataSchema::MDFTYPE_TEXT:
00321             case MetadataSchema::MDFTYPE_PARAGRAPH:
00322             case MetadataSchema::MDFTYPE_NUMBER:
00323             case MetadataSchema::MDFTYPE_FLAG:
00324             case MetadataSchema::MDFTYPE_URL:
00325                 if (isset($this->DBFields[$DBFieldName]))
00326                 {
00327                     $ReturnValue = $this->DBFields[$DBFieldName];
00328                 }
00329                 else
00330                 {
00331                     $ReturnValue = NULL;
00332                 }
00333                 break;
00334 
00335             case MetadataSchema::MDFTYPE_POINT:
00336                 $ReturnValue = array("X" => $this->DBFields[$DBFieldName."X"],
00337                                      "Y" => $this->DBFields[$DBFieldName."Y"]);
00338                 break;
00339 
00340             case MetadataSchema::MDFTYPE_DATE:
00341                 $Date = new Date($this->DBFields[$DBFieldName."Begin"],
00342                                     $this->DBFields[$DBFieldName."End"],
00343                                     $this->DBFields[$DBFieldName."Precision"]);
00344                 if ($ReturnObject)
00345                 {
00346                     $ReturnValue = $Date;
00347                 }
00348                 else
00349                 {
00350                     $ReturnValue = $Date->Formatted();
00351                 }
00352                 break;
00353 
00354             case MetadataSchema::MDFTYPE_TIMESTAMP:
00355                 $ReturnValue = $this->DBFields[$DBFieldName];
00356                 break;
00357 
00358             case MetadataSchema::MDFTYPE_TREE:
00359                 # start with empty array
00360                 $ReturnValue = array();
00361 
00362                 # if classification cache has not been loaded
00363                 if (!isset($this->ClassificationCache))
00364                 {
00365                     # load all classifications associated with this resource into cache
00366                     $this->ClassificationCache = array();
00367                     $this->DB->Query("SELECT Classifications.ClassificationId,Classifications.FieldId,ClassificationName "
00368                             ."FROM ResourceClassInts, Classifications  "
00369                             ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
00370                             ."AND ResourceClassInts.ClassificationId = Classifications.ClassificationId ");
00371                     while ($Record = $this->DB->FetchRow())
00372                     {
00373                         $this->ClassificationCache[$Record["ClassificationId"]]["Name"] =
00374                                 $Record["ClassificationName"];
00375                         $this->ClassificationCache[$Record["ClassificationId"]]["FieldId"] =
00376                                 $Record["FieldId"];
00377                     }
00378                 }
00379 
00380                 # for each entry in classification cache
00381                 foreach ($this->ClassificationCache as $ClassificationId => $ClassificationInfo)
00382                 {
00383                     # if classification ID matches field we are looking for
00384                     if ($ClassificationInfo["FieldId"] == $Field->Id())
00385                     {
00386                         # add field to result
00387                         if ($ReturnObject)
00388                         {
00389                             $ReturnValue[$ClassificationId] = new Classification($ClassificationId);
00390                         }
00391                         else
00392                         {
00393                             $ReturnValue[$ClassificationId] = $ClassificationInfo["Name"];
00394                         }
00395                     }
00396                 }
00397                 break;
00398 
00399             case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
00400             case MetadataSchema::MDFTYPE_OPTION:
00401                 # start with empty array
00402                 $ReturnValue = array();
00403 
00404                 # if controlled name cache has not been loaded
00405                 if (!isset($this->ControlledNameCache))
00406                 {
00407                     # load all controlled names associated with this resource into cache
00408                     $this->ControlledNameCache = array();
00409                     $this->DB->Query("SELECT ControlledNames.ControlledNameId,ControlledNames.FieldId,ControlledName "
00410                             ."FROM ResourceNameInts, ControlledNames  "
00411                             ."WHERE ResourceNameInts.ResourceId = ".$this->Id." "
00412                             ."AND ResourceNameInts.ControlledNameId = ControlledNames.ControlledNameId ");
00413                     while ($Record = $this->DB->FetchRow())
00414                     {
00415                         $this->ControlledNameCache[$Record["ControlledNameId"]]["Name"] = $Record["ControlledName"];
00416                         $this->ControlledNameCache[$Record["ControlledNameId"]]["FieldId"] = $Record["FieldId"];
00417                     }
00418                 }
00419 
00420                 # if variant names requested and variant name cache has not been loaded
00421                 if ($IncludeVariants && !isset($this->ControlledNameVariantCache))
00422                 {
00423                     # load all controlled names associated with this resource into cache
00424                     $this->ControlledNameVariantCache = array();
00425                     $this->DB->Query("SELECT ControlledNames.ControlledNameId,ControlledNames.FieldId,ControlledName,VariantName "
00426                             ."FROM ResourceNameInts, ControlledNames, VariantNames  "
00427                             ."WHERE ResourceNameInts.ResourceId = ".$this->Id." "
00428                             ."AND ResourceNameInts.ControlledNameId = ControlledNames.ControlledNameId "
00429                             ."AND VariantNames.ControlledNameId = ControlledNames.ControlledNameId");
00430                     while ($Record = $this->DB->FetchRow())
00431                     {
00432                         $this->ControlledNameVariantCache[$Record["ControlledNameId"]][] = $Record["VariantName"];
00433                     }
00434                 }
00435 
00436                 # for each entry in controlled name cache
00437                 foreach ($this->ControlledNameCache as $ControlledNameId => $ControlledNameInfo)
00438                 {
00439                     # if controlled name type matches field we are looking for
00440                     if ($ControlledNameInfo["FieldId"] == $Field->Id())
00441                     {
00442                         # if objects requested
00443                         if ($ReturnObject)
00444                         {
00445                             $ReturnValue[$ControlledNameId] =
00446                                     new ControlledName($ControlledNameId);
00447                         }
00448                         else
00449                         {
00450                             # if variant names requested
00451                             if ($IncludeVariants)
00452                             {
00453                                 # add field to result
00454                                 $ReturnValue[] = $ControlledNameInfo["Name"];
00455 
00456                                 # add any variant names to result
00457                                 if (isset($this->ControlledNameVariantCache[$ControlledNameId]))
00458                                 {
00459                                     $ReturnValue = array_merge($ReturnValue, $this->ControlledNameVariantCache[$ControlledNameId]);
00460                                 }
00461                             }
00462                             else
00463                             {
00464                                 # add field with index to result
00465                                 $ReturnValue[$ControlledNameId] = $ControlledNameInfo["Name"];
00466                             }
00467                         }
00468                     }
00469                 }
00470                 break;
00471 
00472             case MetadataSchema::MDFTYPE_USER:
00473                 $User = new User($this->DB, (int)$this->DBFields[$DBFieldName]);
00474                 if ($ReturnObject)
00475                 {
00476                     $ReturnValue = $User;
00477                 }
00478                 else
00479                 {
00480                     $ReturnValue = $User->Get("UserName");
00481                 }
00482                 break;
00483 
00484             case MetadataSchema::MDFTYPE_IMAGE:
00485                 if ($this->DBFields[$DBFieldName] > 0)
00486                 {
00487                     $ImageObject = new SPTImage($this->DBFields[$DBFieldName]);
00488                     if ($ReturnObject)
00489                     {
00490                         $ReturnValue = $ImageObject;
00491                     }
00492                     else
00493                     {
00494                         $ReturnValue = $ImageObject->AltText();
00495                     }
00496                 }
00497                 else
00498                 {
00499                     $ReturnValue = NULL;
00500                 }
00501                 break;
00502 
00503             case MetadataSchema::MDFTYPE_FILE:
00504                 # retrieve files using factory
00505                 $Factory = new FileFactory($Field->Id());
00506                 $ReturnValue = $Factory->GetFilesForResource(
00507                         $this->Id, $ReturnObject);
00508                 break;
00509 
00510             default:
00511                 # ERROR OUT
00512                 exit("<br>SPT - ERROR: attempt to retrieve unknown resource field type (".$Field->Type().")<br>\n");
00513                 break;
00514         }
00515 
00516         # return formatted value to caller
00517         return $ReturnValue;
00518     }
00523     function GetByField($FieldNameOrObject,
00524             $ReturnObject = FALSE, $IncludeVariants = FALSE)
00525     {  return $this->Get($FieldNameOrObject, $ReturnObject, $IncludeVariants);  }
00526 
00540     function GetByFieldId($FieldId, $ReturnObject = FALSE, $IncludeVariants = FALSE)
00541     {
00542         $Field = $this->Schema->GetField($FieldId);
00543         return ($Field) ? $this->Get($Field, $ReturnObject, $IncludeVariants) : NULL;
00544     }
00545 
00558     function GetAsArray($IncludeDisabledFields = FALSE, $ReturnObjects = TRUE)
00559     {
00560         # retrieve field info
00561         $Fields = $this->Schema->GetFields();
00562 
00563         # for each field
00564         foreach ($Fields as $Field)
00565         {
00566             # if field is enabled or caller requested disabled fields
00567             if ($Field->Enabled() || $IncludeDisabledFields)
00568             {
00569                 # retrieve info and add it to the array
00570                 $FieldStrings[$Field->Name()] = $this->Get($Field, $ReturnObjects);
00571 
00572                 # if field uses qualifiers
00573                 if ($Field->UsesQualifiers())
00574                 {
00575                     # get qualifier attributes and add to the array
00576                     $FieldStrings[$Field->Name()." Qualifier"] =
00577                             $this->GetQualifierByField($Field, $ReturnObjects);
00578                 }
00579             }
00580         }
00581 
00582         # add in internal values
00583         $FieldStrings["ResourceId"] = $this->Id();
00584         $FieldStrings["CumulativeRating"] = $this->CumulativeRating();
00585 
00586         # return array to caller
00587         return $FieldStrings;
00588     }
00589 
00604     function GetMapped($MappedName, $ReturnObject = FALSE, $IncludeVariants = FALSE)
00605     {
00606         return $this->Schema->StdNameToFieldMapping($MappedName)
00607                 ? $this->GetByFieldId($this->Schema->StdNameToFieldMapping($MappedName),
00608                         $ReturnObject, $IncludeVariants)
00609                 : NULL;
00610     }
00611 
00620     function GetQualifier($FieldName, $ReturnObject = TRUE)
00621     {
00622         $Field = $this->Schema->GetFieldByName($FieldName);
00623         return $this->GetQualifierByField($Field, $ReturnObject);
00624     }
00625 
00634     function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
00635     {
00636         $Field = $this->Schema->GetField($FieldId);
00637         return $this->GetQualifierByField($Field, $ReturnObject);
00638     }
00639 
00648     function GetQualifierByField($Field, $ReturnObject = TRUE)
00649     {
00650         # return NULL if field is invalid
00651         if ((get_class($Field) != "MetadataField")
00652                 || ($Field->Status() != MetadataSchema::MDFSTAT_OK))
00653                 {  return NULL;  }
00654 
00655         # assume no qualifiers if not otherwise determined
00656         $ReturnValue = NULL;
00657 
00658         # if field uses qualifiers
00659         if ($Field->UsesQualifiers())
00660         {
00661             # retrieve qualifiers based on field type
00662             switch ($Field->Type())
00663             {
00664                 case MetadataSchema::MDFTYPE_TREE:
00665                 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
00666                 case MetadataSchema::MDFTYPE_OPTION:
00667                     # retrieve list of items
00668                     $Items = $this->Get($Field);
00669 
00670                     # if field uses item-level qualifiers
00671                     if ($Field->HasItemLevelQualifiers())
00672                     {
00673                         # determine general item name in DB
00674                         $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
00675                                 ? "Classification" : "ControlledName";
00676 
00677                         # for each item
00678                         foreach ($Items as $ItemId => $ItemName)
00679                         {
00680                             # look up qualifier for item
00681                             $QualId = $this->DB->Query(
00682                                     "SELECT * FROM ".$TableName."s"
00683                                     ." WHERE ".$TableName."Id = ".$ItemId
00684                                     , "QualifierId");
00685 
00686 
00687                             if ($QualId > 0)
00688                             {
00689                                 # if object was requested by caller
00690                                 if ($ReturnObject)
00691                                 {
00692                                     # load qualifier and add to return value array
00693                                     $ReturnValue[$ItemId] = new Qualifier($QualId);
00694                                 }
00695                                 else
00696                                 {
00697                                     # add qualifier ID to return value array
00698                                     $ReturnValue[$ItemId] = $QualId;
00699                                 }
00700                             }
00701                             else
00702                             {
00703                                 # add NULL to return value array for this item
00704                                 $ReturnValue[$ItemId] = NULL;
00705                             }
00706                         }
00707                     }
00708                     else
00709                     {
00710                         # for each item
00711                         foreach ($Items as $ItemId => $ItemName)
00712                         {
00713                             # if object was requested by caller
00714                             if ($ReturnObject)
00715                             {
00716                                 # load default qualifier and add to return value array
00717                                 $ReturnValue[$ItemId] = new Qualifier($Field->DefaultQualifier());
00718                             }
00719                             else
00720                             {
00721                                 # add default qualifier ID to return value array
00722                                 $ReturnValue[$ItemId] = $Field->DefaultQualifier();
00723                             }
00724                         }
00725                     }
00726                     break;
00727 
00728                 default:
00729                     # if field uses item-level qualifiers
00730                     if ($Field->HasItemLevelQualifiers())
00731                     {
00732                         # if qualifier available
00733                         if ($this->DBFields[$Field->DBFieldName()."Qualifier"] > 0)
00734                         {
00735                             # if object was requested by caller
00736                             if ($ReturnObject)
00737                             {
00738                                 # return qualifier for field
00739                                 $ReturnValue = new Qualifier($this->DBFields[$Field->DBFieldName()."Qualifier"]);
00740                             }
00741                             else
00742                             {
00743                                 # return qualifier ID for field
00744                                 $ReturnValue = $this->DBFields[$Field->DBFieldName()."Qualifier"];
00745                             }
00746                         }
00747                     }
00748                     else
00749                     {
00750                         # if default qualifier available
00751                         if ($Field->DefaultQualifier() > 0)
00752                         {
00753                             # if object was requested by caller
00754                             if ($ReturnObject)
00755                             {
00756                                 # return default qualifier
00757                                 $ReturnValue = new Qualifier($Field->DefaultQualifier());
00758                             }
00759                             else
00760                             {
00761                                 # return default qualifier ID
00762                                 $ReturnValue = $Field->DefaultQualifier();
00763                             }
00764                         }
00765                     }
00766                     break;
00767             }
00768         }
00769 
00770         # return qualifier object or ID (or array of same) to caller
00771         return $ReturnValue;
00772     }
00773 
00774 
00775     # --- Generic Attribute Setting Methods ---------------------------------
00776 
00777     # set value using field name or field object
00778     function Set($FieldNameOrObject, $NewValue)
00779     {
00780         # load field object if needed
00781         $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
00782                 : $this->Schema->GetFieldByName($FieldNameOrObject);
00783 
00784         # grab commonly-used values for local use
00785         $DB = $this->DB;
00786         $ResourceId = $this->Id;
00787 
00788         # grab database field name
00789         $DBFieldName = $Field->DBFieldName();
00790 
00791         # Flag to deterimine if we've actually changed anything.
00792         $UpdateModTime = FALSE;
00793 
00794         # store value in DB based on field type
00795         switch ($Field->Type())
00796         {
00797             case MetadataSchema::MDFTYPE_TEXT:
00798             case MetadataSchema::MDFTYPE_PARAGRAPH:
00799             case MetadataSchema::MDFTYPE_URL:
00800                 if ($this->DBFields[$DBFieldName] != $NewValue)
00801                 {
00802                     # save value directly to DB
00803                     $DB->Query("UPDATE Resources SET `"
00804                                .$DBFieldName."` = '".addslashes($NewValue)."' "
00805                                ."WHERE ResourceId = ".$ResourceId);
00806 
00807                     # save value locally
00808                     $this->DBFields[$DBFieldName] = $NewValue;
00809                     $UpdateModTime=TRUE;
00810                 }
00811                 break;
00812 
00813             case MetadataSchema::MDFTYPE_NUMBER:
00814                 if ( $this->DBFields[$DBFieldName] != $NewValue )
00815                 {
00816                     # save value directly to DB
00817                     if (is_null($NewValue))
00818                     {
00819                         $DB->Query("UPDATE Resources SET `"
00820                                    .$DBFieldName."` = NULL"
00821                                    ." WHERE ResourceId = ".$ResourceId);
00822                     }
00823                     else
00824                     {
00825                         $DB->Query("UPDATE Resources SET `"
00826                                    .$DBFieldName."` = ".intval($NewValue)
00827                                    ." WHERE ResourceId = ".$ResourceId);
00828                     }
00829 
00830                     # save value locally
00831                     $this->DBFields[$DBFieldName] = $NewValue;
00832                     $UpdateModTime = TRUE;
00833                 }
00834                 break;
00835 
00836 
00837             case MetadataSchema::MDFTYPE_POINT:
00838                 if ($this->DBFields[$DBFieldName."X"] != $NewValue["X"] ||
00839                     $this->DBFields[$DBFieldName."Y"] != $NewValue["Y"] )
00840                 {
00841                     if (is_null($NewValue))
00842                     {
00843                         $DB->Query("UPDATE Resources SET "
00844                                    ."`".$DBFieldName."X` = NULL, "
00845                                    ."`".$DBFieldName."Y` = NULL "
00846                                    ."WHERE ResourceId = ".$ResourceId);
00847                         $this->DBFields[$DBFieldName."X"] = NULL;
00848                         $this->DBFields[$DBFieldName."Y"] = NULL;
00849                     }
00850                     else
00851                     {
00852                         $DB->Query("UPDATE Resources SET "
00853                                    ."`".$DBFieldName."X` = ".(strlen($NewValue["X"])
00854                                                               ? "'".$NewValue["X"]."'" : "NULL").", "
00855                                    ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
00856                                                               ? "'".$NewValue["Y"]."'" : "NULL")
00857                                    ." WHERE ResourceId = ".$ResourceId);
00858 
00859                         $Digits = $Field->PointDecimalDigits();
00860 
00861                         $this->DBFields[$DBFieldName."X"] =
00862                             strlen($NewValue["X"]) ? round($NewValue["X"], $Digits) : NULL;
00863                         $this->DBFields[$DBFieldName."Y"] =
00864                             strlen($NewValue["Y"]) ? round($NewValue["Y"], $Digits) : NULL;
00865                     }
00866                     $UpdateModTime = TRUE;
00867                 }
00868                 break;
00869 
00870             case MetadataSchema::MDFTYPE_FLAG:
00871                 if ($this->DBFields[$DBFieldName] != $NewValue)
00872                 {
00873                     # save value directly to DB
00874                     if (is_null($NewValue))
00875                     {
00876                         $DB->Query("UPDATE Resources SET `"
00877                                    .$DBFieldName."` = NULL"
00878                                    ." WHERE ResourceId = ".$ResourceId);
00879                     }
00880                     else
00881                     {
00882                         $DB->Query("UPDATE Resources SET `"
00883                                    .$DBFieldName."` = ".$NewValue
00884                                    ." WHERE ResourceId = ".$ResourceId);
00885                     }
00886 
00887                     $this->DBFields[$DBFieldName] = $NewValue;
00888 
00889                     # recalculate counts for any associated classifications if necessary
00890                     if ($DBFieldName == "ReleaseFlag")
00891                     {
00892                         $DB->Query("SELECT ClassificationId FROM ResourceClassInts"
00893                                 ." WHERE ResourceId = ".$ResourceId);
00894                         while ($ClassId = $DB->FetchField("ClassificationId"))
00895                         {
00896                             $Class = new Classification($ClassId);
00897                             $Class->RecalcResourceCount();
00898                         }
00899                     }
00900                     $UpdateModTime = TRUE;
00901                 }
00902                 break;
00903 
00904             case MetadataSchema::MDFTYPE_USER:
00905                 # if value passed in was object
00906                 if (is_object($NewValue))
00907                 {
00908                     # retrieve user ID from object
00909                     $UserId = $NewValue->Get("UserId");
00910                 }
00911                 # else if value passed in was user name
00912                 elseif (is_string($NewValue))
00913                 {
00914                     # create user object and retrieve user ID from there
00915                     $User = new User($this->DB, $NewValue);
00916                     $UserId = $User->Get("UserId");
00917                 }
00918                 else
00919                 {
00920                     # assume value is user ID and use value directly
00921                     $UserId = $NewValue;
00922                 }
00923 
00924                 if ($this->DBFields[$DBFieldName] != $UserId)
00925                 {
00926                     # save value directly to DB
00927                     $DB->Query("UPDATE Resources SET `"
00928                                .$DBFieldName."` = '".$UserId."' "
00929                                ."WHERE ResourceId = ".$ResourceId);
00930 
00931                     # save value locally
00932                     $this->DBFields[$DBFieldName] = $UserId;
00933                     $UpdateModTime = TRUE;
00934                 }
00935                 break;
00936 
00937             case MetadataSchema::MDFTYPE_DATE:
00938                 # if we were given a date object
00939                 if (is_object($NewValue))
00940                 {
00941                     # use supplied date object
00942                     $Date = $NewValue;
00943                 }
00944                 else
00945                 {
00946                     # create date object
00947                     $Date = new Date($NewValue);
00948                 }
00949 
00950                 $OldDate = new Date(
00951                     $this->DBFields[$DBFieldName."Begin"],
00952                     $this->DBFields[$DBFieldName."End"]);
00953 
00954                 if ($OldDate->BeginDate() != $Date->BeginDate() ||
00955                     $OldDate->EndDate()   != $Date->EndDate()   ||
00956                     $OldDate->Precision() != $Date->Precision() )
00957                 {
00958                     # extract values from date object and store in DB
00959                     $BeginDate = "'".$Date->BeginDate()."'";
00960                     if (strlen($BeginDate) < 3) {  $BeginDate = "NULL";  }
00961                     $EndDate = "'".$Date->EndDate()."'";
00962                     if (strlen($EndDate) < 3) {  $EndDate = "NULL";  }
00963 
00964                     $DB->Query("UPDATE Resources SET "
00965                                .$DBFieldName."Begin = ".$BeginDate.", "
00966                                .$DBFieldName."End = ".$EndDate.", "
00967                                .$DBFieldName."Precision = '".$Date->Precision()."' "
00968                                ."WHERE ResourceId = ".$ResourceId);
00969 
00970                     # save values locally
00971                     $this->DBFields[$DBFieldName."Begin"] = $Date->BeginDate();
00972                     $this->DBFields[$DBFieldName."End"] = $Date->EndDate();
00973                     $this->DBFields[$DBFieldName."Precision"] = $Date->Precision();
00974                     $UpdateModTime=TRUE;
00975                 }
00976                 break;
00977 
00978             case MetadataSchema::MDFTYPE_TIMESTAMP:
00979                 if (is_null($NewValue))
00980                 {
00981                     $DateValue = $NewValue;
00982 
00983                     if (!is_null($this->DBFields[$DBFieldName]))
00984                     {
00985                         # save value directly to DB
00986                         $DB->Query("UPDATE Resources SET "
00987                                    ."`".$DBFieldName."` = NULL "
00988                                    ."WHERE ResourceId = ".$ResourceId);
00989                         $UpdateModTime = TRUE;
00990                     }
00991                 }
00992                 else
00993                 {
00994                     # assume value is date and use directly
00995                     $DateValue = date("Y-m-d H:i:s", strtotime($NewValue));
00996 
00997                     if ($this->DBFields[$DBFieldName] != $DateValue)
00998                     {
00999                         # save value directly to DB
01000                         $DB->Query("UPDATE Resources SET "
01001                                    ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
01002                                    ."WHERE ResourceId = ".$ResourceId);
01003                         $UpdateModTime=TRUE;
01004                     }
01005                 }
01006 
01007                 # save value locally
01008                 $this->DBFields[$DBFieldName] = $DateValue;
01009                 break;
01010 
01011             case MetadataSchema::MDFTYPE_TREE:
01012                 $OldValue = $this->Get($Field);
01013 
01014                 # if incoming value is array
01015                 if (is_array($NewValue))
01016                 {
01017                     if ($OldValue != $NewValue)
01018                     {
01019                         # for each element of array
01020                         foreach ($NewValue as
01021                                  $ClassificationId => $ClassificationName)
01022                         {
01023                             $Class = new Classification($ClassificationId);
01024                             if ($Class->Status() == Classification::CLASSSTAT_OK)
01025                             {
01026                                 # associate with resource if not already associated
01027                                 $this->AddAssociation("ResourceClassInts",
01028                                                       "ClassificationId",
01029                                                       $ClassificationId);
01030                                 $Class->RecalcResourceCount();
01031                             }
01032                         }
01033                         $UpdateModTime=TRUE;
01034                     }
01035                 }
01036                 else
01037                 {
01038                     # associate with resource if not already associated
01039                     if (is_object($NewValue))
01040                     {
01041                         $Class = $NewValue;
01042                         $NewValue = $Class->Id();
01043                     }
01044                     else
01045                     {
01046                         $Class = new Classification($NewValue);
01047                     }
01048 
01049                     if (!array_key_exists($Class->Id(), $OldValue))
01050                     {
01051 
01052                         $this->AddAssociation("ResourceClassInts",
01053                                               "ClassificationId",
01054                                               $NewValue);
01055                         $Class->RecalcResourceCount();
01056                         $UpdateModTime=TRUE;
01057                     }
01058                 }
01059 
01060                 # clear our classification cache
01061                 if ($UpdateModTime)
01062                 {
01063                     unset($this->ClassificationCache);
01064                 }
01065                 break;
01066 
01067             case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
01068             case MetadataSchema::MDFTYPE_OPTION:
01069                 $OldValue = $this->Get($Field);
01070 
01071                 # Clear other values if this field expects unique options
01072                 if ($Field->AllowMultiple() === FALSE)
01073                 {
01074                     # If we're fed an array for a unique option,
01075                     # just use the last element of the array
01076                     if (is_array($NewValue)){
01077                         $NewValue = array_pop($NewValue);
01078                     }
01079 
01080                     if (!array_key_exists($NewValue, $OldValue))
01081                     {
01082 
01083                         $this->RemoveAllAssociations("ResourceNameInts",
01084                                                      "ControlledNameId",
01085                                                      $Field );
01086                         $UpdateModTime=TRUE;
01087                     }
01088                 }
01089 
01090                 # if incoming value is array
01091                 if (is_array($NewValue) && ($Field->AllowMultiple() !== FALSE) )
01092                 {
01093                     if ($OldValue != $NewValue)
01094                     {
01095                         # for each element of array
01096                         foreach ($NewValue as $ControlledNameId => $ControlledName)
01097                         {
01098                             # associate with resource if not already associated
01099                             $this->AddAssociation("ResourceNameInts",
01100                                                   "ControlledNameId",
01101                                                   $ControlledNameId);
01102                         }
01103                         $UpdateModTime=TRUE;
01104                     }
01105                 }
01106                 else
01107                 {
01108                     # associate with resource if not already associated
01109                     if (is_object($NewValue)) {  $NewValue = $NewValue->Id();  }
01110                     if (!array_key_exists($NewValue, $OldValue))
01111                     {
01112                         $this->AddAssociation("ResourceNameInts",
01113                                               "ControlledNameId",
01114                                               $NewValue);
01115                         $UpdateModTime=TRUE;
01116                     }
01117                 }
01118 
01119                 if ($UpdateModTime)
01120                 {
01121                     # clear our controlled name cache
01122                     unset($this->ControlledNameCache);
01123                     unset($this->ControlledNameVariantCache);
01124                 }
01125 
01126                 break;
01127 
01128             case MetadataSchema::MDFTYPE_IMAGE:
01129                 # if we were given an image object
01130                 if (is_object($NewValue))
01131                 {
01132                     # grab ID from object
01133                     $ImageId = $NewValue->Id();
01134                 }
01135                 else
01136                 {
01137                     # assume incoming value is ID
01138                     $ImageId = $NewValue;
01139                 }
01140 
01141                 if ($this->DBFields[$DBFieldName] != $ImageId)
01142                 {
01143                     # store new image object ID in database
01144                     $DB->Query("UPDATE Resources SET `"
01145                                .$DBFieldName."` = '".$ImageId."'"
01146                                ." WHERE ResourceId = ".$ResourceId);
01147                     $UpdateModTime = TRUE;
01148                     # save value locally
01149                     $this->DBFields[$DBFieldName] = $ImageId;
01150                 }
01151                 break;
01152 
01153             case MetadataSchema::MDFTYPE_FILE:
01154                 # convert incoming value to array if necessary
01155                 if (!is_array($NewValue)) {  $NewValue = array($NewValue);  }
01156 
01157                 # for each incoming file
01158                 $Factory = new FileFactory($Field->Id());
01159                 foreach ($NewValue as $File)
01160                 {
01161                     # make copy of file
01162                     $NewFile = $Factory->Copy($File);
01163 
01164                     # associate copy with this resource and field
01165                     $NewFile->ResourceId($this->Id);
01166                     $NewFile->FieldId($Field->Id());
01167                 }
01168                 # Since we make a fresh copy of the File whenever Set is called,
01169                 # we'll always update the modification time for this field.
01170                 $UpdateModTime = TRUE;
01171                 break;
01172 
01173             default:
01174                 # ERROR OUT
01175                 exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
01176                 break;
01177         }
01178 
01179         if ($UpdateModTime && !$this->IsTempResource())
01180         {
01181             # update modification timestamps
01182             global $G_User;
01183             $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
01184             $DB->Query("DELETE FROM ResourceFieldTimestamps "
01185                        ."WHERE ResourceId=".$this->Id." AND "
01186                        ."FieldId=".$Field->Id() );
01187             $DB->Query("INSERT INTO ResourceFieldTimestamps "
01188                        ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
01189                        .$this->Id.",".$Field->Id().","
01190                        .$UserId.",NOW())");
01191         }
01192     }
01193     # (for backward compatibility)
01194     function SetByField($Field, $NewValue) {  return $this->Set($Field, $NewValue);  }
01195 
01196     # set value by field ID
01197     function SetByFieldId($FieldId, $NewValue)
01198     {
01199         $Field = $this->Schema->GetField($FieldId);
01200         return $this->Set($Field, $NewValue);
01201     }
01202 
01203     # set qualifier by field name
01204     function SetQualifier($FieldName, $NewValue)
01205     {
01206         $Field = $this->Schema->GetFieldByName($FieldName);
01207         return $this->SetQualifierByField($Field, $NewValue);
01208     }
01209 
01210     # set qualifier by field ID
01211     function SetQualifierByFieldId($FieldId, $NewValue)
01212     {
01213         $Field = $this->Schema->GetField($FieldId);
01214         return $this->SetQualifierByField($Field, $NewValue);
01215     }
01216 
01217     # set qualifier using field object
01218     function SetQualifierByField($Field, $NewValue)
01219     {
01220         # if field uses qualifiers and uses item-level qualifiers
01221         if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
01222         {
01223             # if qualifier object passed in
01224             if (is_object($NewValue))
01225             {
01226                 # grab qualifier ID from object
01227                 $QualifierId = $NewValue->Id();
01228             }
01229             else
01230             {
01231                 # assume value passed in is qualifier ID
01232                 $QualifierId = $NewValue;
01233             }
01234 
01235             # update qualifier value in database
01236             $DBFieldName = $Field->DBFieldName();
01237             $this->DB->Query("UPDATE Resources SET "
01238                      .$DBFieldName."Qualifier = '".$QualifierId."' "
01239                      ."WHERE ResourceId = ".$this->Id);
01240 
01241             # update local qualifier value
01242             $this->DBFields[$DBFieldName."Qualifier"] = $QualifierId;
01243         }
01244     }
01245 
01246     # clear value by field name
01247     function Clear($FieldName, $ValueToClear = NULL)
01248     {
01249         $Field = $this->Schema->GetFieldByName($FieldName);
01250         return $this->ClearByField($Field, $ValueToClear);
01251     }
01252 
01253     # clear value by field ID
01254     function ClearByFieldId($FieldId, $ValueToClear = NULL)
01255     {
01256         $Field = $this->Schema->GetField($FieldId);
01257         return $this->ClearByField($Field, $ValueToClear);
01258     }
01259 
01260     # clear value using field object
01261     function ClearByField($Field, $ValueToClear = NULL)
01262     {
01263         # grab commonly-used values for local use
01264         $DB = $this->DB;
01265         $ResourceId = $this->Id;
01266 
01267         # grab database field name
01268         $DBFieldName = $Field->DBFieldName();
01269 
01270         $UpdateModTime=FALSE;
01271 
01272         # store value in DB based on field type
01273         switch ($Field->Type())
01274         {
01275             case MetadataSchema::MDFTYPE_TEXT:
01276             case MetadataSchema::MDFTYPE_PARAGRAPH:
01277             case MetadataSchema::MDFTYPE_NUMBER:
01278             case MetadataSchema::MDFTYPE_FLAG:
01279             case MetadataSchema::MDFTYPE_USER:
01280             case MetadataSchema::MDFTYPE_TIMESTAMP:
01281             case MetadataSchema::MDFTYPE_URL:
01282                 if (strlen($this->DBFields[$DBFieldName])>0)
01283                 {
01284                     # clear value in DB
01285                     $DB->Query("UPDATE Resources SET `"
01286                                .$DBFieldName."` = '' "
01287                                ."WHERE ResourceId = ".$ResourceId);
01288 
01289                     # clear value locally
01290                     $this->DBFields[$DBFieldName] = NULL;
01291                     $UpdateModTime=TRUE;
01292                 }
01293                 break;
01294 
01295             case MetadataSchema::MDFTYPE_POINT:
01296                 if (!is_null($this->DBFields[$DBFieldName."X"]) ||
01297                     !is_null($this->DBFields[$DBFieldName."Y"]) )
01298                 {
01299                     # Clear DB Values
01300                     $DB->Query("UPDATE Resources SET "
01301                                ."`".$DBFieldName."X` = NULL ,"
01302                                ."`".$DBFieldName."Y` = NULL "
01303                                ."WHERE ResourceId = ".$ResourceId);
01304 
01305                     # Clear local values
01306                     $this->DBFields[$DBFieldName."X"] = NULL;
01307                     $this->DBFields[$DBFieldName."Y"] = NULL;
01308                     $UpdateModTime=TRUE;
01309                 }
01310                 break;
01311 
01312             case MetadataSchema::MDFTYPE_DATE:
01313                 if (!is_null($this->DBFields[$DBFieldName."Begin"]) ||
01314                     !is_null($this->DBFields[$DBFieldName."End"])   ||
01315                     !is_null($this->DBFields[$DBFieldName."Precision"]))
01316                 {
01317                     # clear date object values in DB
01318                     $DB->Query("UPDATE Resources SET "
01319                                .$DBFieldName."Begin = '', "
01320                                .$DBFieldName."End = '', "
01321                                .$DBFieldName."Precision = '' "
01322                                ."WHERE ResourceId = ".$ResourceId);
01323 
01324                     # clear value locally
01325                     $this->DBFields[$DBFieldName."Begin"] = NULL;
01326                     $this->DBFields[$DBFieldName."End"] = NULL;
01327                     $this->DBFields[$DBFieldName."Precision"] = NULL;
01328                     $UpdateModTime=TRUE;
01329                 }
01330                 break;
01331 
01332             case MetadataSchema::MDFTYPE_TREE:
01333                 $OldValue = $this->Get($Field);
01334 
01335                 # if value to clear supplied
01336                 if ($ValueToClear !== NULL)
01337                 {
01338                     # if supplied value is array
01339                     if (is_array($ValueToClear))
01340                     {
01341                         # for each element of array
01342                         foreach ($ValueToClear as $ClassificationId => $Dummy)
01343                         {
01344                             if (array_key_exists($ClassificationId, $OldValue))
01345                             {
01346                                 # remove association with resource (if any)
01347                                 $this->RemoveAssociation("ResourceClassInts",
01348                                                          "ClassificationId",
01349                                                          $ClassificationId);
01350                                 $Class = new Classification($ClassificationId);
01351                                 $Class->RecalcResourceCount();
01352                                 $UpdateModTime=TRUE;
01353                             }
01354                         }
01355                     }
01356                     else
01357                     {
01358                         if (array_key_exists($ValueToClear, $OldValue))
01359                         {
01360                             # remove association with resource (if any)
01361                             $this->RemoveAssociation("ResourceClassInts",
01362                                                      "ClassificationId",
01363                                                      $ValueToClear);
01364                             $Class = new Classification($ValueToClear);
01365                             $Class->RecalcResourceCount();
01366                             $UpdateModTime=TRUE;
01367                         }
01368                     }
01369                 }
01370                 else
01371                 {
01372                     if (count($OldValue)>0)
01373                     {
01374                         # remove all associations for resource and field
01375                         $this->RemoveAllAssociations("ResourceClassInts", "ClassificationId", $Field);
01376 
01377                         # recompute resource count
01378                         $Values = $this->Get($Field);
01379                         foreach ($Values as $ClassificationId => $Dummy)
01380                         {
01381                             $Class = new Classification($ClassificationId);
01382                             $Class->RecalcResourceCount();
01383                         }
01384                         $UpdateModTime=TRUE;
01385                     }
01386                 }
01387 
01388                 # clear our classification cache
01389                 if ($UpdateModTime)
01390                 {
01391                     unset($this->ClassificationCache);
01392                 }
01393                 break;
01394 
01395             case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
01396             case MetadataSchema::MDFTYPE_OPTION:
01397                 $OldValue = $this->Get($Field);
01398                 # if value to clear supplied
01399                 if ($ValueToClear !== NULL)
01400                 {
01401                     # if incoming value is array
01402                     if (is_array($ValueToClear))
01403                     {
01404                         # for each element of array
01405                         foreach ($ValueToClear as $ControlledNameId =>
01406                             $ControlledName)
01407                         {
01408                             if (array_key_exists($ControlledNameId, $OldValue))
01409                             {
01410                                 # remove association with resource (if any)
01411                                 $this->RemoveAssociation("ResourceNameInts",
01412                                                          "ControlledNameId",
01413                                                          $ControlledNameId);
01414                                 $UpdateModTime=TRUE;
01415                             }
01416                         }
01417                     }
01418                     else
01419                     {
01420                         if (array_key_exists($ValueToClear, $OldValue))
01421                         {
01422                             # remove association with resource (if any)
01423                             $this->RemoveAssociation("ResourceNameInts",
01424                                                      "ControlledNameId",
01425                                                      $ValueToClear);
01426                             $UpdateModTime=TRUE;
01427                         }
01428                     }
01429                 }
01430                 else
01431                 {
01432                     if (count($OldValue)>0)
01433                     {
01434                         # remove all associations for resource and field
01435                         $this->RemoveAllAssociations("ResourceNameInts", "ControlledNameId", $Field);
01436                         $UpdateModTime=TRUE;
01437                     }
01438                 }
01439 
01440                 if ($UpdateModTime)
01441                 {
01442                     # clear our controlled name cache
01443                     unset($this->ControlledNameCache);
01444                     unset($this->ControlledNameVariantCache);
01445                 }
01446                 break;
01447 
01448             case MetadataSchema::MDFTYPE_IMAGE:
01449                 # delete image if no other resources are using it
01450                 $ImageId = $DB->Query("SELECT `".$DBFieldName
01451                                       ."` FROM Resources WHERE ResourceId = ".$ResourceId,
01452                                       $DBFieldName);
01453                 if ($ImageId > 0)
01454                 {
01455                     $ImageCount = $DB->Query("SELECT COUNT(*) AS ImageCount FROM Resources"
01456                                              ." WHERE `".$DBFieldName."` = ".$ImageId,
01457                                              "ImageCount");
01458                     if ($ImageCount < 2)
01459                     {
01460                         $Image = new SPTImage($ImageId);
01461                         $Image->Delete();
01462                     }
01463                     $UpdateModTime=TRUE;
01464                 }
01465 
01466                 # clear stored ID
01467                 $DB->Query("UPDATE Resources SET `"
01468                            .$DBFieldName."` = '' "
01469                            ."WHERE ResourceId = ".$ResourceId);
01470 
01471                 # clear value locally
01472                 $this->DBFields[$DBFieldName] = NULL;
01473                 break;
01474 
01475             case MetadataSchema::MDFTYPE_FILE:
01476                 # get array of Files associated with this resource
01477                 $Files = $this->Get($Field, TRUE);
01478 
01479                 if (count($Files)>0){
01480                     # for each File
01481                     foreach ($Files as $File)
01482                     {
01483                         # delete file
01484                         $File->Delete();
01485                     }
01486                     $UpdateModTime=TRUE;
01487                 }
01488                 break;
01489 
01490             default:
01491                 # ERROR OUT
01492                 exit("<br>SPT - ERROR: attempt to clear unknown resource field type<br>\n");
01493                 break;
01494         }
01495 
01496         if ($UpdateModTime && !$this->IsTempResource())
01497         {
01498             # update modification timestamps
01499             global $G_User;
01500             $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
01501             $DB->Query("DELETE FROM ResourceFieldTimestamps "
01502                        ."WHERE ResourceId=".$this->Id." AND "
01503                        ."FieldId=".$Field->Id() );
01504             $DB->Query("INSERT INTO ResourceFieldTimestamps "
01505                        ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
01506                        .$this->Id.",".$Field->Id().","
01507                        .$UserId.",NOW())");
01508         }
01509     }
01510 
01511 
01512     # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
01513 
01514     # return 2D array of classifications associated with resource
01515     # (first index is classification (field) name, second index is classification ID)
01516     function Classifications()
01517     {
01518         $DB = $this->DB;
01519 
01520         # start with empty array
01521         $Names = array();
01522 
01523         # for each controlled name
01524         $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
01525                 ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
01526                 ."Classifications, MetadataFields "
01527                 ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
01528                 ."AND ResourceClassInts.ClassificationId = Classifications.ClassificationId "
01529                 ."AND Classifications.FieldId = MetadataFields.FieldId ");
01530         while ($Record = $DB->FetchRow())
01531         {
01532             # add name to array
01533             $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
01534                     $Record["ClassificationName"];
01535         }
01536 
01537         # return array to caller
01538         return $Names;
01539     }
01540 
01541 
01542     # --- Ratings Methods ---------------------------------------------------
01543 
01544     # return cumulative rating  (range is usually 0-100)
01545     function CumulativeRating() {  return $this->CumulativeRating;  }
01546 
01547     # return cumulative rating scaled to 1/10th  (range is usually 0-10)
01548     function ScaledCumulativeRating()
01549     {
01550         if ($this->CumulativeRating == NULL)
01551         {
01552             return NULL;
01553         }
01554         else
01555         {
01556             return intval(($this->CumulativeRating + 5) / 10);
01557         }
01558     }
01559 
01560     # return current number of ratings for resource
01561     function NumberOfRatings()
01562     {
01563         # if number of ratings not already set
01564         if (!isset($this->NumberOfRatings))
01565         {
01566             # obtain number of ratings
01567             $this->NumberOfRatings =
01568                     $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
01569                             ."FROM ResourceRatings "
01570                             ."WHERE ResourceId = ".$this->Id,
01571                     "NumberOfRatings"
01572                     );
01573 
01574             # recalculate cumulative rating if it looks erroneous
01575             if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
01576             {
01577                 $this->UpdateCumulativeRating();
01578             }
01579         }
01580 
01581         # return number of ratings to caller
01582         return $this->NumberOfRatings;
01583     }
01584 
01585     # update individual rating for resource
01586     function Rating($NewRating = NULL, $UserId = NULL)
01587     {
01588         $DB = $this->DB;
01589 
01590         # if user ID not supplied
01591         if ($UserId == NULL)
01592         {
01593             # if user is logged in
01594             global $User;
01595             if ($User->IsLoggedIn())
01596             {
01597                 # use ID of current user
01598                 $UserId = $User->Get("UserId");
01599             }
01600             else
01601             {
01602                 # return NULL to caller
01603                 return NULL;
01604             }
01605         }
01606 
01607         # sanitize $NewRating
01608         if (!is_null($NewRating))
01609         {
01610             $NewRating = intval($NewRating);
01611         }
01612 
01613         # if there is a rating for resource and user
01614         $DB->Query("SELECT Rating FROM ResourceRatings "
01615                 ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
01616         if ($Record = $DB->FetchRow())
01617         {
01618             # if new rating was supplied
01619             if ($NewRating != NULL)
01620             {
01621                 # update existing rating
01622                 $DB->Query("UPDATE ResourceRatings "
01623                         ."SET Rating = ${NewRating}, DateRated = NOW() "
01624                         ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
01625 
01626                 # update cumulative rating value
01627                 $this->UpdateCumulativeRating();
01628 
01629                 # return value is new rating
01630                 $Rating = $NewRating;
01631             }
01632             else
01633             {
01634                 # get rating value to return to caller
01635                 $Rating = $Record["Rating"];
01636             }
01637         }
01638         else
01639         {
01640             # if new rating was supplied
01641             if ($NewRating != NULL)
01642             {
01643                 # add new rating
01644                 $DB->Query("INSERT INTO ResourceRatings "
01645                         ."(ResourceId, UserId, DateRated, Rating) "
01646                         ."VALUES ("
01647                                 .$this->Id.", "
01648                                 ."${UserId}, "
01649                                 ."NOW(), "
01650                                 ."${NewRating})");
01651 
01652                 # update cumulative rating value
01653                 $this->UpdateCumulativeRating();
01654 
01655                 # return value is new rating
01656                 $Rating = $NewRating;
01657             }
01658             else
01659             {
01660                 # return value is NULL
01661                 $Rating = NULL;
01662             }
01663         }
01664 
01665         # return rating value to caller
01666         return $Rating;
01667     }
01668 
01669 
01670     # --- Resource Comment Methods ------------------------------------------
01671 
01672     # return comments as array of Message objects
01673     function Comments()
01674     {
01675         # read in comments if not already loaded
01676         if (!isset($this->Comments))
01677         {
01678             $this->DB->Query("SELECT MessageId FROM Messages "
01679                     ."WHERE ParentId = ".$this->Id
01680                     ." AND ParentType = 2 "
01681                     ."ORDER BY DatePosted DESC");
01682             while ($MessageId = $this->DB->FetchField("MessageId"))
01683             {
01684                 $this->Comments[] = new Message($MessageId);
01685             }
01686         }
01687 
01688         # return array of comments to caller
01689         return $this->Comments;
01690     }
01691 
01692     # return current number of comments
01693     function NumberOfComments()
01694     {
01695         # obtain number of comments if not already set
01696         if (!isset($this->NumberOfComments))
01697         {
01698             $this->NumberOfComments =
01699                     $this->DB->Query("SELECT Count(*) AS NumberOfComments "
01700                             ."FROM Messages "
01701                             ."WHERE ParentId = ".$this->Id
01702                             ." AND ParentType = 2",
01703                     "NumberOfComments"
01704                     );
01705         }
01706 
01707         # return number of comments to caller
01708         return $this->NumberOfComments;
01709     }
01710 
01711 
01712     # --- Permission Methods -------------------------------------------------
01713 
01714     # return whether user can edit this resource
01715     function UserCanEdit($User)
01716     {
01717         return ($User->HasPriv(PRIV_RESOURCEADMIN)
01718             || $User->HasPriv(PRIV_RELEASEADMIN)
01719             || ($User->HasPriv(PRIV_MYRESOURCEADMIN)
01720                     && ($User->Id() == $this->DBFields["AddedById"]))
01721         );
01722     }
01723 
01724     # report whether user can view or edit the specified field
01725     function UserCanViewField($User, $FieldOrFieldName)
01726     {
01727         $Schema = new MetadataSchema();
01728 
01729         # get field (if not supplied)
01730         if (is_object($FieldOrFieldName)
01731                 && ($FieldOrFieldName instanceof MetadataField))
01732         {
01733             $Field = $FieldOrFieldName;
01734         }
01735         elseif (strlen(trim($FieldOrFieldName)))
01736         {
01737             if ($Schema->FieldExists($FieldOrFieldName))
01738             {
01739                 $Field = $Schema->GetFieldByName($FieldOrFieldName);
01740             }
01741         }
01742 
01743         # the field must be valid and enabled to be viewable
01744         if (!isset($Field) || !$Field->Enabled())
01745         {
01746             return FALSE;
01747         }
01748 
01749         # if the user can edit the field, they can also view it implicitly
01750         if ($this->UserCanEditField($User, $Field))
01751         {
01752             return TRUE;
01753         }
01754 
01755         # an "user is value of field" constraint isn't set, so only worry about
01756         # the viewing privilege
01757         if ($Field->ViewingUserIsValue() == MetadataField::USERISVALUE_UNSET)
01758         {
01759             # no viewing privilege is set, so anyone can view the field
01760             if ($Field->ViewingPrivilege() == 0)
01761             {
01762                 return TRUE;
01763             }
01764 
01765             # a viewing privilege is set, so check if the user has it
01766             else
01767             {
01768                 return $User->HasPriv($Field->ViewingPrivilege());
01769             }
01770         }
01771 
01772         # an "user is value of field" constraint is set
01773         else
01774         {
01775             $ViewingUserIsValue = $Field->ViewingUserIsValue();
01776             $ViewingUserValue = $Field->ViewingUserValue();
01777             $ViewingUserField = $Schema->GetField($ViewingUserValue);
01778             $ViewingUserFieldValue = $this->Get($ViewingUserField);
01779 
01780             # no viewing privilege is set, so only check the constraint
01781             if ($Field->ViewingPrivilege() == 0)
01782             {
01783                 # just check if the user is the value of the field
01784                 return $ViewingUserFieldValue == $User->Name();
01785             }
01786 
01787             # a viewing privilege is set, so check the privilege and constraint
01788             else
01789             {
01790                 # OR user is value of field
01791                 if ($ViewingUserIsValue == MetadataField::USERISVALUE_OR)
01792                 {
01793                     # user is value of the field, so short circuit
01794                     if ($ViewingUserFieldValue == $User->Name())
01795                     {
01796                         return TRUE;
01797                     }
01798                 }
01799 
01800                 # AND user is value of field constraint, but user isn't the
01801                 # value, so short circuit
01802                 else if ($ViewingUserFieldValue != $User->Name())
01803                 {
01804                     return FALSE;
01805                 }
01806 
01807                 # finally, if the logic hasn't been short circuited, check if
01808                 # the user has the viewing privilege
01809                 return $User->HasPriv($Field->ViewingPrivilege());
01810             }
01811         }
01812     }
01813 
01814     # report whether user can author the specified field
01815     function UserCanAuthorField($User, $FieldOrFieldName)
01816     {
01817         $Schema = new MetadataSchema();
01818 
01819         # get field (if not supplied)
01820         if (is_object($FieldOrFieldName)
01821                 && ($FieldOrFieldName instanceof MetadataField))
01822         {
01823             $Field = $FieldOrFieldName;
01824         }
01825         elseif (strlen(trim($FieldOrFieldName)))
01826         {
01827             if ($Schema->FieldExists($FieldOrFieldName))
01828             {
01829                 $Field = $Schema->GetFieldByName($FieldOrFieldName);
01830             }
01831         }
01832 
01833         # the field must be valid and enabled to be viewable
01834         if (!isset($Field) || !$Field->Enabled())
01835         {
01836             return FALSE;
01837         }
01838 
01839         # the user would have had to add the resource to be its author
01840         if ($User->Name() != $this->Get("Added By Id"))
01841         {
01842             return FALSE;
01843         }
01844 
01845         # an "user is value of field" constraint isn't set, so only worry about
01846         # the authoring privilege
01847         if ($Field->AuthoringUserIsValue() == MetadataField::USERISVALUE_UNSET)
01848         {
01849             # no authoring privilege is set, so anyone can author the field
01850             if ($Field->AuthoringPrivilege() == 0)
01851             {
01852                 return TRUE;
01853             }
01854 
01855             # an authoring privilege is set, so check if the user has it
01856             else
01857             {
01858                 return $User->HasPriv($Field->AuthoringPrivilege());
01859             }
01860         }
01861 
01862         # an "user is value of field" constraint is set
01863         else
01864         {
01865             $AuthoringUserIsValue = $Field->AuthoringUserIsValue();
01866             $AuthoringUserValue = $Field->AuthoringUserValue();
01867             $AuthoringUserField = $Schema->GetField($AuthoringUserValue);
01868             $AuthoringUserFieldValue = $this->Get($AuthoringUserField);
01869 
01870             # no authoring privilege is set, so only check the constraint
01871             if ($Field->AuthoringPrivilege() == 0)
01872             {
01873                 # just check if the user is the value of the field
01874                 return $AuthoringUserFieldValue == $User->Name();
01875             }
01876 
01877             # an authoring privilege is set, so check the privilege and
01878             # constraint
01879             else
01880             {
01881                 # OR user is value of field
01882                 if ($AuthoringUserIsValue == MetadataField::USERISVALUE_OR)
01883                 {
01884                     # user is value of the field, so short circuit
01885                     if ($AuthoringUserFieldValue == $User->Name())
01886                     {
01887                         return TRUE;
01888                     }
01889                 }
01890 
01891                 # AND user is value of field constraint, but user isn't the
01892                 # value, so short circuit
01893                 else if ($AuthoringUserFieldValue != $User->Name())
01894                 {
01895                     return FALSE;
01896                 }
01897 
01898                 # finally, if the logic hasn't been short circuited, check if
01899                 # the user has the authoring privilege
01900                 return $User->HasPriv($Field->AuthoringPrivilege());
01901             }
01902         }
01903     }
01904 
01905     # report whether user can author or edit the specified field
01906     function UserCanEditField($User, $FieldOrFieldName)
01907     {
01908         $Schema = new MetadataSchema();
01909 
01910         # fields hard-coded to be not allow edits
01911         $UneditableFields = array(
01912             "Cumulative Rating",
01913             "Date Of Record Creation",
01914             "Date Of Record Release",
01915             "Date Last Modified",
01916             "Last Modified By Id");
01917 
01918         # get field (if not supplied)
01919         if (is_object($FieldOrFieldName)
01920                 && ($FieldOrFieldName instanceof MetadataField))
01921         {
01922             $Field = $FieldOrFieldName;
01923         }
01924         elseif (strlen(trim($FieldOrFieldName)))
01925         {
01926             if ($Schema->FieldExists($FieldOrFieldName))
01927             {
01928                 $Field = $Schema->GetFieldByName($FieldOrFieldName);
01929             }
01930         }
01931 
01932         # the field must be valid and enabled to be editable
01933         if (!isset($Field) || !$Field->Enabled())
01934         {
01935             return FALSE;
01936         }
01937 
01938         # if field name does not appear on "no edit" list
01939         if (in_array($Field->Name(), $UneditableFields))
01940         {
01941             return FALSE;
01942         }
01943 
01944         # if the user can author the field, they can also edit it implicitly
01945         if ($this->UserCanAuthorField($User, $Field))
01946         {
01947             return TRUE;
01948         }
01949 
01950         # an "user is value of field" constraint isn't set, so only worry about
01951         # the editing privilege
01952         if ($Field->EditingUserIsValue() == MetadataField::USERISVALUE_UNSET)
01953         {
01954             # no editing privilege is set, so anyone can author the field
01955             if ($Field->EditingPrivilege() == 0)
01956             {
01957                 return TRUE;
01958             }
01959 
01960             # an editing privilege is set, so check if the user has it
01961             else
01962             {
01963                 return $User->HasPriv($Field->EditingPrivilege());
01964             }
01965         }
01966 
01967         # an "user is value of field" constraint is set
01968         else
01969         {
01970             $EditingUserIsValue = $Field->EditingUserIsValue();
01971             $EditingUserValue = $Field->EditingUserValue();
01972             $EditingUserField = $Schema->GetField($EditingUserValue);
01973             $EditingUserFieldValue = $this->Get($EditingUserField);
01974 
01975             # no editing privilege is set, so only check the constraint
01976             if ($Field->EditingPrivilege() == 0)
01977             {
01978                 # just check if the user is the value of the field
01979                 return $EditingUserFieldValue == $User->Name();
01980             }
01981 
01982             # an editing privilege is set, so check the privilege and
01983             # constraint
01984             else
01985             {
01986                 # OR user is value of field
01987                 if ($EditingUserIsValue == MetadataField::USERISVALUE_OR)
01988                 {
01989                     # user is value of the field, so short circuit
01990                     if ($EditingUserFieldValue == $User->Name())
01991                     {
01992                         return TRUE;
01993                     }
01994                 }
01995 
01996                 # AND user is value of field constraint, but user isn't the
01997                 # value, so short circuit
01998                 else if ($EditingUserFieldValue != $User->Name())
01999                 {
02000                     return FALSE;
02001                 }
02002 
02003                 # finally, if the logic hasn't been short circuited, check if
02004                 # the user has the editing privilege
02005                 return $User->HasPriv($Field->EditingPrivilege());
02006             }
02007         }
02008     }
02009 
02010     # ---- PRIVATE INTERFACE -------------------------------------------------
02011 
02012     private $DB;
02013     private $Schema;
02014     private $DBFields;
02015     private $Id;
02016     private $NumberOfRatings;
02017     private $CumulativeRating;
02018     private $NumberOfComments;
02019     private $Comments;
02020     private $LastStatus;
02021     private $ControlledNameCache;
02022     private $ControlledNameVariantCache;
02023     private $ClassificationCache;
02024 
02025     # recalculate and save cumulative rating value for resource
02026     private function UpdateCumulativeRating()
02027     {
02028         # grab totals from DB
02029         $this->DB->Query("SELECT COUNT(Rating) AS Count, "
02030                 ."SUM(Rating) AS Total FROM ResourceRatings "
02031                 ."WHERE ResourceId = ".$this->Id);
02032         $Record = $this->DB->FetchRow();
02033 
02034         # calculate new cumulative rating
02035         $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
02036 
02037         # save new cumulative rating in DB
02038         $this->DB->Query("UPDATE Resources "
02039                 ."SET CumulativeRating = ".$this->CumulativeRating." "
02040                 ."WHERE ResourceId = ".$this->Id);
02041     }
02042 
02043     # add intersection if not already present
02044     private function AddAssociation($TableName, $TargetFieldName, $TargetValue)
02045     {
02046         # if target not already associated with resource
02047         if ($this->DB->Query("SELECT COUNT(*) AS RecordCount FROM ".$TableName
02048                    ." WHERE ResourceId = ".$this->Id
02049                    ." AND ".$TargetFieldName." = '".$TargetValue."'",
02050                    "RecordCount") == 0)
02051         {
02052             # associate target with resource
02053             $this->DB->Query("INSERT INTO ".$TableName." SET"
02054                        ." ResourceId = ".$this->Id
02055                        .", ".$TargetFieldName." = '".$TargetValue."'");
02056         }
02057     }
02058 
02059     # remove intersections (if any)
02060     private function RemoveAssociation($TableName, $TargetFieldName, $TargetValue)
02061     {
02062         # remove any intersections with target ID from DB
02063         $this->DB->Query("DELETE FROM ".$TableName
02064                          ." WHERE ResourceId = ".$this->Id
02065                          ." AND ".$TargetFieldName." = '".$TargetValue."'");
02066     }
02067 
02068     # remove all intersections for resource and field (if any)
02069     private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
02070     {
02071         # retrieve list of entries for this field and resource
02072         $Entries = $this->Get($Field);
02073 
02074         # for each entry
02075         foreach ($Entries as $EntryId => $EntryName)
02076         {
02077             # remove intersection
02078             $this->RemoveAssociation($TableName, $TargetFieldName, $EntryId);
02079         }
02080     }
02081 }