CWIS Developer Documentation
Resource.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Resource.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
13 class Resource extends Item
14 {
15 
16  # ---- PUBLIC INTERFACE --------------------------------------------------
17 
25  public function __construct($ResourceId)
26  {
27  # call parent contstructor to load info from DB
28  parent::__construct($ResourceId);
29 
30  # load local attributes from database value cache
31  $this->CumulativeRating = $this->ValueCache["CumulativeRating"];
32 
33  # load our local metadata schema
34  $this->SchemaId = $this->ValueCache["SchemaId"];
35  if (!isset(self::$Schemas[$this->SchemaId]))
36  {
37  self::$Schemas[$this->SchemaId] =
38  new MetadataSchema($this->SchemaId);
39  }
40  }
41 
48  public static function Create($SchemaId)
49  {
50  # clean out any temp resource records more than three days old
51  $RFactory = new ResourceFactory();
52  $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
53 
54  # lock DB tables to prevent next ID from being grabbed
55  $DB = new Database;
56  $DB->Query("LOCK TABLES Resources WRITE");
57 
58  # find next temp resource ID
59  $Id = $RFactory->GetNextTempItemId();
60 
61  # write out new resource record with temp resource ID
62  # Set DateLastModified = NOW() to avoid being pruned as a
63  # stale temp resource.
64  $DB->Query(
65  "INSERT INTO Resources
66  SET `ResourceId` = '".intval($Id)."',
67  `SchemaId` = '".intval($SchemaId)."',
68  `DateLastModified` = NOW() " );
69 
70  # release DB tables
71  $DB->Query("UNLOCK TABLES");
72 
73  # create new Resource object
74  $Resource = new Resource($Id);
75 
76  # set some additional fields for default resources
77  if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
78  {
79  $Resource->Set("Date Of Record Creation", date("Y-m-d H:i:s"));
80  $Resource->Set("Date Last Modified", date("Y-m-d H:i:s"));
81  if ($GLOBALS["G_User"]->IsLoggedIn())
82  {
83  $Resource->Set("Added By Id", $GLOBALS["G_User"]->Id());
84  $Resource->Set("Last Modified By Id", $GLOBALS["G_User"]->Id());
85  }
86  }
87 
88  # for each field that can have a default value
89  $Schema = new MetadataSchema($SchemaId);
90  $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
95  foreach ($Fields as $Field)
96  {
97  # if there is a default value available
98  $DefaultValue = $Field->DefaultValue();
99  if ($DefaultValue !== NULL)
100  {
101  # if the default value is an array
102  if (is_array($DefaultValue))
103  {
104  # if there are values in the array
105  if (!empty($DefaultValue))
106  {
107  # flip values for Set() if necessary
108  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
109  {
110  $DefaultValue = array_flip($DefaultValue);
111  }
112 
113  # set default value
114  $Resource->Set($Field, $DefaultValue);
115  }
116  }
117  else
118  {
119  # set default value
120  $Resource->Set($Field, $DefaultValue);
121  }
122  }
123  }
124 
125  $Resource->UpdateAutoupdateFields(
127  $GLOBALS["G_User"]);
128 
129  # signal resource creation
130  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
131  "Resource" => $Resource,
132  ));
133 
134  # return new Resource object to caller
135  return $Resource;
136  }
137 
142  public function Delete()
143  {
144  global $SysConfig;
145 
146  # signal that resource deletion is about to occur
147  global $AF;
148  $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
149  "Resource" => $this,
150  ));
151 
152  # grab list of classifications
153  $Classifications = $this->Classifications();
154 
155  # delete resource/classification intersections
156  $DB = $this->DB;
157  $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
158 
159  # for each classification type
160  foreach ($Classifications as $ClassType => $ClassesOfType)
161  {
162  # for each classification of that type
163  foreach ($ClassesOfType as $ClassId => $ClassName)
164  {
165  # recalculate resource count for classification
166  $Class = new Classification($ClassId);
167  $Class->RecalcResourceCount();
168  }
169  }
170 
171  # delete resource references
172  $DB->Query("
173  DELETE FROM ReferenceInts
174  WHERE SrcResourceId = '".addslashes($this->Id())."'
175  OR DstResourceId = '".addslashes($this->Id())."'");
176 
177  # delete resource/name intersections
178  $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
179 
180  # delete resource/user intersections
181  $DB->Query("DELETE FROM ResourceUserInts WHERE ResourceId = ".$this->Id());
182 
183  # get the list of all images associated with this resource
184  $DB->Query("SELECT ImageId FROM ResourceImageInts"
185  ." WHERE ResourceId = ".intval($this->Id()));
186  $ImageIds = $DB->FetchColumn("ImageId");
187 
188  # disassociate this resource from all images
189  $DB->Query("DELETE FROM ResourceImageInts"
190  ." WHERE ResourceId = ".intval($this->Id()));
191 
192  # delete any images that no longer belong to any resources
193  foreach ($ImageIds as $ImageId)
194  {
195  $DB->Query("SELECT ResourceId FROM ResourceImageInts"
196  ." WHERE ImageId = ".intval($ImageId) );
197  if ($DB->NumRowsSelected() == 0)
198  {
199  $Image = new SPTImage($ImageId);
200  $Image->Delete();
201  }
202  }
203 
204  # delete any associated files
205  $Factory = new FileFactory(NULL);
206  $Files = $Factory->GetFilesForResource($this->Id());
207  foreach ($Files as $File)
208  {
209  $File->Delete();
210  }
211 
212  # delete resource record from database
213  $DB->Query("DELETE FROM Resources WHERE ResourceId = ".$this->Id());
214 
215  # drop item from search engine and recommender system
216  if ($SysConfig->SearchDBEnabled())
217  {
218  $SearchEngine = new SPTSearchEngine();
219  $SearchEngine->DropItem($this->Id());
220  }
221  if ($SysConfig->RecommenderDBEnabled())
222  {
223  $Recommender = new SPTRecommender();
224  $Recommender->DropItem($this->Id());
225  }
226 
227  # get the folders containing the resource
228  $FolderFactory = new FolderFactory();
229  $Folders = $FolderFactory->GetFoldersContainingItem(
230  $this->Id,
231  "Resource");
232 
233  # drop the resource from each folder it belongs to
234  foreach ($Folders as $Folder)
235  {
236  # mixed item type folder
237  if ($Folder->ContainsItem($this->Id, "Resource"))
238  {
239  $Folder->RemoveItem($this->Id, "Resource");
240  }
241 
242  # single item type folder
243  else
244  {
245  $Folder->RemoveItem($this->Id);
246  }
247  }
248 
249  # delete any resource comments
250  $DB->Query("DELETE FROM Messages WHERE ParentId = ".$this->Id);
251  }
252 
259  public function UpdateAutoupdateFields($UpdateType, $User=NULL)
260  {
261  # update all the timestamp fields as required
262  $TimestampFields = $this->Schema()->GetFields(
264  foreach ($TimestampFields as $Field)
265  {
266  if ($Field->UpdateMethod() == $UpdateType)
267  {
268  $this->Set($Field, "now");
269  }
270  }
271 
272  # if a user was provided, update the user fields as well
273  if (!is_null($User) && !$User->IsAnonymous())
274  {
275  $UserFields = $this->Schema()->GetFields(
277  foreach ($UserFields as $Field)
278  {
279  if ($Field->UpdateMethod() == $UpdateType)
280  {
281  $this->Set($Field, $User);
282  }
283  }
284  }
285  }
286 
291  public function Id()
292  {
293  return $this->Id;
294  }
295 
300  public function SchemaId()
301  {
302  return $this->SchemaId;
303  }
304 
309  public function Schema()
310  {
311  return self::$Schemas[$this->SchemaId];
312  }
313 
320  public function IsTempResource($NewSetting = NULL)
321  {
322  # if new temp resource setting supplied
323  if (!is_null($NewSetting))
324  {
325  # if caller requested to switch
326  $DB = $this->DB;
327  if ((($this->Id() < 0) && ($NewSetting == FALSE))
328  || (($this->Id() >= 0) && ($NewSetting == TRUE)))
329  {
330  $Factory = new ResourceFactory($this->SchemaId);
331 
332  # lock DB tables to prevent next ID from being grabbed
333  $DB->Query("LOCK TABLES Resources WRITE");
334 
335  # get next resource ID as appropriate
336  $OldResourceId = $this->Id;
337  if ($NewSetting == TRUE)
338  {
339  $this->Id = $Factory->GetNextTempItemId();
340  }
341  else
342  {
343  $this->Id = $Factory->GetNextItemId();
344  }
345 
346  # change resource ID
347  $DB->Query("UPDATE Resources SET ResourceId = ".
348  $this->Id. " WHERE ResourceId = ".$OldResourceId);
349 
350  # release DB tables
351  $DB->Query("UNLOCK TABLES");
352 
353  # change associations
354  unset($this->ClassificationCache);
355  $DB->Query("UPDATE ResourceClassInts SET ResourceId = ".
356  $this->Id. " WHERE ResourceId = ".$OldResourceId);
357  unset($this->ControlledNameCache);
358  unset($this->ControlledNameVariantCache);
359  $DB->Query("UPDATE ResourceNameInts SET ResourceId = ".
360  $this->Id. " WHERE ResourceId = ".$OldResourceId);
361  $DB->Query("UPDATE Files SET ResourceId = ".
362  $this->Id. " WHERE ResourceId = ".$OldResourceId);
363  $DB->Query("UPDATE ReferenceInts SET SrcResourceId = ".
364  $this->Id. " WHERE SrcResourceId = ".$OldResourceId);
365  $DB->Query("UPDATE ResourceImageInts SET ResourceId = ".
366  $this->Id. " WHERE ResourceId = ".$OldResourceId);
367  $DB->Query("UPDATE ResourceUserInts SET ResourceId = ".
368  $this->Id. " WHERE ResourceId = ".$OldResourceId);
369 
370  # signal event as appropriate
371  if ($NewSetting === FALSE)
372  {
373  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_ADD", array(
374  "Resource" => $this,
375  ));
376  }
377  }
378  }
379 
380  # report to caller whether we are a temp resource
381  return ($this->Id() < 0) ? TRUE : FALSE;
382  }
383 
384 
385  # --- Generic Attribute Retrieval Methods -------------------------------
386 
391  public function GetViewPageUrl()
392  {
393  # put our Id into the ViewPage from our schema
394  $Url = str_replace(
395  "\$ID", $this->Id(),
396  $this->Schema()->ViewPage());
397 
398  # return clean url, if one is available
399  return $GLOBALS["AF"]->GetCleanUrlForPath($Url);
400  }
401 
415  public function Get($Field, $ReturnObject = FALSE, $IncludeVariants = FALSE)
416  {
417  # load field object if not already supplied
418  $Field = is_object($Field) ? $Field : $this->Schema()->GetField($Field);
419 
420  if ($Field->SchemaId() != $this->SchemaId())
421  {
422  throw new Exception("Attempt to get a value for a field"
423  ." from a different schema."
424  ." (Field: ".$Field->Name()." [".$Field->Id()
425  ."], Field Schema: ".$Field->SchemaId()
426  .", Resource Schema: ".$this->SchemaId()
427  .")");
428  }
429 
430  # grab database field name
431  $DBFieldName = $Field->DBFieldName();
432 
433  # format return value based on field type
434  switch ($Field->Type())
435  {
439  $ReturnValue = isset($this->ValueCache[$DBFieldName])
440  ? (string)$this->ValueCache[$DBFieldName] : NULL;
441  break;
442 
444  $ReturnValue = isset($this->ValueCache[$DBFieldName])
445  ? (int)$this->ValueCache[$DBFieldName] : NULL;
446  break;
447 
449  $ReturnValue = isset($this->ValueCache[$DBFieldName])
450  ? (bool)$this->ValueCache[$DBFieldName] : NULL;
451  break;
452 
454  $ReturnValue = array("X" => (float)$this->ValueCache[$DBFieldName."X"],
455  "Y" => (float)$this->ValueCache[$DBFieldName."Y"]);
456  break;
457 
459  $Date = new Date($this->ValueCache[$DBFieldName."Begin"],
460  $this->ValueCache[$DBFieldName."End"],
461  $this->ValueCache[$DBFieldName."Precision"]);
462  if ($ReturnObject)
463  {
464  $ReturnValue = $Date;
465  }
466  else
467  {
468  $ReturnValue = $Date->Formatted();
469  }
470  break;
471 
473  $ReturnValue = $this->ValueCache[$DBFieldName];
474  break;
475 
477  # start with empty array
478  $ReturnValue = array();
479 
480  # if classification cache has not been loaded
481  if (!isset($this->ClassificationCache))
482  {
483  # load all classifications associated with this resource into cache
484  $this->ClassificationCache = array();
485  $this->DB->Query(
486  "SELECT Classifications.ClassificationId,"
487  ." Classifications.FieldId,ClassificationName"
488  ." FROM ResourceClassInts, Classifications"
489  ." WHERE ResourceClassInts.ResourceId = ".$this->Id
490  ." AND ResourceClassInts.ClassificationId"
491  ." = Classifications.ClassificationId");
492  while ($Record = $this->DB->FetchRow())
493  {
494  $ClassId = $Record["ClassificationId"];
495  $this->ClassificationCache[$ClassId]["Name"]
496  = $Record["ClassificationName"];
497  $this->ClassificationCache[$ClassId]["FieldId"]
498  = $Record["FieldId"];
499  }
500  }
501  # for each entry in classification cache
502  foreach ($this->ClassificationCache as
503  $ClassificationId => $ClassificationInfo)
504  {
505  # if classification ID matches field we are looking for
506  if ($ClassificationInfo["FieldId"] == $Field->Id())
507  {
508  # add field to result
509  if ($ReturnObject)
510  {
511  $ReturnValue[$ClassificationId] =
512  new Classification($ClassificationId);
513  }
514  else
515  {
516  $ReturnValue[$ClassificationId] = $ClassificationInfo["Name"];
517  }
518  }
519  }
520  break;
521 
524  # start with empty array
525  $ReturnValue = array();
526 
527  # if controlled name cache has not been loaded
528  if (!isset($this->ControlledNameCache))
529  {
530  # load all controlled names associated with this resource into cache
531  $this->ControlledNameCache = array();
532  $this->DB->Query(
533  "SELECT ControlledNames.ControlledNameId,"
534  ." ControlledNames.FieldId,ControlledName"
535  ." FROM ResourceNameInts, ControlledNames"
536  ." WHERE ResourceNameInts.ResourceId = ".$this->Id
537  ." AND ResourceNameInts.ControlledNameId"
538  ." = ControlledNames.ControlledNameId"
539  ." ORDER BY ControlledNames.ControlledName ASC");
540  while ($Record = $this->DB->FetchRow())
541  {
542  $CNameId = $Record["ControlledNameId"];
543  $this->ControlledNameCache[$CNameId]["Name"]
544  = $Record["ControlledName"];
545  $this->ControlledNameCache[$CNameId]["FieldId"]
546  = $Record["FieldId"];
547  }
548  }
549 
550  # if variant names requested and variant name cache has not been loaded
551  if ($IncludeVariants && !isset($this->ControlledNameVariantCache))
552  {
553  # load all controlled names associated with this resource into cache
554  $this->ControlledNameVariantCache = array();
555  $this->DB->Query("SELECT ControlledNames.ControlledNameId,"
556  ." ControlledNames.FieldId,"
557  ." ControlledName, VariantName"
558  ." FROM ResourceNameInts, ControlledNames, VariantNames"
559  ." WHERE ResourceNameInts.ResourceId = ".$this->Id
560  ." AND ResourceNameInts.ControlledNameId"
561  ." = ControlledNames.ControlledNameId"
562  ." AND VariantNames.ControlledNameId"
563  ." = ControlledNames.ControlledNameId");
564  while ($Record = $this->DB->FetchRow())
565  {
566  $this->ControlledNameVariantCache[$Record["ControlledNameId"]][]
567  = $Record["VariantName"];
568  }
569  }
570 
571  # for each entry in controlled name cache
572  foreach ($this->ControlledNameCache as
573  $CNameId => $ControlledNameInfo)
574  {
575  # if controlled name type matches field we are looking for
576  if ($ControlledNameInfo["FieldId"] == $Field->Id())
577  {
578  # if objects requested
579  if ($ReturnObject)
580  {
581  $ReturnValue[$CNameId] =
582  new ControlledName($CNameId);
583  }
584  else
585  {
586  # if variant names requested
587  if ($IncludeVariants)
588  {
589  # add field to result
590  $ReturnValue[] = $ControlledNameInfo["Name"];
591 
592  # add any variant names to result
593  if (isset($this->ControlledNameVariantCache[$CNameId]))
594  {
595  $ReturnValue = array_merge(
596  $ReturnValue,
597  $this->ControlledNameVariantCache[$CNameId]);
598  }
599  }
600  else
601  {
602  # add field with index to result
603  $ReturnValue[$CNameId] =
604  $ControlledNameInfo["Name"];
605  }
606  }
607  }
608  }
609  break;
610 
612  # start out assuming no associated users
613  $ReturnValue = array();
614 
615  # query the database to get the associated userids
616  $this->DB->Query(
617  "SELECT UserId FROM ResourceUserInts WHERE ".
618  "ResourceId=".intval($this->Id).
619  " AND FieldId=".intval($Field->Id())
620  ." AND UserId IN (SELECT UserId FROM APUsers)"
621  );
622  $UserIds = $this->DB->FetchColumn("UserId");
623 
624  # convert each userid to either a name or a CWUser object
625  foreach ($UserIds as $UserId)
626  {
627  $User = new CWUser(intval($UserId));
628  if ($ReturnObject)
629  {
630  $ReturnValue[$UserId] = $User;
631  }
632  else
633  {
634  $ReturnValue[$UserId] = $User->Get("UserName");
635  }
636  }
637  break;
638 
640  # start out assuming no images will be found
641  $ReturnValue = array();
642 
643  # find all images associated with this resource
644  $this->DB->Query("SELECT ImageId FROM ResourceImageInts"
645  ." WHERE ResourceId = ".intval($this->Id())
646  ." AND FieldId = ".intval($Field->Id()));
647 
648  # if images were found
649  if ($this->DB->NumRowsSelected())
650  {
651  # if we are to return an object
652  $ImageIds = $this->DB->FetchColumn("ImageId");
653  if ($ReturnObject)
654  {
655  # load array of Image objects for return value
656  foreach ($ImageIds as $ImageId)
657  {
658  $ReturnValue[$ImageId] = new SPTImage($ImageId);
659  }
660  }
661  else
662  {
663  # load array of Image ids for return value
664  $ReturnValue = $ImageIds;
665  }
666  }
667  break;
668 
670  # retrieve files using factory
671  $Factory = new FileFactory($Field->Id());
672  $ReturnValue = $Factory->GetFilesForResource(
673  $this->Id, $ReturnObject);
674  break;
675 
677  # query for resource references
678  $this->DB->Query("
679  SELECT * FROM ReferenceInts
680  WHERE FieldId = '".addslashes($Field->Id())."'
681  AND SrcResourceId = '".addslashes($this->Id())."'");
682 
683  $ReturnValue = array();
684 
685  # return each reference as a Resource object
686  if ($ReturnObject)
687  {
688  $FoundErrors = FALSE;
689 
690  while (FALSE !== ($Record = $this->DB->FetchRow()))
691  {
692  $ReferenceId = $Record["DstResourceId"];
693  $Reference = new Resource($ReferenceId);
694  $ReturnValue[$ReferenceId] = $Reference;
695  }
696  }
697 
698  # return each reference as a resource ID
699  else
700  {
701  while (FALSE !== ($Record = $this->DB->FetchRow()))
702  {
703  $ReferenceId = $Record["DstResourceId"];
704  $ReturnValue[$ReferenceId] = $ReferenceId;
705  }
706  }
707  break;
708 
709  default:
710  # ERROR OUT
711  exit("<br>SPT - ERROR: attempt to retrieve "
712  ."unknown resource field type (".$Field->Type().")<br>\n");
713  break;
714  }
715 
716  # return formatted value to caller
717  return $ReturnValue;
718  }
719 
739  public function GetForDisplay(
740  $FieldNameOrObject, $ReturnObject = TRUE, $IncludeVariants = FALSE)
741  {
742  # normalize metadata field for use by any hooked code
743  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
744  : $this->Schema()->GetFieldByName($FieldNameOrObject);
745 
746  # retrieve value
747  $Value = $this->Get($Field, $ReturnObject, $IncludeVariants);
748 
749  # signal event to allowed hooked code to modify value
750  $SignalResult = $GLOBALS["AF"]->SignalEvent(
751  "EVENT_FIELD_DISPLAY_FILTER", array(
752  "Field" => $Field,
753  "Resource" => $this,
754  "Value" => $Value));
755 
756  # return possibly modified value to caller
757  return $SignalResult["Value"];
758  }
759 
775  public function GetByField($FieldNameOrObject,
776  $ReturnObject = FALSE, $IncludeVariants = FALSE)
777  {
778  return $this->Get($FieldNameOrObject, $ReturnObject, $IncludeVariants);
779  }
780 
795  public function GetByFieldId(
796  $FieldId, $ReturnObject = FALSE, $IncludeVariants = FALSE)
797  {
798  return $this->Get($FieldId, $ReturnObject, $IncludeVariants);
799  }
800 
813  public function GetAsArray($IncludeDisabledFields = FALSE, $ReturnObjects = TRUE)
814  {
815  # retrieve field info
816  $Fields = $this->Schema()->GetFields();
817 
818  # for each field
819  foreach ($Fields as $Field)
820  {
821  # if field is enabled or caller requested disabled fields
822  if ($Field->Enabled() || $IncludeDisabledFields)
823  {
824  # retrieve info and add it to the array
825  $FieldStrings[$Field->Name()] = $this->Get($Field, $ReturnObjects);
826 
827  # if field uses qualifiers
828  if ($Field->UsesQualifiers())
829  {
830  # get qualifier attributes and add to the array
831  $FieldStrings[$Field->Name()." Qualifier"] =
832  $this->GetQualifierByField($Field, $ReturnObjects);
833  }
834  }
835  }
836 
837  # add in internal values
838  $FieldStrings["ResourceId"] = $this->Id();
839  $FieldStrings["CumulativeRating"] = $this->CumulativeRating();
840 
841  # return array to caller
842  return $FieldStrings;
843  }
844 
859  public function GetMapped(
860  $MappedName, $ReturnObject = FALSE, $IncludeVariants = FALSE)
861  {
862  $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
863  return $FieldId
864  ? $this->Get($FieldId, $ReturnObject, $IncludeVariants)
865  : NULL;
866  }
867 
876  public function GetQualifier($FieldName, $ReturnObject = TRUE)
877  {
878  $Field = $this->Schema()->GetFieldByName($FieldName);
879  return $this->GetQualifierByField($Field, $ReturnObject);
880  }
881 
890  public function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
891  {
892  $Field = $this->Schema()->GetField($FieldId);
893  return ($Field) ? $this->GetQualifierByField($Field, $ReturnObject) : NULL;
894  }
895 
904  public function GetQualifierByField($Field, $ReturnObject = TRUE)
905  {
906  # return NULL if field is invalid
907  if (!($Field instanceof MetadataField)) { return NULL; }
908 
909  # assume no qualifiers if not otherwise determined
910  $ReturnValue = NULL;
911 
912  # if field uses qualifiers
913  if ($Field->UsesQualifiers())
914  {
915  # retrieve qualifiers based on field type
916  switch ($Field->Type())
917  {
921  # retrieve list of items
922  $Items = $this->Get($Field);
923 
924  # if field uses item-level qualifiers
925  if ($Field->HasItemLevelQualifiers())
926  {
927  # determine general item name in DB
928  $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
929  ? "Classification" : "ControlledName";
930 
931  # for each item
932  foreach ($Items as $ItemId => $ItemName)
933  {
934  # look up qualifier for item
935  $QualId = $this->DB->Query(
936  "SELECT * FROM ".$TableName."s"
937  ." WHERE ".$TableName."Id = ".$ItemId,
938  "QualifierId");
939 
940 
941  if ($QualId > 0)
942  {
943  # if object was requested by caller
944  if ($ReturnObject)
945  {
946  # load qualifier and add to return value array
947  $ReturnValue[$ItemId] = new Qualifier($QualId);
948  }
949  else
950  {
951  # add qualifier ID to return value array
952  $ReturnValue[$ItemId] = $QualId;
953  }
954  }
955  else
956  {
957  # add NULL to return value array for this item
958  $ReturnValue[$ItemId] = NULL;
959  }
960  }
961  }
962  else
963  {
964  # for each item
965  foreach ($Items as $ItemId => $ItemName)
966  {
967  # if object was requested by caller
968  if ($ReturnObject)
969  {
970  # load default qualifier and add to return value array
971  $ReturnValue[$ItemId] = new Qualifier(
972  $Field->DefaultQualifier());
973  }
974  else
975  {
976  # add default qualifier ID to return value array
977  $ReturnValue[$ItemId] = $Field->DefaultQualifier();
978  }
979  }
980  }
981  break;
982 
983  default:
984  # if field uses item-level qualifiers
985  if ($Field->HasItemLevelQualifiers())
986  {
987  # if qualifier available
988  if ($this->ValueCache[$Field->DBFieldName()."Qualifier"] > 0)
989  {
990  # if object was requested by caller
991  $QFieldName = $Field->DBFieldName()."Qualifier";
992  if ($ReturnObject)
993  {
994  # return qualifier for field
995  $ReturnValue = new Qualifier(
996  $this->ValueCache[$QFieldName]);
997  }
998  else
999  {
1000  # return qualifier ID for field
1001  $ReturnValue = $this->ValueCache[$QFieldName];
1002  }
1003  }
1004  }
1005  else
1006  {
1007  # if default qualifier available
1008  if ($Field->DefaultQualifier() > 0)
1009  {
1010  # if object was requested by caller
1011  if ($ReturnObject)
1012  {
1013  # return default qualifier
1014  $ReturnValue = new Qualifier($Field->DefaultQualifier());
1015  }
1016  else
1017  {
1018  # return default qualifier ID
1019  $ReturnValue = $Field->DefaultQualifier();
1020  }
1021  }
1022  }
1023  break;
1024  }
1025  }
1026 
1027  # return qualifier object or ID (or array of same) to caller
1028  return $ReturnValue;
1029  }
1030 
1038  public function FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
1039  {
1040  # load field object if needed
1041  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1042  : $this->Schema()->GetFieldByName($FieldNameOrObject);
1043 
1044  # return no value found if we don't have a valid field
1045  if (!($Field instanceof MetadataField)) { return FALSE; }
1046 
1047  # get the value
1048  $Value = $this->Get($Field);
1049 
1050  # checks depend on the field type
1051  switch ($Field->Type())
1052  {
1057  return isset($Value)
1058  && strlen($Value)
1059  && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1060 
1062  return isset($Value)
1063  && strlen($Value);
1064 
1066  return isset($Value["X"])
1067  && isset($Value["Y"])
1068  && strlen(trim($Value["X"]))
1069  && strlen(trim($Value["Y"]));
1070 
1072  return isset($Value)
1073  && strlen(trim($Value))
1074  && $Value != "0000-00-00";
1075 
1077  return isset($Value)
1078  && strlen(trim($Value))
1079  && $Value != "0000-00-00 00:00:00";
1080 
1087  return count($Value) > 0;
1088 
1090  $Factory = new CWUserFactory();
1091  return isset($Value)
1092  && strlen($Value)
1093  && $Factory->UserNameExists($Value);
1094 
1095  default:
1096  return FALSE;
1097  }
1098  }
1099 
1108  public function GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
1109  {
1110  $Result = array();
1111 
1112  # get our target field and extract its values
1113  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1114  : $this->Schema()->GetField($FieldNameOrObject);
1115  $Images = $this->Get($Field, TRUE);
1116 
1117  # iterate over our images getting URLs for each
1118  $Index = 0;
1119  foreach ($Images as $Image)
1120  {
1121  $Result[$Image->Id()] = $Image->GetImageUrlForResource(
1122  $this->Id(), $Field->Id(), $Index, $ImageSize);
1123  $Index++;
1124  }
1125 
1126  return $Result;
1127  }
1128 
1129  # --- Generic Attribute Setting Methods ---------------------------------
1130 
1143  public function Set($Field, $NewValue, $Reset=FALSE)
1144  {
1145  # load field object if not already supplied
1146  $Field = is_object($Field) ? $Field
1147  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
1148  : $this->Schema()->GetFieldByName($Field));
1149 
1150  # return if we don't have a valid field
1151  if (!($Field instanceof MetadataField)) { return; }
1152 
1153  if ($Field->SchemaId() != $this->SchemaId())
1154  {
1155  throw new Exception("Attempt to set a value for a field "
1156  ."from a different schema.");
1157  }
1158 
1159  # grab commonly-used values for local use
1160  $DB = $this->DB;
1161  $ResourceId = $this->Id;
1162 
1163  # grab database field name
1164  $DBFieldName = $Field->DBFieldName();
1165 
1166  # Flag to deterimine if we've actually changed anything.
1167  $UpdateModTime = FALSE;
1168 
1169  # store value in DB based on field type
1170  switch ($Field->Type())
1171  {
1175  if ($this->ValueCache[$DBFieldName] != $NewValue)
1176  {
1177  # save value directly to DB
1178  $DB->Query("UPDATE Resources SET `"
1179  .$DBFieldName."` = '".addslashes($NewValue)."' "
1180  ."WHERE ResourceId = ".$ResourceId);
1181 
1182  # save value locally
1183  $this->ValueCache[$DBFieldName] = $NewValue;
1184  $UpdateModTime=TRUE;
1185  }
1186  break;
1187 
1189  if ( $this->ValueCache[$DBFieldName] != $NewValue )
1190  {
1191  # save value directly to DB
1192  if (is_null($NewValue))
1193  {
1194  $DB->Query("UPDATE Resources SET `"
1195  .$DBFieldName."` = NULL"
1196  ." WHERE ResourceId = ".$ResourceId);
1197  }
1198  else
1199  {
1200  $DB->Query("UPDATE Resources SET `"
1201  .$DBFieldName."` = ".intval($NewValue)
1202  ." WHERE ResourceId = ".$ResourceId);
1203  }
1204 
1205  # save value locally
1206  $this->ValueCache[$DBFieldName] = $NewValue;
1207  $UpdateModTime = TRUE;
1208  }
1209  break;
1210 
1211 
1213  if ($this->ValueCache[$DBFieldName."X"] != $NewValue["X"] ||
1214  $this->ValueCache[$DBFieldName."Y"] != $NewValue["Y"] )
1215  {
1216  if (is_null($NewValue))
1217  {
1218  $DB->Query("UPDATE Resources SET "
1219  ."`".$DBFieldName."X` = NULL, "
1220  ."`".$DBFieldName."Y` = NULL "
1221  ."WHERE ResourceId = ".$ResourceId);
1222  $this->ValueCache[$DBFieldName."X"] = NULL;
1223  $this->ValueCache[$DBFieldName."Y"] = NULL;
1224  }
1225  else
1226  {
1227  $DB->Query("UPDATE Resources SET "
1228  ."`".$DBFieldName."X` = " .(strlen($NewValue["X"])
1229  ? "'".$NewValue["X"]."'" : "NULL").", "
1230  ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
1231  ? "'".$NewValue["Y"]."'" : "NULL")
1232  ." WHERE ResourceId = ".$ResourceId);
1233 
1234  $Digits = $Field->PointDecimalDigits();
1235 
1236  $this->ValueCache[$DBFieldName."X"] =
1237  strlen($NewValue["X"]) ?
1238  round($NewValue["X"], $Digits) : NULL;
1239  $this->ValueCache[$DBFieldName."Y"] =
1240  strlen($NewValue["Y"]) ?
1241  round($NewValue["Y"], $Digits) : NULL;
1242  }
1243  $UpdateModTime = TRUE;
1244  }
1245  break;
1246 
1248  if ($this->ValueCache[$DBFieldName] != $NewValue)
1249  {
1250  # save value directly to DB
1251  if (is_null($NewValue))
1252  {
1253  $DB->Query("UPDATE Resources SET `"
1254  .$DBFieldName."` = NULL"
1255  ." WHERE ResourceId = ".$ResourceId);
1256  }
1257  else
1258  {
1259  $NewValue = $NewValue ? "1" : "0";
1260  $DB->Query("UPDATE Resources SET `"
1261  .$DBFieldName."` = ".$NewValue
1262  ." WHERE ResourceId = ".$ResourceId);
1263  }
1264 
1265  $this->ValueCache[$DBFieldName] = $NewValue;
1266 
1267  $UpdateModTime = TRUE;
1268  }
1269  break;
1270 
1272  $OldValue = $this->Get($Field);
1273  # value comes back as array (UserId => UserName), just get the Ids
1274  $OldValue = array_keys($OldValue);
1275 
1276  # input to Set() for these fields is one of
1277  # 1. an int specifying a UserId
1278  if (is_numeric($NewValue))
1279  {
1280  $NewValue = array($NewValue);
1281  }
1282  # 2. a CWUser object
1283  elseif ($NewValue instanceof CWUser)
1284  {
1285  $NewValue = array($NewValue->Id());
1286  }
1287  # 3. an array keyed by UserId (don't care about the values)
1288  elseif (is_array($NewValue))
1289  {
1290  $NewValue = array_keys($NewValue);
1291  }
1292  else
1293  {
1294  throw new Exception("Unknown format for NewValue in a User field");
1295  }
1296 
1297  # if this is a unique field, only accept the first of the options given
1298  if ($Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1299  {
1300  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1301  }
1302 
1303  # sort new and old values so we can directly compare
1304  sort($OldValue);
1305  sort($NewValue);
1306 
1307  # if the value has changed
1308  if ($OldValue != $NewValue)
1309  {
1310  if ($Reset || $Field->AllowMultiple() == FALSE )
1311  {
1312  $ToRemove = array_diff($OldValue, $NewValue);
1313  $this->RemoveAssociation(
1314  "ResourceUserInts", "UserId", $ToRemove, $Field);
1315  }
1316 
1317  # associate with resource if not already associated
1318  $this->AddAssociation("ResourceUserInts",
1319  "UserId",
1320  $NewValue, $Field);
1321 
1322  $UpdateModTime=TRUE;
1323  }
1324  break;
1325 
1327  # if we were given a date object
1328  if (is_object($NewValue))
1329  {
1330  # use supplied date object
1331  $Date = $NewValue;
1332  }
1333  else
1334  {
1335  # create date object
1336  $Date = new Date($NewValue);
1337  }
1338 
1339  $OldDate = new Date(
1340  $this->ValueCache[$DBFieldName."Begin"],
1341  $this->ValueCache[$DBFieldName."End"]);
1342 
1343  if ($OldDate->BeginDate() != $Date->BeginDate() ||
1344  $OldDate->EndDate() != $Date->EndDate() ||
1345  $OldDate->Precision() != $Date->Precision() )
1346  {
1347  # extract values from date object and store in DB
1348  $BeginDate = "'".$Date->BeginDate()."'";
1349  if (strlen($BeginDate) < 3) { $BeginDate = "NULL"; }
1350  $EndDate = "'".$Date->EndDate()."'";
1351  if (strlen($EndDate) < 3) { $EndDate = "NULL"; }
1352 
1353  $DB->Query("UPDATE Resources SET "
1354  .$DBFieldName."Begin = ".$BeginDate.", "
1355  .$DBFieldName."End = ".$EndDate.", "
1356  .$DBFieldName."Precision = '".$Date->Precision()."' "
1357  ."WHERE ResourceId = ".$ResourceId);
1358 
1359  # save values locally
1360  $this->ValueCache[$DBFieldName."Begin"] = $Date->BeginDate();
1361  $this->ValueCache[$DBFieldName."End"] = $Date->EndDate();
1362  $this->ValueCache[$DBFieldName."Precision"] = $Date->Precision();
1363  $UpdateModTime=TRUE;
1364  }
1365  break;
1366 
1368  if (is_null($NewValue) || !strlen(trim($NewValue)))
1369  {
1370  $DateValue = $NewValue;
1371 
1372  if (!is_null($this->ValueCache[$DBFieldName]))
1373  {
1374  # save value directly to DB
1375  $DB->Query("UPDATE Resources SET "
1376  ."`".$DBFieldName."` = NULL "
1377  ."WHERE ResourceId = ".$ResourceId);
1378  $UpdateModTime = TRUE;
1379  }
1380  }
1381  else
1382  {
1383  # assume value is date and use directly
1384  $TimestampValue = strtotime($NewValue);
1385 
1386  # use the new value if the date is valid
1387  if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1388  {
1389  $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1390 
1391  if ($this->ValueCache[$DBFieldName] != $DateValue)
1392  {
1393  # save value directly to DB
1394  $DB->Query("UPDATE Resources SET "
1395  ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1396  ."WHERE ResourceId = ".$ResourceId);
1397  $UpdateModTime=TRUE;
1398  }
1399  }
1400 
1401  # continue using the old value if invalid
1402  else
1403  {
1404  $DateValue = $this->Get($Field);
1405  }
1406  }
1407 
1408  # save value locally
1409  $this->ValueCache[$DBFieldName] = $DateValue;
1410  break;
1411 
1413  $OldValue = $this->Get($Field);
1414 
1415  # if incoming value is array
1416  if (is_array($NewValue))
1417  {
1418  if ($OldValue != $NewValue)
1419  {
1420  if ($Reset)
1421  {
1422  # remove values that were in the old value
1423  # but not the new one
1424  $ToRemove = array_diff(array_keys($OldValue),
1425  array_keys($NewValue));
1426  foreach ($ToRemove as $ClassificationId)
1427  {
1428  $this->RemoveAssociation("ResourceClassInts",
1429  "ClassificationId",
1430  $ClassificationId);
1431  $Class = new Classification($ClassificationId);
1432  $Class->RecalcResourceCount();
1433  }
1434  }
1435 
1436  # for each element of array
1437  foreach ($NewValue as
1438  $ClassificationId => $ClassificationName)
1439  {
1440  $Class = new Classification($ClassificationId);
1441  if ($Class->FieldId() == $Field->Id())
1442  {
1443  # associate with resource if not already associated
1444  if ($this->AddAssociation("ResourceClassInts",
1445  "ClassificationId", $ClassificationId))
1446  {
1447  $Class->UpdateLastAssigned();
1448  $Class->RecalcResourceCount();
1449  }
1450  }
1451  else
1452  {
1453  throw new Exception(
1454  "Attempting to store classification from "
1455  ."Field ".$Class->FieldId()." into Field "
1456  .$Field->Id() );
1457  }
1458 
1459  }
1460 
1461  $UpdateModTime=TRUE;
1462  }
1463  }
1464  else
1465  {
1466  # associate with resource if not already associated
1467  if (is_object($NewValue))
1468  {
1469  $Class = $NewValue;
1470  $NewValue = $Class->Id();
1471  }
1472  else
1473  {
1474  $Class = new Classification($NewValue);
1475  }
1476 
1477  if (!array_key_exists($Class->Id(), $OldValue))
1478  {
1479 
1480  $this->AddAssociation("ResourceClassInts",
1481  "ClassificationId",
1482  $NewValue);
1483  $Class->UpdateLastAssigned();
1484  $Class->RecalcResourceCount();
1485  $UpdateModTime=TRUE;
1486  }
1487  }
1488 
1489  # clear our classification cache
1490  if ($UpdateModTime)
1491  {
1492  unset($this->ClassificationCache);
1493  }
1494  break;
1495 
1498  $OldValue = $this->Get($Field);
1499 
1500  # input to Set() for these fields is one of
1501  # 1. an int specifying a ControlledNameId
1502  # 2. a ControlledName object
1503  # 3. an array with keys giving Ids and values giving ControlledNames
1504  #
1505  # normalize 1 and 2 into 3 for simplicity of processing
1506  if (is_object($NewValue) || !is_array($NewValue) )
1507  {
1508  if (!is_object($NewValue))
1509  {
1510  $NewValue = new ControlledName($NewValue);
1511  }
1512 
1513  $TmpValue = array();
1514  $TmpValue[$NewValue->Id()] = $NewValue->Name();
1515 
1516  $NewValue = $TmpValue;
1517  }
1518 
1519  # if this is a unique field, only accept the first of the options given
1520  # NB: all ControlledNames implicitly AllowMultiple
1521  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1522  $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1523  {
1524  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1525  }
1526 
1527  # if the value has changed
1528  if ($OldValue != $NewValue)
1529  {
1530  if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1531  && $Field->AllowMultiple() == FALSE ) )
1532  {
1533  $ToRemove = array_diff(array_keys($OldValue),
1534  array_keys($NewValue));
1535  foreach ($ToRemove as $CNId)
1536  {
1537  $this->RemoveAssociation("ResourceNameInts",
1538  "ControlledNameId",
1539  $CNId);
1540  }
1541  }
1542 
1543  # for each element of array
1544  foreach ($NewValue as $ControlledNameId => $ControlledName)
1545  {
1546  # associate with resource if not already associated
1547  if ($this->AddAssociation("ResourceNameInts",
1548  "ControlledNameId",
1549  $ControlledNameId))
1550  {
1551  $CN = new ControlledName($ControlledNameId);
1552  if ($CN->Status() != ControlledName::STATUS_OK)
1553  {
1554  $this->RemoveAssociation("ResourceNameInts",
1555  "ControlledNameId", $ControlledNameId);
1556  throw new InvalidArgumentException(
1557  "Attempt to set controlled name with"
1558  ." invalid ID (".$ControlledNameId.").");
1559  }
1560  $CN->UpdateLastAssigned();
1561  }
1562  }
1563  $UpdateModTime = TRUE;
1564  }
1565 
1566  if ($UpdateModTime)
1567  {
1568  # clear our controlled name cache
1569  unset($this->ControlledNameCache);
1570  unset($this->ControlledNameVariantCache);
1571 
1572  # clear visible count cache for any affected resources
1573  $ValueIds = array_keys($OldValue) + array_keys($NewValue);
1574  $DB->Query(
1575  "DELETE FROM VisibleResourceCounts WHERE "
1576  ."SchemaId=".intval($this->SchemaId)." AND "
1577  ."ValueId IN (".implode(",", $ValueIds).")");
1578  }
1579 
1580  break;
1581 
1583  # associate value(s) with resource
1584  $this->AddAssociation(
1585  "ResourceImageInts", "ImageId", $NewValue, $Field);
1586  # clear cached image mappings
1587  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1588  break;
1589 
1591  # convert incoming value to array if necessary
1592  if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1593 
1594  # for each incoming file
1595  $Factory = new FileFactory($Field->Id());
1596  foreach ($NewValue as $File)
1597  {
1598  # make copy of file
1599  $NewFile = $Factory->Copy($File);
1600 
1601  # associate copy with this resource and field
1602  $NewFile->ResourceId($this->Id);
1603  $NewFile->FieldId($Field->Id());
1604  }
1605  # Since we make a fresh copy of the File whenever Set is called,
1606  # we'll always update the modification time for this field.
1607  $UpdateModTime = TRUE;
1608  break;
1609 
1611  # convert incoming value to array to simplify the workflow
1612  if (is_scalar($NewValue) || $NewValue instanceof Resource)
1613  {
1614  $NewValue = array($NewValue);
1615  }
1616 
1617  # delete existing resource references
1618  $this->ClearByField($Field);
1619 
1620  # add each reference
1621  foreach ($NewValue as $ReferenceOrId)
1622  {
1623  # initially issume it's a reference ID and not an object...
1624  $ReferenceId = $ReferenceOrId;
1625 
1626  # ... but get the reference ID if it's an object
1627  if ($ReferenceOrId instanceof Resource)
1628  {
1629  $ReferenceId = $ReferenceOrId->Id();
1630  }
1631 
1632  # skip blank reference IDs
1633  if (strlen(trim($ReferenceId)) < 1)
1634  {
1635  continue;
1636  }
1637 
1638  # skip reference IDs that don't look right
1639  if (!is_numeric($ReferenceId))
1640  {
1641  continue;
1642  }
1643 
1644  # skip references to the current resource
1645  if ($ReferenceId == $this->Id())
1646  {
1647  continue;
1648  }
1649 
1650  # add the reference to the references table
1651  $DB->Query("
1652  INSERT INTO ReferenceInts (
1653  FieldId,
1654  SrcResourceId,
1655  DstResourceId)
1656  VALUES (
1657  ".addslashes($Field->Id()).",
1658  ".addslashes($this->Id()).",
1659  ".addslashes($ReferenceId).")");
1660  }
1661  break;
1662 
1663  default:
1664  # ERROR OUT
1665  exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1666  break;
1667  }
1668 
1669  if ($UpdateModTime && !$this->IsTempResource())
1670  {
1671  # update modification timestamps
1672  global $G_User;
1673  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1674  $DB->Query("DELETE FROM ResourceFieldTimestamps "
1675  ."WHERE ResourceId=".$this->Id." AND "
1676  ."FieldId=".$Field->Id() );
1677  $DB->Query("INSERT INTO ResourceFieldTimestamps "
1678  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1679  .$this->Id.",".$Field->Id().","
1680  .$UserId.",NOW())");
1681 
1682  # on resource modification, clear the UserPermsCache entry
1683  # so that stale permissions checks are not cached
1684  $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1685  }
1686  }
1687 
1695  public function SetByField($Field, $NewValue)
1696  {
1697  $this->Set($Field, $NewValue);
1698  }
1699 
1707  public function SetByFieldId($FieldId, $NewValue)
1708  {
1709  $this->Set($FieldId, $NewValue);
1710  }
1711 
1717  public function SetQualifier($FieldName, $NewValue)
1718  {
1719  $Field = $this->Schema()->GetFieldByName($FieldName);
1720  $this->SetQualifierByField($Field, $NewValue);
1721  }
1722 
1728  public function SetQualifierByFieldId($FieldId, $NewValue)
1729  {
1730  $Field = $this->Schema()->GetField($FieldId);
1731  $this->SetQualifierByField($Field, $NewValue);
1732  }
1733 
1739  public function SetQualifierByField($Field, $NewValue)
1740  {
1741  # if field uses qualifiers and uses item-level qualifiers
1742  if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1743  {
1744  # if qualifier object passed in
1745  if (is_object($NewValue))
1746  {
1747  # grab qualifier ID from object
1748  $QualifierId = $NewValue->Id();
1749  }
1750  else
1751  {
1752  # assume value passed in is qualifier ID
1753  $QualifierId = $NewValue;
1754  }
1755 
1756  # update qualifier value in database
1757  $DBFieldName = $Field->DBFieldName();
1758  $this->DB->Query("UPDATE Resources SET "
1759  .$DBFieldName."Qualifier = '".$QualifierId."' "
1760  ."WHERE ResourceId = ".$this->Id);
1761 
1762  # update local qualifier value
1763  $this->ValueCache[$DBFieldName."Qualifier"] = $QualifierId;
1764  }
1765  }
1766 
1773  public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1774  {
1775  $Field = $this->Schema()->GetField($FieldId);
1776  $this->Clear($Field, $ValueToClear);
1777  }
1778 
1785  public function Clear($Field, $ValueToClear = NULL)
1786  {
1787  # convert field name to object if necessary
1788  if (!is_object($Field))
1789  {
1790  $Field = $this->Schema()->GetFieldByName($Field);
1791  }
1792 
1793  # grab commonly-used values for local use
1794  $DB = $this->DB;
1795  $ResourceId = $this->Id;
1796 
1797  # grab database field name
1798  $DBFieldName = $Field->DBFieldName();
1799 
1800  $UpdateModTime=FALSE;
1801 
1802  # store value in DB based on field type
1803  switch ($Field->Type())
1804  {
1811  if (strlen($this->ValueCache[$DBFieldName])>0)
1812  {
1813  # clear value in DB
1814  $DB->Query("UPDATE Resources SET `"
1815  .$DBFieldName."` = NULL "
1816  ."WHERE ResourceId = ".$ResourceId);
1817 
1818  # clear value locally
1819  $this->ValueCache[$DBFieldName] = NULL;
1820  $UpdateModTime=TRUE;
1821  }
1822  break;
1823 
1825  if (!is_null($this->ValueCache[$DBFieldName."X"]) ||
1826  !is_null($this->ValueCache[$DBFieldName."Y"]) )
1827  {
1828  # Clear DB Values
1829  $DB->Query("UPDATE Resources SET "
1830  ."`".$DBFieldName."X` = NULL ,"
1831  ."`".$DBFieldName."Y` = NULL "
1832  ."WHERE ResourceId = ".$ResourceId);
1833 
1834  # Clear local values
1835  $this->ValueCache[$DBFieldName."X"] = NULL;
1836  $this->ValueCache[$DBFieldName."Y"] = NULL;
1837  $UpdateModTime=TRUE;
1838  }
1839  break;
1840 
1842  if (!is_null($this->ValueCache[$DBFieldName."Begin"]) ||
1843  !is_null($this->ValueCache[$DBFieldName."End"]) ||
1844  !is_null($this->ValueCache[$DBFieldName."Precision"]))
1845  {
1846  # clear date object values in DB
1847  $DB->Query("UPDATE Resources SET "
1848  .$DBFieldName."Begin = '', "
1849  .$DBFieldName."End = '', "
1850  .$DBFieldName."Precision = '' "
1851  ."WHERE ResourceId = ".$ResourceId);
1852 
1853  # clear value locally
1854  $this->ValueCache[$DBFieldName."Begin"] = NULL;
1855  $this->ValueCache[$DBFieldName."End"] = NULL;
1856  $this->ValueCache[$DBFieldName."Precision"] = NULL;
1857  $UpdateModTime=TRUE;
1858  }
1859  break;
1860 
1862  $OldValue = $this->Get($Field);
1863 
1864  # if value to clear supplied
1865  if ($ValueToClear !== NULL)
1866  {
1867  # if supplied value is array
1868  if (is_array($ValueToClear))
1869  {
1870  # for each element of array
1871  foreach ($ValueToClear as $ClassificationId => $Dummy)
1872  {
1873  if (array_key_exists($ClassificationId, $OldValue))
1874  {
1875  # remove association with resource (if any)
1876  $this->RemoveAssociation("ResourceClassInts",
1877  "ClassificationId",
1878  $ClassificationId);
1879  $Class = new Classification($ClassificationId);
1880  $Class->RecalcResourceCount();
1881  $UpdateModTime=TRUE;
1882  }
1883  }
1884  }
1885  else
1886  {
1887  if (array_key_exists($ValueToClear, $OldValue))
1888  {
1889  # remove association with resource (if any)
1890  $this->RemoveAssociation("ResourceClassInts",
1891  "ClassificationId",
1892  $ValueToClear);
1893  $Class = new Classification($ValueToClear);
1894  $Class->RecalcResourceCount();
1895  $UpdateModTime=TRUE;
1896  }
1897  }
1898  }
1899  else
1900  {
1901  if (count($OldValue)>0)
1902  {
1903  # remove all associations for resource and field
1904  $this->RemoveAllAssociations(
1905  "ResourceClassInts", "ClassificationId", $Field);
1906 
1907  # recompute resource count
1908  $Values = $this->Get($Field);
1909  foreach ($Values as $ClassificationId => $Dummy)
1910  {
1911  $Class = new Classification($ClassificationId);
1912  $Class->RecalcResourceCount();
1913  }
1914  $UpdateModTime=TRUE;
1915  }
1916  }
1917 
1918  # clear our classification cache
1919  if ($UpdateModTime)
1920  {
1921  unset($this->ClassificationCache);
1922  }
1923  break;
1924 
1927  $OldValue = $this->Get($Field);
1928  # if value to clear supplied
1929  if ($ValueToClear !== NULL)
1930  {
1931  # if incoming value is array
1932  if (is_array($ValueToClear))
1933  {
1934  # for each element of array
1935  foreach ($ValueToClear as $ControlledNameId =>
1936  $ControlledName)
1937  {
1938  if (array_key_exists($ControlledNameId, $OldValue))
1939  {
1940  # remove association with resource (if any)
1941  $this->RemoveAssociation("ResourceNameInts",
1942  "ControlledNameId",
1943  $ControlledNameId);
1944  $UpdateModTime=TRUE;
1945  }
1946  }
1947  }
1948  else
1949  {
1950  if (array_key_exists($ValueToClear, $OldValue))
1951  {
1952  # remove association with resource (if any)
1953  $this->RemoveAssociation("ResourceNameInts",
1954  "ControlledNameId",
1955  $ValueToClear);
1956  $UpdateModTime=TRUE;
1957  }
1958  }
1959  }
1960  else
1961  {
1962  if (count($OldValue)>0)
1963  {
1964  # remove all associations for resource and field
1965  $this->RemoveAllAssociations(
1966  "ResourceNameInts", "ControlledNameId", $Field);
1967  $UpdateModTime=TRUE;
1968  }
1969  }
1970 
1971  if ($UpdateModTime)
1972  {
1973  # clear our controlled name cache
1974  unset($this->ControlledNameCache);
1975  unset($this->ControlledNameVariantCache);
1976  }
1977  break;
1978 
1980  $OldValue = $this->Get($Field);
1981 
1982  # if value to clear supplied
1983  if ($ValueToClear !== NULL)
1984  {
1985  # if incoming value is array
1986  if (is_array($ValueToClear))
1987  {
1988  # for each element of array
1989  foreach ($ValueToClear as $UserId => $User)
1990  {
1991  if (array_key_exists($UserId, $OldValue))
1992  {
1993  # remove association with resource (if any)
1994  $this->RemoveAssociation("ResourceUserInts",
1995  "UserId",
1996  $UserId,
1997  $Field);
1998  $UpdateModTime=TRUE;
1999  }
2000  }
2001  }
2002  else
2003  {
2004  if (array_key_exists($ValueToClear, $OldValue))
2005  {
2006  # remove association with resource (if any)
2007  $this->RemoveAssociation("ResourceUserInts",
2008  "UserId",
2009  $UserId,
2010  $Field);
2011  $UpdateModTime=TRUE;
2012  }
2013  }
2014  }
2015  else
2016  {
2017  if (count($OldValue)>0)
2018  {
2019  # remove all associations for resource and field
2020  $this->RemoveAllAssociations(
2021  "ResourceUserInts", "UserId", $Field);
2022  $UpdateModTime=TRUE;
2023  }
2024  }
2025 
2026  break;
2027 
2029  # if value to clear supplied
2030  if ($ValueToClear !== NULL)
2031  {
2032  # convert value to array if necessary
2033  $Files = $ValueToClear;
2034  if (!is_array($Files)) { $Files = array($Files); }
2035 
2036  # convert values to objects if necessary
2037  foreach ($Files as $Index => $File)
2038  {
2039  if (!is_object($File))
2040  {
2041  $Files[$Index] = new File($File);
2042  }
2043  }
2044  }
2045  else
2046  {
2047  # use all files associated with resource
2048  $Files = $this->Get($Field, TRUE);
2049  }
2050 
2051  # delete files
2052  foreach ($Files as $File) { $File->Delete(); }
2053  break;
2054 
2056  # if value to clear supplied
2057  if ($ValueToClear !== NULL)
2058  {
2059  # convert value to array if necessary
2060  $Images = $ValueToClear;
2061  if (!is_array($Images)) { $Images = array($Images); }
2062 
2063  # convert values to objects if necessary
2064  foreach ($Images as $Index => $Image)
2065  {
2066  if (!is_object($Image))
2067  {
2068  $Images[$Index] = new SPTImage($Image);
2069  }
2070  }
2071  }
2072  else
2073  {
2074  # use all images associated with resource
2075  $Images = $this->Get($Field, TRUE);
2076  }
2077 
2078  # delete images if we are the last resource referencing
2079  # a particular image.
2080  foreach ($Images as $Image)
2081  {
2082  $Cnt = $this->DB->Query(
2083  "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
2084  "ImageId=".$Image->Id(), "Cnt");
2085  if ($Cnt==1)
2086  {
2087  $Image->Delete();
2088  }
2089  }
2090 
2091  # clear cached image mappings
2092  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
2093 
2094  # remove connections to images
2095  $UpdateModTime = $this->RemoveAssociation(
2096  "ResourceImageInts", "ImageId", $Images, $Field);
2097  break;
2098 
2100  # remove references from the references table
2101  $DB->Query("
2102  DELETE FROM ReferenceInts
2103  WHERE FieldId = '".addslashes($Field->Id())."'
2104  AND SrcResourceId = '".addslashes($this->Id())."'");
2105  break;
2106 
2107  default:
2108  # ERROR OUT
2109  exit("<br>SPT - ERROR: attempt to clear "
2110  ."unknown resource field type<br>\n");
2111  break;
2112  }
2113 
2114  if ($UpdateModTime && !$this->IsTempResource())
2115  {
2116  # update modification timestamps
2117  global $G_User;
2118  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
2119  $DB->Query("DELETE FROM ResourceFieldTimestamps "
2120  ."WHERE ResourceId=".$this->Id." AND "
2121  ."FieldId=".$Field->Id() );
2122  $DB->Query("INSERT INTO ResourceFieldTimestamps "
2123  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
2124  .$this->Id.",".$Field->Id().","
2125  .$UserId.",NOW())");
2126  }
2127  }
2128 
2137  public function ClearByField($Field, $ValueToClear = NULL)
2138  {
2139  $this->Clear($Field, $ValueToClear);
2140  }
2141 
2142  # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
2143 
2149  public function Classifications()
2150  {
2151  $DB = $this->DB;
2152 
2153  # start with empty array
2154  $Names = array();
2155 
2156  # for each controlled name
2157  $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2158  ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2159  ."Classifications, MetadataFields "
2160  ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2161  ."AND ResourceClassInts.ClassificationId = "
2162  ."Classifications.ClassificationId "
2163  ."AND Classifications.FieldId = MetadataFields.FieldId ");
2164  while ($Record = $DB->FetchRow())
2165  {
2166  # add name to array
2167  $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2168  $Record["ClassificationName"];
2169  }
2170 
2171  # return array to caller
2172  return $Names;
2173  }
2174 
2175 
2176  # --- Ratings Methods ---------------------------------------------------
2177 
2182  public function CumulativeRating()
2183  {
2184  return $this->CumulativeRating;
2185  }
2186 
2191  public function ScaledCumulativeRating()
2192  {
2193  if ($this->CumulativeRating == NULL)
2194  {
2195  return NULL;
2196  }
2197  else
2198  {
2199  return intval(($this->CumulativeRating + 5) / 10);
2200  }
2201  }
2202 
2207  public function NumberOfRatings()
2208  {
2209  # if number of ratings not already set
2210  if (!isset($this->NumberOfRatings))
2211  {
2212  # obtain number of ratings
2213  $this->NumberOfRatings =
2214  $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
2215  ."FROM ResourceRatings "
2216  ."WHERE ResourceId = ".$this->Id,
2217  "NumberOfRatings"
2218  );
2219 
2220  # recalculate cumulative rating if it looks erroneous
2221  if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
2222  {
2223  $this->UpdateCumulativeRating();
2224  }
2225  }
2226 
2227  # return number of ratings to caller
2228  return $this->NumberOfRatings;
2229  }
2230 
2238  public function Rating($NewRating = NULL, $UserId = NULL)
2239  {
2240  $DB = $this->DB;
2241 
2242  # if user ID not supplied
2243  if ($UserId == NULL)
2244  {
2245  # if user is logged in
2246  global $User;
2247  if ($User->IsLoggedIn())
2248  {
2249  # use ID of current user
2250  $UserId = $User->Get("UserId");
2251  }
2252  else
2253  {
2254  # return NULL to caller
2255  return NULL;
2256  }
2257  }
2258 
2259  # sanitize $NewRating
2260  if (!is_null($NewRating))
2261  {
2262  $NewRating = intval($NewRating);
2263  }
2264 
2265  # if there is a rating for resource and user
2266  $DB->Query("SELECT Rating FROM ResourceRatings "
2267  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2268  if ($Record = $DB->FetchRow())
2269  {
2270  # if new rating was supplied
2271  if ($NewRating != NULL)
2272  {
2273  # update existing rating
2274  $DB->Query("UPDATE ResourceRatings "
2275  ."SET Rating = ${NewRating}, DateRated = NOW() "
2276  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2277 
2278  # update cumulative rating value
2279  $this->UpdateCumulativeRating();
2280 
2281  # return value is new rating
2282  $Rating = $NewRating;
2283  }
2284  else
2285  {
2286  # get rating value to return to caller
2287  $Rating = $Record["Rating"];
2288  }
2289  }
2290  else
2291  {
2292  # if new rating was supplied
2293  if ($NewRating != NULL)
2294  {
2295  # add new rating
2296  $DB->Query("INSERT INTO ResourceRatings "
2297  ."(ResourceId, UserId, DateRated, Rating) "
2298  ."VALUES ("
2299  .$this->Id.", "
2300  ."${UserId}, "
2301  ."NOW(), "
2302  ."${NewRating})");
2303 
2304  # update cumulative rating value
2305  $this->UpdateCumulativeRating();
2306 
2307  # return value is new rating
2308  $Rating = $NewRating;
2309  }
2310  else
2311  {
2312  # return value is NULL
2313  $Rating = NULL;
2314  }
2315  }
2316 
2317  # return rating value to caller
2318  return $Rating;
2319  }
2320 
2321 
2322  # --- Resource Comment Methods ------------------------------------------
2323 
2328  public function Comments()
2329  {
2330  # read in comments if not already loaded
2331  if (!isset($this->Comments))
2332  {
2333  $this->DB->Query("SELECT MessageId FROM Messages "
2334  ."WHERE ParentId = ".$this->Id
2335  ." AND ParentType = 2 "
2336  ."ORDER BY DatePosted DESC");
2337  while ($MessageId = $this->DB->FetchField("MessageId"))
2338  {
2339  $this->Comments[] = new Message($MessageId);
2340  }
2341  }
2342 
2343  # return array of comments to caller
2344  return $this->Comments;
2345  }
2346 
2351  public function NumberOfComments()
2352  {
2353  # obtain number of comments if not already set
2354  if (!isset($this->NumberOfComments))
2355  {
2356  $this->NumberOfComments =
2357  $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2358  ."FROM Messages "
2359  ."WHERE ParentId = ".$this->Id
2360  ." AND ParentType = 2",
2361  "NumberOfComments"
2362  );
2363  }
2364 
2365  # return number of comments to caller
2366  return $this->NumberOfComments;
2367  }
2368 
2369 
2370  # --- Permission Methods -------------------------------------------------
2371 
2381  public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2382  {
2383  return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2384  }
2385 
2392  public function UserCanEdit($User)
2393  {
2394  return $this->CheckSchemaPermissions($User, "Edit");
2395  }
2396 
2403  public function UserCanAuthor($User)
2404  {
2405  return $this->CheckSchemaPermissions($User, "Author");
2406  }
2407 
2414  public function UserCanModify($User)
2415  {
2416  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2417  return $this->$CheckFn($User);
2418  }
2419 
2426  public function UserCanViewField($User, $FieldOrFieldName)
2427  {
2428  return $this->CheckFieldPermissions($User, $FieldOrFieldName, "View");
2429  }
2430 
2437  public function UserCanViewMappedField($User, $MappedName)
2438  {
2439  $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
2440  return ($FieldId === NULL) ? FALSE
2441  : $this->CheckFieldPermissions($User, $FieldId, "View");
2442  }
2443 
2450  public function UserCanEditField($User, $FieldOrFieldName)
2451  {
2452  return $this->CheckFieldPermissions($User, $FieldOrFieldName, "Edit");
2453  }
2454 
2461  public function UserCanAuthorField($User, $FieldOrFieldName)
2462  {
2463  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2464  }
2465 
2473  public function UserCanModifyField($User, $FieldOrFieldName)
2474  {
2475  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2476 
2477  return $this->$CheckFn($User, $FieldOrFieldName);
2478  }
2479 
2480  # --- Utility Methods ----------------------------------------------------
2481 
2486  {
2487  if (!$this->IsTempResource())
2488  {
2489  $SearchEngine = new SPTSearchEngine();
2490  $SearchEngine->QueueUpdateForItem($this);
2491 
2492  $Recommender = new SPTRecommender();
2493  $Recommender->QueueUpdateForItem($this);
2494  }
2495  }
2496 
2502  public static function GetSchemaForResource($ResourceId)
2503  {
2504  # if schema IDs are not loaded
2505  if (!isset(self::$SchemaIdCache))
2506  {
2507  # load schema IDs
2508  $DB = new Database();
2509  $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2510  self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2511  }
2512 
2513  # if multiple resources specified
2514  if (is_array($ResourceId))
2515  {
2516  # find schema IDs for specified resources
2517  $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2518  array_flip($ResourceId));
2519 
2520  # check that specified resource IDs were all valid
2521  if (count($SchemaIds) < count($ResourceId))
2522  {
2523  $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2524  throw new InvalidArgumentException("Unknown resource IDs ("
2525  .implode(", ", $BadIds).").");
2526  }
2527 
2528  # return schema IDs to caller
2529  return $SchemaIds;
2530  }
2531  else
2532  {
2533  # check that specified resource was valid
2534  if (!isset(self::$SchemaIdCache[$ResourceId]))
2535  {
2536  throw new InvalidArgumentException("Unknown resource ID ("
2537  .$ResourceId.").");
2538  }
2539 
2540  # return schema IDs for specified resource
2541  return self::$SchemaIdCache[$ResourceId];
2542  }
2543  }
2544 
2545 
2546  # ---- PRIVATE INTERFACE -------------------------------------------------
2547 
2548  private $ClassificationCache;
2549  private $Comments;
2550  private $ControlledNameCache;
2551  private $ControlledNameVariantCache;
2552  private $CumulativeRating;
2553  private $NumberOfComments;
2554  private $NumberOfRatings;
2555  private $PermissionCache;
2556  private $SchemaId;
2557 
2558  static private $Schemas;
2559  static private $SchemaIdCache;
2560 
2571  private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2572  {
2573  # construct a key to use for our permissions cache
2574  $CacheKey = "UserCan".$CheckType.$User->Id();
2575 
2576  # if we don't have a cached value for this perm, compute one
2577  if (!isset($this->PermissionCache[$CacheKey]))
2578  {
2579  # get privileges for schema
2580  $PermsFn = $CheckType."ingPrivileges";
2581  $SchemaPrivs = $this->Schema()->$PermsFn();
2582 
2583  # check passes if user privileges are greater than resource set
2584  $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2585 
2586  # save the result of this check in our cache
2587  $this->PermissionCache[$CacheKey] = $CheckResult;
2588  }
2589 
2590  $Value = $this->PermissionCache[$CacheKey];
2591 
2592  if ($AllowHooksToModify)
2593  {
2594  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2595  "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2596  array(
2597  "Resource" => $this,
2598  "User" => $User,
2599  "Can".$CheckType => $Value,
2600  "Schema" => $this->Schema(), ));
2601 
2602  $Value = $SignalResult["Can".$CheckType];
2603  }
2604 
2605  return $Value;
2606  }
2607 
2616  private function CheckFieldPermissions($User, $Field, $CheckType)
2617  {
2618  # get field object (if not supplied)
2619  if (!($Field instanceof MetadataField))
2620  {
2621  try
2622  {
2623  $Field = $this->Schema()->GetField($Field);
2624  }
2625  catch (InvalidArgumentException $Exception)
2626  {
2627  # (user cannot view/author/edit if field was invalid)
2628  return FALSE;
2629  }
2630  }
2631 
2632  # construct a key to use for our permissions cache
2633  $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2634 
2635  # if we don't have a cahced value, compute one
2636  if (!isset($this->PermissionCache[$CacheKey]))
2637  {
2638  # if field is enabled and editable, do permission check
2639  if ($Field->Enabled() &&
2640  ($CheckType == "View" || $Field->Editable()))
2641  {
2642  # be sure schema privs allow View/Edit/Author for this resource
2643  $SchemaCheckFn = "UserCan".$CheckType;
2644  if ($this->$SchemaCheckFn($User))
2645  {
2646  # get appropriate privilege set for field
2647  $PermsFn = $CheckType."ingPrivileges";
2648  $FieldPrivs = $Field->$PermsFn();
2649 
2650  # user can View/Edit/Author if privileges are greater than field set
2651  $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2652  }
2653  else
2654  {
2655  $CheckResult = FALSE;
2656  }
2657  }
2658  else
2659  {
2660  $CheckResult = FALSE;
2661  }
2662 
2663  # allow plugins to modify result of permission check
2664  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2665  "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2666  "Field" => $Field,
2667  "Resource" => $this,
2668  "User" => $User,
2669  "Can".$CheckType => $CheckResult));
2670  $CheckResult = $SignalResult["Can".$CheckType];
2671 
2672  # save the result of this check in our cache
2673  $this->PermissionCache[$CacheKey] = $CheckResult;
2674  }
2675 
2676  # return cached permission value
2677  return $this->PermissionCache[$CacheKey];
2678  }
2679 
2683  private function UpdateCumulativeRating()
2684  {
2685  # grab totals from DB
2686  $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2687  ."SUM(Rating) AS Total FROM ResourceRatings "
2688  ."WHERE ResourceId = ".$this->Id);
2689  $Record = $this->DB->FetchRow();
2690 
2691  # calculate new cumulative rating
2692  $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
2693 
2694  # save new cumulative rating in DB
2695  $this->DB->Query("UPDATE Resources "
2696  ."SET CumulativeRating = ".$this->CumulativeRating." "
2697  ."WHERE ResourceId = ".$this->Id);
2698  }
2699 
2711  private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2712  {
2713  # We should ignore duplicate key errors when doing inserts:
2714  $this->DB->SetQueryErrorsToIgnore( array(
2715  "/INSERT INTO ".$TableName."/" =>
2716  "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2717 
2718  # start out assuming no association will be added
2719  $AssociationAdded = FALSE;
2720 
2721  # convert new value to array if necessary
2722  $Values = is_array($Value) ? $Value : array($Value);
2723 
2724  # for each new value
2725  foreach ($Values as $Value)
2726  {
2727  # retrieve ID from value if necessary
2728  if (is_object($Value)) { $Value = $Value->Id(); }
2729 
2730  # Try to insert a new entry for this association.
2731  $this->DB->Query("INSERT INTO ".$TableName." SET"
2732  ." ResourceId = ".intval($this->Id)
2733  .", ".$FieldName." = ".intval($Value)
2734  .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2735 
2736  # If the insert ran without a duplicate key error,
2737  # then we added an assocation:
2738  if ($this->DB->IgnoredError() === FALSE)
2739  {
2740  $AssociationAdded = TRUE;
2741  }
2742  }
2743 
2744  # Clear ignored errors:
2745  $this->DB->SetQueryErrorsToIgnore( NULL );
2746 
2747  # report to caller whether association was added
2748  return $AssociationAdded;
2749  }
2750 
2762  private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2763  {
2764  # start out assuming no association will be removed
2765  $AssociationRemoved = FALSE;
2766 
2767  # convert value to array if necessary
2768  $Values = is_array($Value) ? $Value : array($Value);
2769 
2770  # for each value
2771  foreach ($Values as $Value)
2772  {
2773  # retrieve ID from value if necessary
2774  if (is_object($Value)) { $Value = $Value->Id(); }
2775 
2776  # remove any intersections with target ID from DB
2777  $this->DB->Query("DELETE FROM ".$TableName
2778  ." WHERE ResourceId = ".intval($this->Id)
2779  .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2780  ." AND ".$FieldName." = ".intval($Value));
2781  if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2782  }
2783 
2784  # report to caller whether association was added
2785  return $AssociationRemoved;
2786  }
2787 
2794  private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
2795  {
2796  # retrieve list of entries for this field and resource
2797  $Entries = $this->Get($Field);
2798 
2799  # divide them into chunks of not more than 100
2800  foreach (array_chunk($Entries, 100, TRUE) as $Chunk)
2801  {
2802  # remove assocations from this chunk
2803  $this->DB->Query("DELETE FROM ".$TableName
2804  ." WHERE ResourceId = ".intval($this->Id)
2805  ." AND ".$TargetFieldName." IN "
2806  ."(".implode(",", array_keys($Chunk)).")");
2807  }
2808  }
2809 
2816  static protected function SetDatabaseAccessValues($ClassName)
2817  {
2818  if (!isset(self::$ItemIdColumnNames[$ClassName]))
2819  {
2820  self::$ItemIdColumnNames[$ClassName] = "ResourceId";
2821  self::$ItemNameColumnNames[$ClassName] = NULL;
2822  self::$ItemTableNames[$ClassName] = "Resources";
2823  }
2824  }
2825 }
GetByField($FieldNameOrObject, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Old method for retrieving values, deprecated in favor of Get().
Definition: Resource.php:775
UserCanView(User $User, $AllowHooksToModify=TRUE)
Determine if the given user can view the resource, e.g., on the full record page. ...
Definition: Resource.php:2381
GetFilesForResource($ResourceOrResourceId, $ReturnObjects=TRUE)
Retrieve all files (names or objects) for specified resource.
Definition: FileFactory.php:39
GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
Get URLs for images, returning CleanURLs when possible and direct paths to image files otherwise...
Definition: Resource.php:1108
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1717
UserCanViewMappedField($User, $MappedName)
Check whether user can view specified standard (mapped) metadata field.
Definition: Resource.php:2437
Metadata schema (in effect a Factory class for MetadataField).
Abstraction for forum messages and resource comments.
Definition: Message.php:14
SQL database abstraction object with smart query caching.
Definition: Database.php:22
UserCanModifyField($User, $FieldOrFieldName)
Check whether user is allowed to modify (Edit for perm resources, Author for temp) specified metadata...
Definition: Resource.php:2473
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2485
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:813
Id()
Retrieve numerical resource ID.
Definition: Resource.php:291
$DB
Definition: Item.php:188
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2450
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1739
GetViewPageUrl()
Retrieve view page URL for this resource.
Definition: Resource.php:391
Rating($NewRating=NULL, $UserId=NULL)
Get/set rating by a specific user for resource.
Definition: Resource.php:2238
Definition: User.php:48
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2351
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2207
GetQualifier($FieldName, $ReturnObject=TRUE)
Retrieve qualifier by field name.
Definition: Resource.php:876
Factory object for Folder class, used to retrieve and manage Folders and groups of Folders...
Copy($FileToCopy)
Create copy of File and return to caller.
Definition: FileFactory.php:85
Schema()
Get MetadataSchema for resource.
Definition: Resource.php:309
Definition: Date.php:18
Metadata type representing non-hierarchical controlled vocabulary values.
UserCanEdit($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2392
const MDFTYPE_CONTROLLEDNAME
GetForDisplay($FieldNameOrObject, $ReturnObject=TRUE, $IncludeVariants=FALSE)
Retrieve value using field name or field object, signaling EVENT_FIELD_DISPLAY_FILTER to allow other ...
Definition: Resource.php:739
Comments()
Get comments for resource.
Definition: Resource.php:2328
UpdateAutoupdateFields($UpdateType, $User=NULL)
Update the auto-updated fields as necessary.
Definition: Resource.php:259
CWIS-specific user factory class.
Get($Field, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field name or field object.
Definition: Resource.php:415
static GetSchemaForResource($ResourceId)
Get schema ID for specified resource(s).
Definition: Resource.php:2502
Factory for manipulating File objects.
Definition: FileFactory.php:13
Common base class for persistent items store in database.
Definition: Item.php:13
GetQualifierByFieldId($FieldId, $ReturnObject=TRUE)
Retrieve qualifier by field ID.
Definition: Resource.php:890
Encapsulates a full-size, preview, and thumbnail image.
Definition: SPTImage.php:13
UserCanAuthorField($User, $FieldOrFieldName)
Check whether user is allowed to author specified metadata field.
Definition: Resource.php:2461
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1785
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2414
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2403
GetByFieldId($FieldId, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field ID.
Definition: Resource.php:795
IsTempResource($NewSetting=NULL)
Get/set whether resource is a temporary record.
Definition: Resource.php:320
SetByField($Field, $NewValue)
Method replaced by Resource::Set(), preserved for backward compatibility.
Definition: Resource.php:1695
const STATUS_OK
Successful execution.
Object representing a locally-defined type of metadata field.
__construct($ResourceId)
Object constructor for loading an existing resource.
Definition: Resource.php:25
GetMapped($MappedName, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using standard (mapped) field name.
Definition: Resource.php:859
$Id
Definition: Item.php:189
static SetDatabaseAccessValues($ClassName)
Set the database access values (table name, ID column name, name column name) for specified class...
Definition: Resource.php:2816
Represents a "resource" in CWIS.
Definition: Resource.php:13
GetQualifierByField($Field, $ReturnObject=TRUE)
Retrieve qualifier by Field object.
Definition: Resource.php:904
ClearByFieldId($FieldId, $ValueToClear=NULL)
Clear field value specified by field ID.
Definition: Resource.php:1773
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1728
const SIZE_FULL
Definition: SPTImage.php:21
static ClearImageSymlinksForResource($ResourceId, $FieldId)
Remove symlinks used for to cache image mappings.
Definition: SPTImage.php:576
SchemaId()
Retrieve ID of schema for resource.
Definition: Resource.php:300
ScaledCumulativeRating()
Return cumulative rating scaled to 1/10th.
Definition: Resource.php:2191
Set($Field, $NewValue, $Reset=FALSE)
Set value using field name or field object.
Definition: Resource.php:1143
const UPDATEMETHOD_ONRECORDCREATE
static Create($SchemaId)
Create a new resource.
Definition: Resource.php:48
UserCanViewField($User, $FieldOrFieldName)
Check whether user is allowed to view specified metadata field.
Definition: Resource.php:2426
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1707
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:2149
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:2137
Class representing a stored (usually uploaded) file.
Definition: File.php:13
Factory for Resource objects.
CWIS-specific user class.
Definition: CWUser.php:13
CumulativeRating()
Get cumulative rating (range is usually 0-100)
Definition: Resource.php:2182
FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
Determine if the value for a field is set.
Definition: Resource.php:1038
Delete()
Remove resource (and accompanying associations) from database and delete any associated files...
Definition: Resource.php:142