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 }