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  $UserIds = $this->DB->FetchColumn("UserId");
621 
622  # convert each userid to either a name or a CWUser object
623  foreach ($UserIds as $UserId)
624  {
625  $User = new CWUser(intval($UserId));
626  if ($ReturnObject)
627  {
628  $ReturnValue[$UserId] = $User;
629  }
630  else
631  {
632  $ReturnValue[$UserId] = $User->Get("UserName");
633  }
634  }
635  break;
636 
638  # start out assuming no images will be found
639  $ReturnValue = array();
640 
641  # find all images associated with this resource
642  $this->DB->Query("SELECT ImageId FROM ResourceImageInts"
643  ." WHERE ResourceId = ".intval($this->Id())
644  ." AND FieldId = ".intval($Field->Id()));
645 
646  # if images were found
647  if ($this->DB->NumRowsSelected())
648  {
649  # if we are to return an object
650  $ImageIds = $this->DB->FetchColumn("ImageId");
651  if ($ReturnObject)
652  {
653  # load array of Image objects for return value
654  foreach ($ImageIds as $ImageId)
655  {
656  $ReturnValue[$ImageId] = new SPTImage($ImageId);
657  }
658  }
659  else
660  {
661  # load array of Image ids for return value
662  $ReturnValue = $ImageIds;
663  }
664  }
665  break;
666 
668  # retrieve files using factory
669  $Factory = new FileFactory($Field->Id());
670  $ReturnValue = $Factory->GetFilesForResource(
671  $this->Id, $ReturnObject);
672  break;
673 
675  # query for resource references
676  $this->DB->Query("
677  SELECT * FROM ReferenceInts
678  WHERE FieldId = '".addslashes($Field->Id())."'
679  AND SrcResourceId = '".addslashes($this->Id())."'");
680 
681  $ReturnValue = array();
682 
683  # return each reference as a Resource object
684  if ($ReturnObject)
685  {
686  $FoundErrors = FALSE;
687 
688  while (FALSE !== ($Record = $this->DB->FetchRow()))
689  {
690  $ReferenceId = $Record["DstResourceId"];
691  $Reference = new Resource($ReferenceId);
692  $ReturnValue[$ReferenceId] = $Reference;
693  }
694  }
695 
696  # return each reference as a resource ID
697  else
698  {
699  while (FALSE !== ($Record = $this->DB->FetchRow()))
700  {
701  $ReferenceId = $Record["DstResourceId"];
702  $ReturnValue[$ReferenceId] = $ReferenceId;
703  }
704  }
705  break;
706 
707  default:
708  # ERROR OUT
709  exit("<br>SPT - ERROR: attempt to retrieve "
710  ."unknown resource field type (".$Field->Type().")<br>\n");
711  break;
712  }
713 
714  # return formatted value to caller
715  return $ReturnValue;
716  }
717 
737  public function GetForDisplay(
738  $FieldNameOrObject, $ReturnObject = TRUE, $IncludeVariants = FALSE)
739  {
740  # normalize metadata field for use by any hooked code
741  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
742  : $this->Schema()->GetFieldByName($FieldNameOrObject);
743 
744  # retrieve value
745  $Value = $this->Get($Field, $ReturnObject, $IncludeVariants);
746 
747  # signal event to allowed hooked code to modify value
748  $SignalResult = $GLOBALS["AF"]->SignalEvent(
749  "EVENT_FIELD_DISPLAY_FILTER", array(
750  "Field" => $Field,
751  "Resource" => $this,
752  "Value" => $Value));
753 
754  # return possibly modified value to caller
755  return $SignalResult["Value"];
756  }
757 
773  public function GetByField($FieldNameOrObject,
774  $ReturnObject = FALSE, $IncludeVariants = FALSE)
775  {
776  return $this->Get($FieldNameOrObject, $ReturnObject, $IncludeVariants);
777  }
778 
793  public function GetByFieldId(
794  $FieldId, $ReturnObject = FALSE, $IncludeVariants = FALSE)
795  {
796  return $this->Get($FieldId, $ReturnObject, $IncludeVariants);
797  }
798 
811  public function GetAsArray($IncludeDisabledFields = FALSE, $ReturnObjects = TRUE)
812  {
813  # retrieve field info
814  $Fields = $this->Schema()->GetFields();
815 
816  # for each field
817  foreach ($Fields as $Field)
818  {
819  # if field is enabled or caller requested disabled fields
820  if ($Field->Enabled() || $IncludeDisabledFields)
821  {
822  # retrieve info and add it to the array
823  $FieldStrings[$Field->Name()] = $this->Get($Field, $ReturnObjects);
824 
825  # if field uses qualifiers
826  if ($Field->UsesQualifiers())
827  {
828  # get qualifier attributes and add to the array
829  $FieldStrings[$Field->Name()." Qualifier"] =
830  $this->GetQualifierByField($Field, $ReturnObjects);
831  }
832  }
833  }
834 
835  # add in internal values
836  $FieldStrings["ResourceId"] = $this->Id();
837  $FieldStrings["CumulativeRating"] = $this->CumulativeRating();
838 
839  # return array to caller
840  return $FieldStrings;
841  }
842 
857  public function GetMapped(
858  $MappedName, $ReturnObject = FALSE, $IncludeVariants = FALSE)
859  {
860  $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
861  return $FieldId
862  ? $this->Get($FieldId, $ReturnObject, $IncludeVariants)
863  : NULL;
864  }
865 
874  public function GetQualifier($FieldName, $ReturnObject = TRUE)
875  {
876  $Field = $this->Schema()->GetFieldByName($FieldName);
877  return $this->GetQualifierByField($Field, $ReturnObject);
878  }
879 
888  public function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
889  {
890  $Field = $this->Schema()->GetField($FieldId);
891  return ($Field) ? $this->GetQualifierByField($Field, $ReturnObject) : NULL;
892  }
893 
902  public function GetQualifierByField($Field, $ReturnObject = TRUE)
903  {
904  # return NULL if field is invalid
905  if (!($Field instanceof MetadataField)) { return NULL; }
906 
907  # assume no qualifiers if not otherwise determined
908  $ReturnValue = NULL;
909 
910  # if field uses qualifiers
911  if ($Field->UsesQualifiers())
912  {
913  # retrieve qualifiers based on field type
914  switch ($Field->Type())
915  {
919  # retrieve list of items
920  $Items = $this->Get($Field);
921 
922  # if field uses item-level qualifiers
923  if ($Field->HasItemLevelQualifiers())
924  {
925  # determine general item name in DB
926  $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
927  ? "Classification" : "ControlledName";
928 
929  # for each item
930  foreach ($Items as $ItemId => $ItemName)
931  {
932  # look up qualifier for item
933  $QualId = $this->DB->Query(
934  "SELECT * FROM ".$TableName."s"
935  ." WHERE ".$TableName."Id = ".$ItemId,
936  "QualifierId");
937 
938 
939  if ($QualId > 0)
940  {
941  # if object was requested by caller
942  if ($ReturnObject)
943  {
944  # load qualifier and add to return value array
945  $ReturnValue[$ItemId] = new Qualifier($QualId);
946  }
947  else
948  {
949  # add qualifier ID to return value array
950  $ReturnValue[$ItemId] = $QualId;
951  }
952  }
953  else
954  {
955  # add NULL to return value array for this item
956  $ReturnValue[$ItemId] = NULL;
957  }
958  }
959  }
960  else
961  {
962  # for each item
963  foreach ($Items as $ItemId => $ItemName)
964  {
965  # if object was requested by caller
966  if ($ReturnObject)
967  {
968  # load default qualifier and add to return value array
969  $ReturnValue[$ItemId] = new Qualifier(
970  $Field->DefaultQualifier());
971  }
972  else
973  {
974  # add default qualifier ID to return value array
975  $ReturnValue[$ItemId] = $Field->DefaultQualifier();
976  }
977  }
978  }
979  break;
980 
981  default:
982  # if field uses item-level qualifiers
983  if ($Field->HasItemLevelQualifiers())
984  {
985  # if qualifier available
986  if ($this->ValueCache[$Field->DBFieldName()."Qualifier"] > 0)
987  {
988  # if object was requested by caller
989  $QFieldName = $Field->DBFieldName()."Qualifier";
990  if ($ReturnObject)
991  {
992  # return qualifier for field
993  $ReturnValue = new Qualifier(
994  $this->ValueCache[$QFieldName]);
995  }
996  else
997  {
998  # return qualifier ID for field
999  $ReturnValue = $this->ValueCache[$QFieldName];
1000  }
1001  }
1002  }
1003  else
1004  {
1005  # if default qualifier available
1006  if ($Field->DefaultQualifier() > 0)
1007  {
1008  # if object was requested by caller
1009  if ($ReturnObject)
1010  {
1011  # return default qualifier
1012  $ReturnValue = new Qualifier($Field->DefaultQualifier());
1013  }
1014  else
1015  {
1016  # return default qualifier ID
1017  $ReturnValue = $Field->DefaultQualifier();
1018  }
1019  }
1020  }
1021  break;
1022  }
1023  }
1024 
1025  # return qualifier object or ID (or array of same) to caller
1026  return $ReturnValue;
1027  }
1028 
1036  public function FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
1037  {
1038  # load field object if needed
1039  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1040  : $this->Schema()->GetFieldByName($FieldNameOrObject);
1041 
1042  # return no value found if we don't have a valid field
1043  if (!($Field instanceof MetadataField)) { return FALSE; }
1044 
1045  # get the value
1046  $Value = $this->Get($Field);
1047 
1048  # checks depend on the field type
1049  switch ($Field->Type())
1050  {
1055  return isset($Value)
1056  && strlen($Value)
1057  && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1058 
1060  return isset($Value)
1061  && strlen($Value);
1062 
1064  return isset($Value["X"])
1065  && isset($Value["Y"])
1066  && strlen(trim($Value["X"]))
1067  && strlen(trim($Value["Y"]));
1068 
1070  return isset($Value)
1071  && strlen(trim($Value))
1072  && $Value != "0000-00-00";
1073 
1075  return isset($Value)
1076  && strlen(trim($Value))
1077  && $Value != "0000-00-00 00:00:00";
1078 
1085  return count($Value) > 0;
1086 
1088  $Factory = new CWUserFactory();
1089  return isset($Value)
1090  && strlen($Value)
1091  && $Factory->UserNameExists($Value);
1092 
1093  default:
1094  return FALSE;
1095  }
1096  }
1097 
1106  public function GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
1107  {
1108  $Result = array();
1109 
1110  # get our target field and extract its values
1111  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1112  : $this->Schema()->GetField($FieldNameOrObject);
1113  $Images = $this->Get($Field, TRUE);
1114 
1115  # iterate over our images getting URLs for each
1116  $Index = 0;
1117  foreach ($Images as $Image)
1118  {
1119  $Result[$Image->Id()] = $Image->GetImageUrlForResource(
1120  $this->Id(), $Field->Id(), $Index, $ImageSize);
1121  $Index++;
1122  }
1123 
1124  return $Result;
1125  }
1126 
1127  # --- Generic Attribute Setting Methods ---------------------------------
1128 
1141  public function Set($Field, $NewValue, $Reset=FALSE)
1142  {
1143  # load field object if not already supplied
1144  $Field = is_object($Field) ? $Field
1145  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
1146  : $this->Schema()->GetFieldByName($Field));
1147 
1148  # return if we don't have a valid field
1149  if (!($Field instanceof MetadataField)) { return; }
1150 
1151  if ($Field->SchemaId() != $this->SchemaId())
1152  {
1153  throw new Exception("Attempt to set a value for a field "
1154  ."from a different schema.");
1155  }
1156 
1157  # grab commonly-used values for local use
1158  $DB = $this->DB;
1159  $ResourceId = $this->Id;
1160 
1161  # grab database field name
1162  $DBFieldName = $Field->DBFieldName();
1163 
1164  # Flag to deterimine if we've actually changed anything.
1165  $UpdateModTime = FALSE;
1166 
1167  # store value in DB based on field type
1168  switch ($Field->Type())
1169  {
1173  if ($this->ValueCache[$DBFieldName] != $NewValue)
1174  {
1175  # save value directly to DB
1176  $DB->Query("UPDATE Resources SET `"
1177  .$DBFieldName."` = '".addslashes($NewValue)."' "
1178  ."WHERE ResourceId = ".$ResourceId);
1179 
1180  # save value locally
1181  $this->ValueCache[$DBFieldName] = $NewValue;
1182  $UpdateModTime=TRUE;
1183  }
1184  break;
1185 
1187  if ( $this->ValueCache[$DBFieldName] != $NewValue )
1188  {
1189  # save value directly to DB
1190  if (is_null($NewValue))
1191  {
1192  $DB->Query("UPDATE Resources SET `"
1193  .$DBFieldName."` = NULL"
1194  ." WHERE ResourceId = ".$ResourceId);
1195  }
1196  else
1197  {
1198  $DB->Query("UPDATE Resources SET `"
1199  .$DBFieldName."` = ".intval($NewValue)
1200  ." WHERE ResourceId = ".$ResourceId);
1201  }
1202 
1203  # save value locally
1204  $this->ValueCache[$DBFieldName] = $NewValue;
1205  $UpdateModTime = TRUE;
1206  }
1207  break;
1208 
1209 
1211  if ($this->ValueCache[$DBFieldName."X"] != $NewValue["X"] ||
1212  $this->ValueCache[$DBFieldName."Y"] != $NewValue["Y"] )
1213  {
1214  if (is_null($NewValue))
1215  {
1216  $DB->Query("UPDATE Resources SET "
1217  ."`".$DBFieldName."X` = NULL, "
1218  ."`".$DBFieldName."Y` = NULL "
1219  ."WHERE ResourceId = ".$ResourceId);
1220  $this->ValueCache[$DBFieldName."X"] = NULL;
1221  $this->ValueCache[$DBFieldName."Y"] = NULL;
1222  }
1223  else
1224  {
1225  $DB->Query("UPDATE Resources SET "
1226  ."`".$DBFieldName."X` = " .(strlen($NewValue["X"])
1227  ? "'".$NewValue["X"]."'" : "NULL").", "
1228  ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
1229  ? "'".$NewValue["Y"]."'" : "NULL")
1230  ." WHERE ResourceId = ".$ResourceId);
1231 
1232  $Digits = $Field->PointDecimalDigits();
1233 
1234  $this->ValueCache[$DBFieldName."X"] =
1235  strlen($NewValue["X"]) ?
1236  round($NewValue["X"], $Digits) : NULL;
1237  $this->ValueCache[$DBFieldName."Y"] =
1238  strlen($NewValue["Y"]) ?
1239  round($NewValue["Y"], $Digits) : NULL;
1240  }
1241  $UpdateModTime = TRUE;
1242  }
1243  break;
1244 
1246  if ($this->ValueCache[$DBFieldName] != $NewValue)
1247  {
1248  # save value directly to DB
1249  if (is_null($NewValue))
1250  {
1251  $DB->Query("UPDATE Resources SET `"
1252  .$DBFieldName."` = NULL"
1253  ." WHERE ResourceId = ".$ResourceId);
1254  }
1255  else
1256  {
1257  $NewValue = $NewValue ? "1" : "0";
1258  $DB->Query("UPDATE Resources SET `"
1259  .$DBFieldName."` = ".$NewValue
1260  ." WHERE ResourceId = ".$ResourceId);
1261  }
1262 
1263  $this->ValueCache[$DBFieldName] = $NewValue;
1264 
1265  $UpdateModTime = TRUE;
1266  }
1267  break;
1268 
1270  $OldValue = $this->Get($Field);
1271  # value comes back as array (UserId => UserName), just get the Ids
1272  $OldValue = array_keys($OldValue);
1273 
1274  # input to Set() for these fields is one of
1275  # 1. an int specifying a UserId
1276  if (is_numeric($NewValue))
1277  {
1278  $NewValue = array($NewValue);
1279  }
1280  # 2. a CWUser object
1281  elseif ($NewValue instanceof CWUser)
1282  {
1283  $NewValue = array($NewValue->Id());
1284  }
1285  # 3. an array keyed by UserId (don't care about the values)
1286  elseif (is_array($NewValue))
1287  {
1288  $NewValue = array_keys($NewValue);
1289  }
1290  else
1291  {
1292  throw new Exception("Unknown format for NewValue in a User field");
1293  }
1294 
1295  # if this is a unique field, only accept the first of the options given
1296  if ($Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1297  {
1298  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1299  }
1300 
1301  # sort new and old values so we can directly compare
1302  sort($OldValue);
1303  sort($NewValue);
1304 
1305  # if the value has changed
1306  if ($OldValue != $NewValue)
1307  {
1308  if ($Reset || $Field->AllowMultiple() == FALSE )
1309  {
1310  $ToRemove = array_diff($OldValue, $NewValue);
1311  $this->RemoveAssociation(
1312  "ResourceUserInts", "UserId", $ToRemove, $Field);
1313  }
1314 
1315  # associate with resource if not already associated
1316  $this->AddAssociation("ResourceUserInts",
1317  "UserId",
1318  $NewValue, $Field);
1319 
1320  $UpdateModTime=TRUE;
1321  }
1322  break;
1323 
1325  # if we were given a date object
1326  if (is_object($NewValue))
1327  {
1328  # use supplied date object
1329  $Date = $NewValue;
1330  }
1331  else
1332  {
1333  # create date object
1334  $Date = new Date($NewValue);
1335  }
1336 
1337  $OldDate = new Date(
1338  $this->ValueCache[$DBFieldName."Begin"],
1339  $this->ValueCache[$DBFieldName."End"]);
1340 
1341  if ($OldDate->BeginDate() != $Date->BeginDate() ||
1342  $OldDate->EndDate() != $Date->EndDate() ||
1343  $OldDate->Precision() != $Date->Precision() )
1344  {
1345  # extract values from date object and store in DB
1346  $BeginDate = "'".$Date->BeginDate()."'";
1347  if (strlen($BeginDate) < 3) { $BeginDate = "NULL"; }
1348  $EndDate = "'".$Date->EndDate()."'";
1349  if (strlen($EndDate) < 3) { $EndDate = "NULL"; }
1350 
1351  $DB->Query("UPDATE Resources SET "
1352  .$DBFieldName."Begin = ".$BeginDate.", "
1353  .$DBFieldName."End = ".$EndDate.", "
1354  .$DBFieldName."Precision = '".$Date->Precision()."' "
1355  ."WHERE ResourceId = ".$ResourceId);
1356 
1357  # save values locally
1358  $this->ValueCache[$DBFieldName."Begin"] = $Date->BeginDate();
1359  $this->ValueCache[$DBFieldName."End"] = $Date->EndDate();
1360  $this->ValueCache[$DBFieldName."Precision"] = $Date->Precision();
1361  $UpdateModTime=TRUE;
1362  }
1363  break;
1364 
1366  if (is_null($NewValue) || !strlen(trim($NewValue)))
1367  {
1368  $DateValue = $NewValue;
1369 
1370  if (!is_null($this->ValueCache[$DBFieldName]))
1371  {
1372  # save value directly to DB
1373  $DB->Query("UPDATE Resources SET "
1374  ."`".$DBFieldName."` = NULL "
1375  ."WHERE ResourceId = ".$ResourceId);
1376  $UpdateModTime = TRUE;
1377  }
1378  }
1379  else
1380  {
1381  # assume value is date and use directly
1382  $TimestampValue = strtotime($NewValue);
1383 
1384  # use the new value if the date is valid
1385  if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1386  {
1387  $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1388 
1389  if ($this->ValueCache[$DBFieldName] != $DateValue)
1390  {
1391  # save value directly to DB
1392  $DB->Query("UPDATE Resources SET "
1393  ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1394  ."WHERE ResourceId = ".$ResourceId);
1395  $UpdateModTime=TRUE;
1396  }
1397  }
1398 
1399  # continue using the old value if invalid
1400  else
1401  {
1402  $DateValue = $this->Get($Field);
1403  }
1404  }
1405 
1406  # save value locally
1407  $this->ValueCache[$DBFieldName] = $DateValue;
1408  break;
1409 
1411  $OldValue = $this->Get($Field);
1412 
1413  # if incoming value is array
1414  if (is_array($NewValue))
1415  {
1416  if ($OldValue != $NewValue)
1417  {
1418  if ($Reset)
1419  {
1420  # remove values that were in the old value
1421  # but not the new one
1422  $ToRemove = array_diff(array_keys($OldValue),
1423  array_keys($NewValue));
1424  foreach ($ToRemove as $ClassificationId)
1425  {
1426  $this->RemoveAssociation("ResourceClassInts",
1427  "ClassificationId",
1428  $ClassificationId);
1429  $Class = new Classification($ClassificationId);
1430  $Class->RecalcResourceCount();
1431  }
1432  }
1433 
1434  # for each element of array
1435  foreach ($NewValue as
1436  $ClassificationId => $ClassificationName)
1437  {
1438  $Class = new Classification($ClassificationId);
1439  if ($Class->FieldId() == $Field->Id())
1440  {
1441  # associate with resource if not already associated
1442  if ($this->AddAssociation("ResourceClassInts",
1443  "ClassificationId", $ClassificationId))
1444  {
1445  $Class->UpdateLastAssigned();
1446  $Class->RecalcResourceCount();
1447  }
1448  }
1449  else
1450  {
1451  throw new Exception(
1452  "Attempting to store classification from "
1453  ."Field ".$Class->FieldId()." into Field "
1454  .$Field->Id() );
1455  }
1456 
1457  }
1458 
1459  $UpdateModTime=TRUE;
1460  }
1461  }
1462  else
1463  {
1464  # associate with resource if not already associated
1465  if (is_object($NewValue))
1466  {
1467  $Class = $NewValue;
1468  $NewValue = $Class->Id();
1469  }
1470  else
1471  {
1472  $Class = new Classification($NewValue);
1473  }
1474 
1475  if (!array_key_exists($Class->Id(), $OldValue))
1476  {
1477 
1478  $this->AddAssociation("ResourceClassInts",
1479  "ClassificationId",
1480  $NewValue);
1481  $Class->UpdateLastAssigned();
1482  $Class->RecalcResourceCount();
1483  $UpdateModTime=TRUE;
1484  }
1485  }
1486 
1487  # clear our classification cache
1488  if ($UpdateModTime)
1489  {
1490  unset($this->ClassificationCache);
1491  }
1492  break;
1493 
1496  $OldValue = $this->Get($Field);
1497 
1498  # input to Set() for these fields is one of
1499  # 1. an int specifying a ControlledNameId
1500  # 2. a ControlledName object
1501  # 3. an array with keys giving Ids and values giving ControlledNames
1502  #
1503  # normalize 1 and 2 into 3 for simplicity of processing
1504  if (is_object($NewValue) || !is_array($NewValue) )
1505  {
1506  if (!is_object($NewValue))
1507  {
1508  $NewValue = new ControlledName($NewValue);
1509  }
1510 
1511  $TmpValue = array();
1512  $TmpValue[$NewValue->Id()] = $NewValue->Name();
1513 
1514  $NewValue = $TmpValue;
1515  }
1516 
1517  # if this is a unique field, only accept the first of the options given
1518  # NB: all ControlledNames implicitly AllowMultiple
1519  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1520  $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1521  {
1522  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1523  }
1524 
1525  # if the value has changed
1526  if ($OldValue != $NewValue)
1527  {
1528  if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1529  && $Field->AllowMultiple() == FALSE ) )
1530  {
1531  $ToRemove = array_diff(array_keys($OldValue),
1532  array_keys($NewValue));
1533  foreach ($ToRemove as $CNId)
1534  {
1535  $this->RemoveAssociation("ResourceNameInts",
1536  "ControlledNameId",
1537  $CNId);
1538  }
1539  }
1540 
1541  # for each element of array
1542  foreach ($NewValue as $ControlledNameId => $ControlledName)
1543  {
1544  # associate with resource if not already associated
1545  if ($this->AddAssociation("ResourceNameInts",
1546  "ControlledNameId",
1547  $ControlledNameId))
1548  {
1549  $CN = new ControlledName($ControlledNameId);
1550  if ($CN->Status() != ControlledName::STATUS_OK)
1551  {
1552  $this->RemoveAssociation("ResourceNameInts",
1553  "ControlledNameId", $ControlledNameId);
1554  throw new InvalidArgumentException(
1555  "Attempt to set controlled name with"
1556  ." invalid ID (".$ControlledNameId.").");
1557  }
1558  $CN->UpdateLastAssigned();
1559  }
1560  }
1561  $UpdateModTime = TRUE;
1562  }
1563 
1564  if ($UpdateModTime)
1565  {
1566  # clear our controlled name cache
1567  unset($this->ControlledNameCache);
1568  unset($this->ControlledNameVariantCache);
1569 
1570  # clear visible count cache for any affected resources
1571  $ValueIds = array_keys($OldValue) + array_keys($NewValue);
1572  $DB->Query(
1573  "DELETE FROM VisibleResourceCounts WHERE "
1574  ."SchemaId=".intval($this->SchemaId)." AND "
1575  ."ValueId IN (".implode(",", $ValueIds).")");
1576  }
1577 
1578  break;
1579 
1581  # associate value(s) with resource
1582  $this->AddAssociation(
1583  "ResourceImageInts", "ImageId", $NewValue, $Field);
1584  # clear cached image mappings
1585  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1586  break;
1587 
1589  # convert incoming value to array if necessary
1590  if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1591 
1592  # for each incoming file
1593  $Factory = new FileFactory($Field->Id());
1594  foreach ($NewValue as $File)
1595  {
1596  # make copy of file
1597  $NewFile = $Factory->Copy($File);
1598 
1599  # associate copy with this resource and field
1600  $NewFile->ResourceId($this->Id);
1601  $NewFile->FieldId($Field->Id());
1602  }
1603  # Since we make a fresh copy of the File whenever Set is called,
1604  # we'll always update the modification time for this field.
1605  $UpdateModTime = TRUE;
1606  break;
1607 
1609  # convert incoming value to array to simplify the workflow
1610  if (is_scalar($NewValue) || $NewValue instanceof Resource)
1611  {
1612  $NewValue = array($NewValue);
1613  }
1614 
1615  # delete existing resource references
1616  $this->ClearByField($Field);
1617 
1618  # add each reference
1619  foreach ($NewValue as $ReferenceOrId)
1620  {
1621  # initially issume it's a reference ID and not an object...
1622  $ReferenceId = $ReferenceOrId;
1623 
1624  # ... but get the reference ID if it's an object
1625  if ($ReferenceOrId instanceof Resource)
1626  {
1627  $ReferenceId = $ReferenceOrId->Id();
1628  }
1629 
1630  # skip blank reference IDs
1631  if (strlen(trim($ReferenceId)) < 1)
1632  {
1633  continue;
1634  }
1635 
1636  # skip reference IDs that don't look right
1637  if (!is_numeric($ReferenceId))
1638  {
1639  continue;
1640  }
1641 
1642  # skip references to the current resource
1643  if ($ReferenceId == $this->Id())
1644  {
1645  continue;
1646  }
1647 
1648  # add the reference to the references table
1649  $DB->Query("
1650  INSERT INTO ReferenceInts (
1651  FieldId,
1652  SrcResourceId,
1653  DstResourceId)
1654  VALUES (
1655  ".addslashes($Field->Id()).",
1656  ".addslashes($this->Id()).",
1657  ".addslashes($ReferenceId).")");
1658  }
1659  break;
1660 
1661  default:
1662  # ERROR OUT
1663  exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1664  break;
1665  }
1666 
1667  if ($UpdateModTime && !$this->IsTempResource())
1668  {
1669  # update modification timestamps
1670  global $G_User;
1671  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1672  $DB->Query("DELETE FROM ResourceFieldTimestamps "
1673  ."WHERE ResourceId=".$this->Id." AND "
1674  ."FieldId=".$Field->Id() );
1675  $DB->Query("INSERT INTO ResourceFieldTimestamps "
1676  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1677  .$this->Id.",".$Field->Id().","
1678  .$UserId.",NOW())");
1679 
1680  # on resource modification, clear the UserPermsCache entry
1681  # so that stale permissions checks are not cached
1682  $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1683  }
1684  }
1685 
1693  public function SetByField($Field, $NewValue)
1694  {
1695  $this->Set($Field, $NewValue);
1696  }
1697 
1705  public function SetByFieldId($FieldId, $NewValue)
1706  {
1707  $this->Set($FieldId, $NewValue);
1708  }
1709 
1715  public function SetQualifier($FieldName, $NewValue)
1716  {
1717  $Field = $this->Schema()->GetFieldByName($FieldName);
1718  $this->SetQualifierByField($Field, $NewValue);
1719  }
1720 
1726  public function SetQualifierByFieldId($FieldId, $NewValue)
1727  {
1728  $Field = $this->Schema()->GetField($FieldId);
1729  $this->SetQualifierByField($Field, $NewValue);
1730  }
1731 
1737  public function SetQualifierByField($Field, $NewValue)
1738  {
1739  # if field uses qualifiers and uses item-level qualifiers
1740  if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1741  {
1742  # if qualifier object passed in
1743  if (is_object($NewValue))
1744  {
1745  # grab qualifier ID from object
1746  $QualifierId = $NewValue->Id();
1747  }
1748  else
1749  {
1750  # assume value passed in is qualifier ID
1751  $QualifierId = $NewValue;
1752  }
1753 
1754  # update qualifier value in database
1755  $DBFieldName = $Field->DBFieldName();
1756  $this->DB->Query("UPDATE Resources SET "
1757  .$DBFieldName."Qualifier = '".$QualifierId."' "
1758  ."WHERE ResourceId = ".$this->Id);
1759 
1760  # update local qualifier value
1761  $this->ValueCache[$DBFieldName."Qualifier"] = $QualifierId;
1762  }
1763  }
1764 
1771  public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1772  {
1773  $Field = $this->Schema()->GetField($FieldId);
1774  $this->Clear($Field, $ValueToClear);
1775  }
1776 
1783  public function Clear($Field, $ValueToClear = NULL)
1784  {
1785  # convert field name to object if necessary
1786  if (!is_object($Field))
1787  {
1788  $Field = $this->Schema()->GetFieldByName($Field);
1789  }
1790 
1791  # grab commonly-used values for local use
1792  $DB = $this->DB;
1793  $ResourceId = $this->Id;
1794 
1795  # grab database field name
1796  $DBFieldName = $Field->DBFieldName();
1797 
1798  $UpdateModTime=FALSE;
1799 
1800  # store value in DB based on field type
1801  switch ($Field->Type())
1802  {
1809  if (strlen($this->ValueCache[$DBFieldName])>0)
1810  {
1811  # clear value in DB
1812  $DB->Query("UPDATE Resources SET `"
1813  .$DBFieldName."` = NULL "
1814  ."WHERE ResourceId = ".$ResourceId);
1815 
1816  # clear value locally
1817  $this->ValueCache[$DBFieldName] = NULL;
1818  $UpdateModTime=TRUE;
1819  }
1820  break;
1821 
1823  if (!is_null($this->ValueCache[$DBFieldName."X"]) ||
1824  !is_null($this->ValueCache[$DBFieldName."Y"]) )
1825  {
1826  # Clear DB Values
1827  $DB->Query("UPDATE Resources SET "
1828  ."`".$DBFieldName."X` = NULL ,"
1829  ."`".$DBFieldName."Y` = NULL "
1830  ."WHERE ResourceId = ".$ResourceId);
1831 
1832  # Clear local values
1833  $this->ValueCache[$DBFieldName."X"] = NULL;
1834  $this->ValueCache[$DBFieldName."Y"] = NULL;
1835  $UpdateModTime=TRUE;
1836  }
1837  break;
1838 
1840  if (!is_null($this->ValueCache[$DBFieldName."Begin"]) ||
1841  !is_null($this->ValueCache[$DBFieldName."End"]) ||
1842  !is_null($this->ValueCache[$DBFieldName."Precision"]))
1843  {
1844  # clear date object values in DB
1845  $DB->Query("UPDATE Resources SET "
1846  .$DBFieldName."Begin = '', "
1847  .$DBFieldName."End = '', "
1848  .$DBFieldName."Precision = '' "
1849  ."WHERE ResourceId = ".$ResourceId);
1850 
1851  # clear value locally
1852  $this->ValueCache[$DBFieldName."Begin"] = NULL;
1853  $this->ValueCache[$DBFieldName."End"] = NULL;
1854  $this->ValueCache[$DBFieldName."Precision"] = NULL;
1855  $UpdateModTime=TRUE;
1856  }
1857  break;
1858 
1860  $OldValue = $this->Get($Field);
1861 
1862  # if value to clear supplied
1863  if ($ValueToClear !== NULL)
1864  {
1865  # if supplied value is array
1866  if (is_array($ValueToClear))
1867  {
1868  # for each element of array
1869  foreach ($ValueToClear as $ClassificationId => $Dummy)
1870  {
1871  if (array_key_exists($ClassificationId, $OldValue))
1872  {
1873  # remove association with resource (if any)
1874  $this->RemoveAssociation("ResourceClassInts",
1875  "ClassificationId",
1876  $ClassificationId);
1877  $Class = new Classification($ClassificationId);
1878  $Class->RecalcResourceCount();
1879  $UpdateModTime=TRUE;
1880  }
1881  }
1882  }
1883  else
1884  {
1885  if (array_key_exists($ValueToClear, $OldValue))
1886  {
1887  # remove association with resource (if any)
1888  $this->RemoveAssociation("ResourceClassInts",
1889  "ClassificationId",
1890  $ValueToClear);
1891  $Class = new Classification($ValueToClear);
1892  $Class->RecalcResourceCount();
1893  $UpdateModTime=TRUE;
1894  }
1895  }
1896  }
1897  else
1898  {
1899  if (count($OldValue)>0)
1900  {
1901  # remove all associations for resource and field
1902  $this->RemoveAllAssociations(
1903  "ResourceClassInts", "ClassificationId", $Field);
1904 
1905  # recompute resource count
1906  $Values = $this->Get($Field);
1907  foreach ($Values as $ClassificationId => $Dummy)
1908  {
1909  $Class = new Classification($ClassificationId);
1910  $Class->RecalcResourceCount();
1911  }
1912  $UpdateModTime=TRUE;
1913  }
1914  }
1915 
1916  # clear our classification cache
1917  if ($UpdateModTime)
1918  {
1919  unset($this->ClassificationCache);
1920  }
1921  break;
1922 
1925  $OldValue = $this->Get($Field);
1926  # if value to clear supplied
1927  if ($ValueToClear !== NULL)
1928  {
1929  # if incoming value is array
1930  if (is_array($ValueToClear))
1931  {
1932  # for each element of array
1933  foreach ($ValueToClear as $ControlledNameId =>
1934  $ControlledName)
1935  {
1936  if (array_key_exists($ControlledNameId, $OldValue))
1937  {
1938  # remove association with resource (if any)
1939  $this->RemoveAssociation("ResourceNameInts",
1940  "ControlledNameId",
1941  $ControlledNameId);
1942  $UpdateModTime=TRUE;
1943  }
1944  }
1945  }
1946  else
1947  {
1948  if (array_key_exists($ValueToClear, $OldValue))
1949  {
1950  # remove association with resource (if any)
1951  $this->RemoveAssociation("ResourceNameInts",
1952  "ControlledNameId",
1953  $ValueToClear);
1954  $UpdateModTime=TRUE;
1955  }
1956  }
1957  }
1958  else
1959  {
1960  if (count($OldValue)>0)
1961  {
1962  # remove all associations for resource and field
1963  $this->RemoveAllAssociations(
1964  "ResourceNameInts", "ControlledNameId", $Field);
1965  $UpdateModTime=TRUE;
1966  }
1967  }
1968 
1969  if ($UpdateModTime)
1970  {
1971  # clear our controlled name cache
1972  unset($this->ControlledNameCache);
1973  unset($this->ControlledNameVariantCache);
1974  }
1975  break;
1976 
1978  $OldValue = $this->Get($Field);
1979 
1980  # if value to clear supplied
1981  if ($ValueToClear !== NULL)
1982  {
1983  # if incoming value is array
1984  if (is_array($ValueToClear))
1985  {
1986  # for each element of array
1987  foreach ($ValueToClear as $UserId => $User)
1988  {
1989  if (array_key_exists($UserId, $OldValue))
1990  {
1991  # remove association with resource (if any)
1992  $this->RemoveAssociation("ResourceUserInts",
1993  "UserId",
1994  $UserId,
1995  $Field);
1996  $UpdateModTime=TRUE;
1997  }
1998  }
1999  }
2000  else
2001  {
2002  if (array_key_exists($ValueToClear, $OldValue))
2003  {
2004  # remove association with resource (if any)
2005  $this->RemoveAssociation("ResourceUserInts",
2006  "UserId",
2007  $UserId,
2008  $Field);
2009  $UpdateModTime=TRUE;
2010  }
2011  }
2012  }
2013  else
2014  {
2015  if (count($OldValue)>0)
2016  {
2017  # remove all associations for resource and field
2018  $this->RemoveAllAssociations(
2019  "ResourceUserInts", "UserId", $Field);
2020  $UpdateModTime=TRUE;
2021  }
2022  }
2023 
2024  break;
2025 
2027  # if value to clear supplied
2028  if ($ValueToClear !== NULL)
2029  {
2030  # convert value to array if necessary
2031  $Files = $ValueToClear;
2032  if (!is_array($Files)) { $Files = array($Files); }
2033 
2034  # convert values to objects if necessary
2035  foreach ($Files as $Index => $File)
2036  {
2037  if (!is_object($File))
2038  {
2039  $Files[$Index] = new File($File);
2040  }
2041  }
2042  }
2043  else
2044  {
2045  # use all files associated with resource
2046  $Files = $this->Get($Field, TRUE);
2047  }
2048 
2049  # delete files
2050  foreach ($Files as $File) { $File->Delete(); }
2051  break;
2052 
2054  # if value to clear supplied
2055  if ($ValueToClear !== NULL)
2056  {
2057  # convert value to array if necessary
2058  $Images = $ValueToClear;
2059  if (!is_array($Images)) { $Images = array($Images); }
2060 
2061  # convert values to objects if necessary
2062  foreach ($Images as $Index => $Image)
2063  {
2064  if (!is_object($Image))
2065  {
2066  $Images[$Index] = new SPTImage($Image);
2067  }
2068  }
2069  }
2070  else
2071  {
2072  # use all images associated with resource
2073  $Images = $this->Get($Field, TRUE);
2074  }
2075 
2076  # delete images if we are the last resource referencing
2077  # a particular image.
2078  foreach ($Images as $Image)
2079  {
2080  $Cnt = $this->DB->Query(
2081  "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
2082  "ImageId=".$Image->Id(), "Cnt");
2083  if ($Cnt==1)
2084  {
2085  $Image->Delete();
2086  }
2087  }
2088 
2089  # clear cached image mappings
2090  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
2091 
2092  # remove connections to images
2093  $UpdateModTime = $this->RemoveAssociation(
2094  "ResourceImageInts", "ImageId", $Images, $Field);
2095  break;
2096 
2098  # remove references from the references table
2099  $DB->Query("
2100  DELETE FROM ReferenceInts
2101  WHERE FieldId = '".addslashes($Field->Id())."'
2102  AND SrcResourceId = '".addslashes($this->Id())."'");
2103  break;
2104 
2105  default:
2106  # ERROR OUT
2107  exit("<br>SPT - ERROR: attempt to clear "
2108  ."unknown resource field type<br>\n");
2109  break;
2110  }
2111 
2112  if ($UpdateModTime && !$this->IsTempResource())
2113  {
2114  # update modification timestamps
2115  global $G_User;
2116  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
2117  $DB->Query("DELETE FROM ResourceFieldTimestamps "
2118  ."WHERE ResourceId=".$this->Id." AND "
2119  ."FieldId=".$Field->Id() );
2120  $DB->Query("INSERT INTO ResourceFieldTimestamps "
2121  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
2122  .$this->Id.",".$Field->Id().","
2123  .$UserId.",NOW())");
2124  }
2125  }
2126 
2135  public function ClearByField($Field, $ValueToClear = NULL)
2136  {
2137  $this->Clear($Field, $ValueToClear);
2138  }
2139 
2140  # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
2141 
2147  public function Classifications()
2148  {
2149  $DB = $this->DB;
2150 
2151  # start with empty array
2152  $Names = array();
2153 
2154  # for each controlled name
2155  $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2156  ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2157  ."Classifications, MetadataFields "
2158  ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2159  ."AND ResourceClassInts.ClassificationId = "
2160  ."Classifications.ClassificationId "
2161  ."AND Classifications.FieldId = MetadataFields.FieldId ");
2162  while ($Record = $DB->FetchRow())
2163  {
2164  # add name to array
2165  $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2166  $Record["ClassificationName"];
2167  }
2168 
2169  # return array to caller
2170  return $Names;
2171  }
2172 
2173 
2174  # --- Ratings Methods ---------------------------------------------------
2175 
2180  public function CumulativeRating()
2181  {
2182  return $this->CumulativeRating;
2183  }
2184 
2189  public function ScaledCumulativeRating()
2190  {
2191  if ($this->CumulativeRating == NULL)
2192  {
2193  return NULL;
2194  }
2195  else
2196  {
2197  return intval(($this->CumulativeRating + 5) / 10);
2198  }
2199  }
2200 
2205  public function NumberOfRatings()
2206  {
2207  # if number of ratings not already set
2208  if (!isset($this->NumberOfRatings))
2209  {
2210  # obtain number of ratings
2211  $this->NumberOfRatings =
2212  $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
2213  ."FROM ResourceRatings "
2214  ."WHERE ResourceId = ".$this->Id,
2215  "NumberOfRatings"
2216  );
2217 
2218  # recalculate cumulative rating if it looks erroneous
2219  if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
2220  {
2221  $this->UpdateCumulativeRating();
2222  }
2223  }
2224 
2225  # return number of ratings to caller
2226  return $this->NumberOfRatings;
2227  }
2228 
2236  public function Rating($NewRating = NULL, $UserId = NULL)
2237  {
2238  $DB = $this->DB;
2239 
2240  # if user ID not supplied
2241  if ($UserId == NULL)
2242  {
2243  # if user is logged in
2244  global $User;
2245  if ($User->IsLoggedIn())
2246  {
2247  # use ID of current user
2248  $UserId = $User->Get("UserId");
2249  }
2250  else
2251  {
2252  # return NULL to caller
2253  return NULL;
2254  }
2255  }
2256 
2257  # sanitize $NewRating
2258  if (!is_null($NewRating))
2259  {
2260  $NewRating = intval($NewRating);
2261  }
2262 
2263  # if there is a rating for resource and user
2264  $DB->Query("SELECT Rating FROM ResourceRatings "
2265  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2266  if ($Record = $DB->FetchRow())
2267  {
2268  # if new rating was supplied
2269  if ($NewRating != NULL)
2270  {
2271  # update existing rating
2272  $DB->Query("UPDATE ResourceRatings "
2273  ."SET Rating = ${NewRating}, DateRated = NOW() "
2274  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2275 
2276  # update cumulative rating value
2277  $this->UpdateCumulativeRating();
2278 
2279  # return value is new rating
2280  $Rating = $NewRating;
2281  }
2282  else
2283  {
2284  # get rating value to return to caller
2285  $Rating = $Record["Rating"];
2286  }
2287  }
2288  else
2289  {
2290  # if new rating was supplied
2291  if ($NewRating != NULL)
2292  {
2293  # add new rating
2294  $DB->Query("INSERT INTO ResourceRatings "
2295  ."(ResourceId, UserId, DateRated, Rating) "
2296  ."VALUES ("
2297  .$this->Id.", "
2298  ."${UserId}, "
2299  ."NOW(), "
2300  ."${NewRating})");
2301 
2302  # update cumulative rating value
2303  $this->UpdateCumulativeRating();
2304 
2305  # return value is new rating
2306  $Rating = $NewRating;
2307  }
2308  else
2309  {
2310  # return value is NULL
2311  $Rating = NULL;
2312  }
2313  }
2314 
2315  # return rating value to caller
2316  return $Rating;
2317  }
2318 
2319 
2320  # --- Resource Comment Methods ------------------------------------------
2321 
2326  public function Comments()
2327  {
2328  # read in comments if not already loaded
2329  if (!isset($this->Comments))
2330  {
2331  $this->DB->Query("SELECT MessageId FROM Messages "
2332  ."WHERE ParentId = ".$this->Id
2333  ." AND ParentType = 2 "
2334  ."ORDER BY DatePosted DESC");
2335  while ($MessageId = $this->DB->FetchField("MessageId"))
2336  {
2337  $this->Comments[] = new Message($MessageId);
2338  }
2339  }
2340 
2341  # return array of comments to caller
2342  return $this->Comments;
2343  }
2344 
2349  public function NumberOfComments()
2350  {
2351  # obtain number of comments if not already set
2352  if (!isset($this->NumberOfComments))
2353  {
2354  $this->NumberOfComments =
2355  $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2356  ."FROM Messages "
2357  ."WHERE ParentId = ".$this->Id
2358  ." AND ParentType = 2",
2359  "NumberOfComments"
2360  );
2361  }
2362 
2363  # return number of comments to caller
2364  return $this->NumberOfComments;
2365  }
2366 
2367 
2368  # --- Permission Methods -------------------------------------------------
2369 
2379  public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2380  {
2381  return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2382  }
2383 
2390  public function UserCanEdit($User)
2391  {
2392  return $this->CheckSchemaPermissions($User, "Edit");
2393  }
2394 
2401  public function UserCanAuthor($User)
2402  {
2403  return $this->CheckSchemaPermissions($User, "Author");
2404  }
2405 
2412  public function UserCanModify($User)
2413  {
2414  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2415  return $this->$CheckFn($User);
2416  }
2417 
2424  public function UserCanViewField($User, $FieldOrFieldName)
2425  {
2426  return $this->CheckFieldPermissions($User, $FieldOrFieldName, "View");
2427  }
2428 
2435  public function UserCanViewMappedField($User, $MappedName)
2436  {
2437  $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
2438  return ($FieldId === NULL) ? FALSE
2439  : $this->CheckFieldPermissions($User, $FieldId, "View");
2440  }
2441 
2448  public function UserCanEditField($User, $FieldOrFieldName)
2449  {
2450  return $this->CheckFieldPermissions($User, $FieldOrFieldName, "Edit");
2451  }
2452 
2459  public function UserCanAuthorField($User, $FieldOrFieldName)
2460  {
2461  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2462  }
2463 
2471  public function UserCanModifyField($User, $FieldOrFieldName)
2472  {
2473  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2474 
2475  return $this->$CheckFn($User, $FieldOrFieldName);
2476  }
2477 
2478  # --- Utility Methods ----------------------------------------------------
2479 
2484  {
2485  if (!$this->IsTempResource())
2486  {
2487  $SearchEngine = new SPTSearchEngine();
2488  $SearchEngine->QueueUpdateForItem($this);
2489 
2490  $Recommender = new SPTRecommender();
2491  $Recommender->QueueUpdateForItem($this);
2492  }
2493  }
2494 
2500  public static function GetSchemaForResource($ResourceId)
2501  {
2502  # if schema IDs are not loaded
2503  if (!isset(self::$SchemaIdCache))
2504  {
2505  # load schema IDs
2506  $DB = new Database();
2507  $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2508  self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2509  }
2510 
2511  # if multiple resources specified
2512  if (is_array($ResourceId))
2513  {
2514  # find schema IDs for specified resources
2515  $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2516  array_flip($ResourceId));
2517 
2518  # check that specified resource IDs were all valid
2519  if (count($SchemaIds) < count($ResourceId))
2520  {
2521  $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2522  throw new InvalidArgumentException("Unknown resource IDs ("
2523  .implode(", ", $BadIds).").");
2524  }
2525 
2526  # return schema IDs to caller
2527  return $SchemaIds;
2528  }
2529  else
2530  {
2531  # check that specified resource was valid
2532  if (!isset(self::$SchemaIdCache[$ResourceId]))
2533  {
2534  throw new InvalidArgumentException("Unknown resource ID ("
2535  .$ResourceId.").");
2536  }
2537 
2538  # return schema IDs for specified resource
2539  return self::$SchemaIdCache[$ResourceId];
2540  }
2541  }
2542 
2543 
2544  # ---- PRIVATE INTERFACE -------------------------------------------------
2545 
2546  private $ClassificationCache;
2547  private $Comments;
2548  private $ControlledNameCache;
2549  private $ControlledNameVariantCache;
2550  private $CumulativeRating;
2551  private $NumberOfComments;
2552  private $NumberOfRatings;
2553  private $PermissionCache;
2554  private $SchemaId;
2555 
2556  static private $Schemas;
2557  static private $SchemaIdCache;
2558 
2569  private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2570  {
2571  # construct a key to use for our permissions cache
2572  $CacheKey = "UserCan".$CheckType.$User->Id();
2573 
2574  # if we don't have a cached value for this perm, compute one
2575  if (!isset($this->PermissionCache[$CacheKey]))
2576  {
2577  # get privileges for schema
2578  $PermsFn = $CheckType."ingPrivileges";
2579  $SchemaPrivs = $this->Schema()->$PermsFn();
2580 
2581  # check passes if user privileges are greater than resource set
2582  $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2583 
2584  # save the result of this check in our cache
2585  $this->PermissionCache[$CacheKey] = $CheckResult;
2586  }
2587 
2588  $Value = $this->PermissionCache[$CacheKey];
2589 
2590  if ($AllowHooksToModify)
2591  {
2592  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2593  "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2594  array(
2595  "Resource" => $this,
2596  "User" => $User,
2597  "Can".$CheckType => $Value,
2598  "Schema" => $this->Schema(), ));
2599 
2600  $Value = $SignalResult["Can".$CheckType];
2601  }
2602 
2603  return $Value;
2604  }
2605 
2614  private function CheckFieldPermissions($User, $Field, $CheckType)
2615  {
2616  # get field object (if not supplied)
2617  if (!($Field instanceof MetadataField))
2618  {
2619  try
2620  {
2621  $Field = $this->Schema()->GetField($Field);
2622  }
2623  catch (InvalidArgumentException $Exception)
2624  {
2625  # (user cannot view/author/edit if field was invalid)
2626  return FALSE;
2627  }
2628  }
2629 
2630  # construct a key to use for our permissions cache
2631  $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2632 
2633  # if we don't have a cahced value, compute one
2634  if (!isset($this->PermissionCache[$CacheKey]))
2635  {
2636  # if field is enabled and editable, do permission check
2637  if ($Field->Enabled() &&
2638  ($CheckType == "View" || $Field->Editable()))
2639  {
2640  # be sure schema privs allow View/Edit/Author for this resource
2641  $SchemaCheckFn = "UserCan".$CheckType;
2642  if ($this->$SchemaCheckFn($User))
2643  {
2644  # get appropriate privilege set for field
2645  $PermsFn = $CheckType."ingPrivileges";
2646  $FieldPrivs = $Field->$PermsFn();
2647 
2648  # user can View/Edit/Author if privileges are greater than field set
2649  $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2650  }
2651  else
2652  {
2653  $CheckResult = FALSE;
2654  }
2655  }
2656  else
2657  {
2658  $CheckResult = FALSE;
2659  }
2660 
2661  # allow plugins to modify result of permission check
2662  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2663  "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2664  "Field" => $Field,
2665  "Resource" => $this,
2666  "User" => $User,
2667  "Can".$CheckType => $CheckResult));
2668  $CheckResult = $SignalResult["Can".$CheckType];
2669 
2670  # save the result of this check in our cache
2671  $this->PermissionCache[$CacheKey] = $CheckResult;
2672  }
2673 
2674  # return cached permission value
2675  return $this->PermissionCache[$CacheKey];
2676  }
2677 
2681  private function UpdateCumulativeRating()
2682  {
2683  # grab totals from DB
2684  $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2685  ."SUM(Rating) AS Total FROM ResourceRatings "
2686  ."WHERE ResourceId = ".$this->Id);
2687  $Record = $this->DB->FetchRow();
2688 
2689  # calculate new cumulative rating
2690  $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
2691 
2692  # save new cumulative rating in DB
2693  $this->DB->Query("UPDATE Resources "
2694  ."SET CumulativeRating = ".$this->CumulativeRating." "
2695  ."WHERE ResourceId = ".$this->Id);
2696  }
2697 
2709  private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2710  {
2711  # We should ignore duplicate key errors when doing inserts:
2712  $this->DB->SetQueryErrorsToIgnore( array(
2713  "/INSERT INTO ".$TableName."/" =>
2714  "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2715 
2716  # start out assuming no association will be added
2717  $AssociationAdded = FALSE;
2718 
2719  # convert new value to array if necessary
2720  $Values = is_array($Value) ? $Value : array($Value);
2721 
2722  # for each new value
2723  foreach ($Values as $Value)
2724  {
2725  # retrieve ID from value if necessary
2726  if (is_object($Value)) { $Value = $Value->Id(); }
2727 
2728  # Try to insert a new entry for this association.
2729  $this->DB->Query("INSERT INTO ".$TableName." SET"
2730  ." ResourceId = ".intval($this->Id)
2731  .", ".$FieldName." = ".intval($Value)
2732  .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2733 
2734  # If the insert ran without a duplicate key error,
2735  # then we added an assocation:
2736  if ($this->DB->IgnoredError() === FALSE)
2737  {
2738  $AssociationAdded = TRUE;
2739  }
2740  }
2741 
2742  # Clear ignored errors:
2743  $this->DB->SetQueryErrorsToIgnore( NULL );
2744 
2745  # report to caller whether association was added
2746  return $AssociationAdded;
2747  }
2748 
2760  private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2761  {
2762  # start out assuming no association will be removed
2763  $AssociationRemoved = FALSE;
2764 
2765  # convert value to array if necessary
2766  $Values = is_array($Value) ? $Value : array($Value);
2767 
2768  # for each value
2769  foreach ($Values as $Value)
2770  {
2771  # retrieve ID from value if necessary
2772  if (is_object($Value)) { $Value = $Value->Id(); }
2773 
2774  # remove any intersections with target ID from DB
2775  $this->DB->Query("DELETE FROM ".$TableName
2776  ." WHERE ResourceId = ".intval($this->Id)
2777  .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2778  ." AND ".$FieldName." = ".intval($Value));
2779  if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2780  }
2781 
2782  # report to caller whether association was added
2783  return $AssociationRemoved;
2784  }
2785 
2792  private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
2793  {
2794  # retrieve list of entries for this field and resource
2795  $Entries = $this->Get($Field);
2796 
2797  # divide them into chunks of not more than 100
2798  foreach (array_chunk($Entries, 100, TRUE) as $Chunk)
2799  {
2800  # remove assocations from this chunk
2801  $this->DB->Query("DELETE FROM ".$TableName
2802  ." WHERE ResourceId = ".intval($this->Id)
2803  ." AND ".$TargetFieldName." IN "
2804  ."(".implode(",", array_keys($Chunk)).")");
2805  }
2806  }
2807 
2814  static protected function SetDatabaseAccessValues($ClassName)
2815  {
2816  if (!isset(self::$ItemIdColumnNames[$ClassName]))
2817  {
2818  self::$ItemIdColumnNames[$ClassName] = "ResourceId";
2819  self::$ItemNameColumnNames[$ClassName] = NULL;
2820  self::$ItemTableNames[$ClassName] = "Resources";
2821  }
2822  }
2823 }
GetByField($FieldNameOrObject, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Old method for retrieving values, deprecated in favor of Get().
Definition: Resource.php:773
UserCanView(User $User, $AllowHooksToModify=TRUE)
Determine if the given user can view the resource, e.g., on the full record page. ...
Definition: Resource.php:2379
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:1106
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1715
UserCanViewMappedField($User, $MappedName)
Check whether user can view specified standard (mapped) metadata field.
Definition: Resource.php:2435
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:2471
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2483
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:811
Id()
Retrieve numerical resource ID.
Definition: Resource.php:291
$DB
Definition: Item.php:181
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2448
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1737
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:2236
Definition: User.php:48
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2349
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2205
GetQualifier($FieldName, $ReturnObject=TRUE)
Retrieve qualifier by field name.
Definition: Resource.php:874
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:2390
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:737
Comments()
Get comments for resource.
Definition: Resource.php:2326
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:2500
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:888
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:2459
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1783
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2412
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2401
GetByFieldId($FieldId, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field ID.
Definition: Resource.php:793
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:1693
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:857
$Id
Definition: Item.php:182
static SetDatabaseAccessValues($ClassName)
Set the database access values (table name, ID column name, name column name) for specified class...
Definition: Resource.php:2814
Represents a "resource" in CWIS.
Definition: Resource.php:13
GetQualifierByField($Field, $ReturnObject=TRUE)
Retrieve qualifier by Field object.
Definition: Resource.php:902
ClearByFieldId($FieldId, $ValueToClear=NULL)
Clear field value specified by field ID.
Definition: Resource.php:1771
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1726
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:2189
Set($Field, $NewValue, $Reset=FALSE)
Set value using field name or field object.
Definition: Resource.php:1141
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:2424
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1705
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:2147
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:2135
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:2180
FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
Determine if the value for a field is set.
Definition: Resource.php:1036
Delete()
Remove resource (and accompanying associations) from database and delete any associated files...
Definition: Resource.php:142