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 
24  public function __construct($ResourceId)
25  {
26  # call parent contstructor to load info from DB
27  parent::__construct($ResourceId);
28 
29  # load local attributes from database value cache
30  $this->CumulativeRating = $this->ValueCache["CumulativeRating"];
31 
32  # load our local metadata schema
33  $this->SchemaId = $this->ValueCache["SchemaId"];
34  if (!isset(self::$Schemas[$this->SchemaId]))
35  {
36  self::$Schemas[$this->SchemaId] =
37  new MetadataSchema($this->SchemaId);
38  }
39  }
40 
47  public static function Create($SchemaId)
48  {
49  # clean out any temp resource records more than three days old
50  $RFactory = new ResourceFactory();
51  $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
52 
53  # lock DB tables to prevent next ID from being grabbed
54  $DB = new Database;
55  $DB->Query("LOCK TABLES Resources WRITE");
56 
57  # find next temp resource ID
58  $Id = $RFactory->GetNextTempItemId();
59 
60  # write out new resource record with temp resource ID
61  # Set DateLastModified = NOW() to avoid being pruned as a
62  # stale temp resource.
63  $DB->Query(
64  "INSERT INTO Resources
65  SET `ResourceId` = '".intval($Id)."',
66  `SchemaId` = '".intval($SchemaId)."',
67  `DateLastModified` = NOW() " );
68 
69  # release DB tables
70  $DB->Query("UNLOCK TABLES");
71 
72  # create new Resource object
73  $Resource = new Resource($Id);
74 
75  # set some additional fields for default resources
76  if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
77  {
78  $Resource->Set("Added By Id", $GLOBALS["G_User"]->Id());
79  $Resource->Set("Last Modified By Id", $GLOBALS["G_User"]->Id());
80  $Resource->Set("Date Of Record Creation", date("Y-m-d H:i:s"));
81  $Resource->Set("Date Last Modified", date("Y-m-d H:i:s"));
82  }
83 
84  # for each field that can have a default value
85  $Schema = new MetadataSchema($SchemaId);
86  $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
91  foreach ($Fields as $Field)
92  {
93  # if there is a default value available
94  $DefaultValue = $Field->DefaultValue();
95  if ($DefaultValue !== NULL)
96  {
97  # if the default value is an array
98  if (is_array($DefaultValue))
99  {
100  # if there are values in the array
101  if (!empty($DefaultValue))
102  {
103  # flip values for Set() if necessary
104  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
105  {
106  $DefaultValue = array_flip($DefaultValue);
107  }
108 
109  # set default value
110  $Resource->Set($Field, $DefaultValue);
111  }
112  }
113  else
114  {
115  # set default value
116  $Resource->Set($Field, $DefaultValue);
117  }
118  }
119  }
120 
121  $Resource->UpdateAutoupdateFields(
123  $GLOBALS["G_User"]);
124 
125  # signal resource creation
126  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
127  "Resource" => $Resource,
128  ));
129 
130  # return new Resource object to caller
131  return $Resource;
132  }
133 
138  public function Delete()
139  {
140  global $SysConfig;
141 
142  # signal that resource deletion is about to occur
143  global $AF;
144  $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
145  "Resource" => $this,
146  ));
147 
148  # grab list of classifications
149  $Classifications = $this->Classifications();
150 
151  # delete resource/classification intersections
152  $DB = $this->DB;
153  $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
154 
155  # for each classification type
156  foreach ($Classifications as $ClassType => $ClassesOfType)
157  {
158  # for each classification of that type
159  foreach ($ClassesOfType as $ClassId => $ClassName)
160  {
161  # recalculate resource count for classification
162  $Class = new Classification($ClassId);
163  $Class->RecalcResourceCount();
164  }
165  }
166 
167  # delete resource references
168  $DB->Query("
169  DELETE FROM ReferenceInts
170  WHERE SrcResourceId = '".addslashes($this->Id())."'
171  OR DstResourceId = '".addslashes($this->Id())."'");
172 
173  # delete resource/name intersections
174  $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
175 
176  # delete resource/user intersections
177  $DB->Query("DELETE FROM ResourceUserInts WHERE ResourceId = ".$this->Id());
178 
179  # get the list of all images associated with this resource
180  $DB->Query("SELECT ImageId FROM ResourceImageInts"
181  ." WHERE ResourceId = ".intval($this->Id()));
182  $ImageIds = $DB->FetchColumn("ImageId");
183 
184  # disassociate this resource from all images
185  $DB->Query("DELETE FROM ResourceImageInts"
186  ." WHERE ResourceId = ".intval($this->Id()));
187 
188  # delete any images that no longer belong to any resources
189  foreach ($ImageIds as $ImageId)
190  {
191  $DB->Query("SELECT ResourceId FROM ResourceImageInts"
192  ." WHERE ImageId = ".intval($ImageId) );
193  if ($DB->NumRowsSelected() == 0)
194  {
195  $Image = new SPTImage($ImageId);
196  $Image->Delete();
197  }
198  }
199 
200  # delete any associated files
201  $Factory = new FileFactory(NULL);
202  $Files = $Factory->GetFilesForResource($this->Id());
203  foreach ($Files as $File)
204  {
205  $File->Delete();
206  }
207 
208  # delete resource record from database
209  $DB->Query("DELETE FROM Resources WHERE ResourceId = ".$this->Id());
210 
211  # drop item from search engine and recommender system
212  if ($SysConfig->SearchDBEnabled())
213  {
214  $SearchEngine = new SPTSearchEngine();
215  $SearchEngine->DropItem($this->Id());
216  }
217  if ($SysConfig->RecommenderDBEnabled())
218  {
219  $Recommender = new SPTRecommender();
220  $Recommender->DropItem($this->Id());
221  }
222 
223  # get the folders containing the resource
224  $FolderFactory = new FolderFactory();
225  $Folders = $FolderFactory->GetFoldersContainingItem(
226  $this->Id,
227  "Resource");
228 
229  # drop the resource from each folder it belongs to
230  foreach ($Folders as $Folder)
231  {
232  # mixed item type folder
233  if ($Folder->ContainsItem($this->Id, "Resource"))
234  {
235  $Folder->RemoveItem($this->Id, "Resource");
236  }
237 
238  # single item type folder
239  else
240  {
241  $Folder->RemoveItem($this->Id);
242  }
243  }
244 
245  # delete any resource comments
246  $DB->Query("DELETE FROM Messages WHERE ParentId = ".$this->Id);
247  }
248 
255  public function UpdateAutoupdateFields($UpdateType, $User=NULL)
256  {
257  # update all the timestamp fields as required
258  $TimestampFields = $this->Schema()->GetFields(
260  foreach ($TimestampFields as $Field)
261  {
262  if ($Field->UpdateMethod() == $UpdateType)
263  {
264  $this->Set($Field, "now");
265  }
266  }
267 
268  # if a user was provided, update the user fields as well
269  if (!is_null($User))
270  {
271  $UserFields = $this->Schema()->GetFields(
273  foreach ($UserFields as $Field)
274  {
275  if ($Field->UpdateMethod() == $UpdateType)
276  {
277  $this->Set($Field, $User);
278  }
279  }
280  }
281  }
282 
287  public function Id()
288  {
289  return $this->Id;
290  }
291 
296  public function SchemaId()
297  {
298  return $this->SchemaId;
299  }
300 
305  public function Schema()
306  {
307  return self::$Schemas[$this->SchemaId];
308  }
309 
316  public function IsTempResource($NewSetting = NULL)
317  {
318  # if new temp resource setting supplied
319  if (!is_null($NewSetting))
320  {
321  # if caller requested to switch
322  $DB = $this->DB;
323  if ((($this->Id() < 0) && ($NewSetting == FALSE))
324  || (($this->Id() >= 0) && ($NewSetting == TRUE)))
325  {
326  # lock DB tables to prevent next ID from being grabbed
327  $DB->Query("LOCK TABLES Resources write");
328 
329  # get next resource ID as appropriate
330  $OldResourceId = $this->Id;
331  $Factory = new ResourceFactory($this->SchemaId);
332  if ($NewSetting == TRUE)
333  {
334  $this->Id = $Factory->GetNextTempItemId();
335  }
336  else
337  {
338  $this->Id = $Factory->GetNextItemId();
339  }
340 
341  # change resource ID
342  $DB->Query("UPDATE Resources SET ResourceId = ".
343  $this->Id. " WHERE ResourceId = ".$OldResourceId);
344 
345  # release DB tables
346  $DB->Query("UNLOCK TABLES");
347 
348  # change associations
349  unset($this->ClassificationCache);
350  $DB->Query("UPDATE ResourceClassInts SET ResourceId = ".
351  $this->Id. " WHERE ResourceId = ".$OldResourceId);
352  unset($this->ControlledNameCache);
353  unset($this->ControlledNameVariantCache);
354  $DB->Query("UPDATE ResourceNameInts SET ResourceId = ".
355  $this->Id. " WHERE ResourceId = ".$OldResourceId);
356  $DB->Query("UPDATE Files SET ResourceId = ".
357  $this->Id. " WHERE ResourceId = ".$OldResourceId);
358  $DB->Query("UPDATE ReferenceInts SET SrcResourceId = ".
359  $this->Id. " WHERE SrcResourceId = ".$OldResourceId);
360  $DB->Query("UPDATE ResourceImageInts SET ResourceId = ".
361  $this->Id. " WHERE ResourceId = ".$OldResourceId);
362  $DB->Query("UPDATE ResourceUserInts SET ResourceId = ".
363  $this->Id. " WHERE ResourceId = ".$OldResourceId);
364 
365  # signal event as appropriate
366  if ($NewSetting === FALSE)
367  {
368  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_ADD", array(
369  "Resource" => $this,
370  ));
371  }
372  }
373  }
374 
375  # report to caller whether we are a temp resource
376  return ($this->Id() < 0) ? TRUE : FALSE;
377  }
378 
379 
380  # --- Generic Attribute Retrieval Methods -------------------------------
381 
386  public function GetViewPageUrl()
387  {
388  # put our Id into the ViewPage from our schema
389  $Url = str_replace(
390  "\$ID", $this->Id(),
391  $this->Schema()->ViewPage());
392 
393  # return clean url, if one is available
394  return $GLOBALS["AF"]->GetCleanUrlForPath($Url);
395  }
396 
410  public function Get($Field, $ReturnObject = FALSE, $IncludeVariants = FALSE)
411  {
412  # load field object if not already supplied
413  $Field = is_object($Field) ? $Field
414  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
415  : $this->Schema()->GetFieldByName($Field));
416 
417  # return no value found if we don't have a valid field
418  if (!($Field instanceof MetadataField)) { return NULL; }
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  $Schema = $this->Schema();
861  $FieldId = $Schema->StdNameToFieldMapping($MappedName);
862  return $FieldId
863  ? $this->Get($FieldId, $ReturnObject, $IncludeVariants)
864  : NULL;
865  }
866 
875  public function GetQualifier($FieldName, $ReturnObject = TRUE)
876  {
877  $Field = $this->Schema()->GetFieldByName($FieldName);
878  return $this->GetQualifierByField($Field, $ReturnObject);
879  }
880 
889  public function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
890  {
891  $Field = $this->Schema()->GetField($FieldId);
892  return ($Field) ? $this->GetQualifierByField($Field, $ReturnObject) : NULL;
893  }
894 
903  public function GetQualifierByField($Field, $ReturnObject = TRUE)
904  {
905  # return NULL if field is invalid
906  if (!($Field instanceof MetadataField)) { return NULL; }
907 
908  # assume no qualifiers if not otherwise determined
909  $ReturnValue = NULL;
910 
911  # if field uses qualifiers
912  if ($Field->UsesQualifiers())
913  {
914  # retrieve qualifiers based on field type
915  switch ($Field->Type())
916  {
920  # retrieve list of items
921  $Items = $this->Get($Field);
922 
923  # if field uses item-level qualifiers
924  if ($Field->HasItemLevelQualifiers())
925  {
926  # determine general item name in DB
927  $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
928  ? "Classification" : "ControlledName";
929 
930  # for each item
931  foreach ($Items as $ItemId => $ItemName)
932  {
933  # look up qualifier for item
934  $QualId = $this->DB->Query(
935  "SELECT * FROM ".$TableName."s"
936  ." WHERE ".$TableName."Id = ".$ItemId,
937  "QualifierId");
938 
939 
940  if ($QualId > 0)
941  {
942  # if object was requested by caller
943  if ($ReturnObject)
944  {
945  # load qualifier and add to return value array
946  $ReturnValue[$ItemId] = new Qualifier($QualId);
947  }
948  else
949  {
950  # add qualifier ID to return value array
951  $ReturnValue[$ItemId] = $QualId;
952  }
953  }
954  else
955  {
956  # add NULL to return value array for this item
957  $ReturnValue[$ItemId] = NULL;
958  }
959  }
960  }
961  else
962  {
963  # for each item
964  foreach ($Items as $ItemId => $ItemName)
965  {
966  # if object was requested by caller
967  if ($ReturnObject)
968  {
969  # load default qualifier and add to return value array
970  $ReturnValue[$ItemId] = new Qualifier(
971  $Field->DefaultQualifier());
972  }
973  else
974  {
975  # add default qualifier ID to return value array
976  $ReturnValue[$ItemId] = $Field->DefaultQualifier();
977  }
978  }
979  }
980  break;
981 
982  default:
983  # if field uses item-level qualifiers
984  if ($Field->HasItemLevelQualifiers())
985  {
986  # if qualifier available
987  if ($this->ValueCache[$Field->DBFieldName()."Qualifier"] > 0)
988  {
989  # if object was requested by caller
990  $QFieldName = $Field->DBFieldName()."Qualifier";
991  if ($ReturnObject)
992  {
993  # return qualifier for field
994  $ReturnValue = new Qualifier(
995  $this->ValueCache[$QFieldName]);
996  }
997  else
998  {
999  # return qualifier ID for field
1000  $ReturnValue = $this->ValueCache[$QFieldName];
1001  }
1002  }
1003  }
1004  else
1005  {
1006  # if default qualifier available
1007  if ($Field->DefaultQualifier() > 0)
1008  {
1009  # if object was requested by caller
1010  if ($ReturnObject)
1011  {
1012  # return default qualifier
1013  $ReturnValue = new Qualifier($Field->DefaultQualifier());
1014  }
1015  else
1016  {
1017  # return default qualifier ID
1018  $ReturnValue = $Field->DefaultQualifier();
1019  }
1020  }
1021  }
1022  break;
1023  }
1024  }
1025 
1026  # return qualifier object or ID (or array of same) to caller
1027  return $ReturnValue;
1028  }
1029 
1037  public function FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
1038  {
1039  # load field object if needed
1040  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1041  : $this->Schema()->GetFieldByName($FieldNameOrObject);
1042 
1043  # return no value found if we don't have a valid field
1044  if (!($Field instanceof MetadataField)) { return FALSE; }
1045 
1046  # get the value
1047  $Value = $this->Get($Field);
1048 
1049  # checks depend on the field type
1050  switch ($Field->Type())
1051  {
1056  return isset($Value)
1057  && strlen($Value)
1058  && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1059 
1061  return isset($Value)
1062  && strlen($Value);
1063 
1065  return isset($Value["X"])
1066  && isset($Value["Y"])
1067  && strlen(trim($Value["X"]))
1068  && strlen(trim($Value["Y"]));
1069 
1071  return isset($Value)
1072  && strlen(trim($Value))
1073  && $Value != "0000-00-00";
1074 
1076  return isset($Value)
1077  && strlen(trim($Value))
1078  && $Value != "0000-00-00 00:00:00";
1079 
1086  return count($Value) > 0;
1087 
1089  $Factory = new CWUserFactory();
1090  return isset($Value)
1091  && strlen($Value)
1092  && $Factory->UserNameExists($Value);
1093 
1094  default:
1095  return FALSE;
1096  }
1097  }
1098 
1107  public function GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
1108  {
1109  $Result = array();
1110 
1111  # get our target field and extract its values
1112  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1113  : $this->Schema()->GetField($FieldNameOrObject);
1114  $Images = $this->Get($Field, TRUE);
1115 
1116  # iterate over our images getting URLs for each
1117  $Index = 0;
1118  foreach ($Images as $Image)
1119  {
1120  $Result[$Image->Id()] = $Image->GetImageUrlForResource(
1121  $this->Id(), $Field->Id(), $Index, $ImageSize);
1122  $Index++;
1123  }
1124 
1125  return $Result;
1126  }
1127 
1128  # --- Generic Attribute Setting Methods ---------------------------------
1129 
1142  public function Set($Field, $NewValue, $Reset=FALSE)
1143  {
1144  # load field object if not already supplied
1145  $Field = is_object($Field) ? $Field
1146  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
1147  : $this->Schema()->GetFieldByName($Field));
1148 
1149  # return if we don't have a valid field
1150  if (!($Field instanceof MetadataField)) { return; }
1151 
1152  if ($Field->SchemaId() != $this->SchemaId())
1153  {
1154  throw new Exception("Attempt to set a value for a field "
1155  ."from a different schema.");
1156  }
1157 
1158  # grab commonly-used values for local use
1159  $DB = $this->DB;
1160  $ResourceId = $this->Id;
1161 
1162  # grab database field name
1163  $DBFieldName = $Field->DBFieldName();
1164 
1165  # Flag to deterimine if we've actually changed anything.
1166  $UpdateModTime = FALSE;
1167 
1168  # store value in DB based on field type
1169  switch ($Field->Type())
1170  {
1174  if ($this->ValueCache[$DBFieldName] != $NewValue)
1175  {
1176  # save value directly to DB
1177  $DB->Query("UPDATE Resources SET `"
1178  .$DBFieldName."` = '".addslashes($NewValue)."' "
1179  ."WHERE ResourceId = ".$ResourceId);
1180 
1181  # save value locally
1182  $this->ValueCache[$DBFieldName] = $NewValue;
1183  $UpdateModTime=TRUE;
1184  }
1185  break;
1186 
1188  if ( $this->ValueCache[$DBFieldName] != $NewValue )
1189  {
1190  # save value directly to DB
1191  if (is_null($NewValue))
1192  {
1193  $DB->Query("UPDATE Resources SET `"
1194  .$DBFieldName."` = NULL"
1195  ." WHERE ResourceId = ".$ResourceId);
1196  }
1197  else
1198  {
1199  $DB->Query("UPDATE Resources SET `"
1200  .$DBFieldName."` = ".intval($NewValue)
1201  ." WHERE ResourceId = ".$ResourceId);
1202  }
1203 
1204  # save value locally
1205  $this->ValueCache[$DBFieldName] = $NewValue;
1206  $UpdateModTime = TRUE;
1207  }
1208  break;
1209 
1210 
1212  if ($this->ValueCache[$DBFieldName."X"] != $NewValue["X"] ||
1213  $this->ValueCache[$DBFieldName."Y"] != $NewValue["Y"] )
1214  {
1215  if (is_null($NewValue))
1216  {
1217  $DB->Query("UPDATE Resources SET "
1218  ."`".$DBFieldName."X` = NULL, "
1219  ."`".$DBFieldName."Y` = NULL "
1220  ."WHERE ResourceId = ".$ResourceId);
1221  $this->ValueCache[$DBFieldName."X"] = NULL;
1222  $this->ValueCache[$DBFieldName."Y"] = NULL;
1223  }
1224  else
1225  {
1226  $DB->Query("UPDATE Resources SET "
1227  ."`".$DBFieldName."X` = " .(strlen($NewValue["X"])
1228  ? "'".$NewValue["X"]."'" : "NULL").", "
1229  ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
1230  ? "'".$NewValue["Y"]."'" : "NULL")
1231  ." WHERE ResourceId = ".$ResourceId);
1232 
1233  $Digits = $Field->PointDecimalDigits();
1234 
1235  $this->ValueCache[$DBFieldName."X"] =
1236  strlen($NewValue["X"]) ?
1237  round($NewValue["X"], $Digits) : NULL;
1238  $this->ValueCache[$DBFieldName."Y"] =
1239  strlen($NewValue["Y"]) ?
1240  round($NewValue["Y"], $Digits) : NULL;
1241  }
1242  $UpdateModTime = TRUE;
1243  }
1244  break;
1245 
1247  if ($this->ValueCache[$DBFieldName] != $NewValue)
1248  {
1249  # save value directly to DB
1250  if (is_null($NewValue))
1251  {
1252  $DB->Query("UPDATE Resources SET `"
1253  .$DBFieldName."` = NULL"
1254  ." WHERE ResourceId = ".$ResourceId);
1255  }
1256  else
1257  {
1258  $NewValue = $NewValue ? "1" : "0";
1259  $DB->Query("UPDATE Resources SET `"
1260  .$DBFieldName."` = ".$NewValue
1261  ." WHERE ResourceId = ".$ResourceId);
1262  }
1263 
1264  $this->ValueCache[$DBFieldName] = $NewValue;
1265 
1266  # recalculate counts for any associated classifications if necessary
1267  if ($DBFieldName == "ReleaseFlag")
1268  {
1269  $DB->Query("SELECT ClassificationId FROM ResourceClassInts"
1270  ." WHERE ResourceId = ".$ResourceId);
1271  while ($ClassId = $DB->FetchField("ClassificationId"))
1272  {
1273  $Class = new Classification($ClassId);
1274  $Class->RecalcResourceCount();
1275  }
1276  }
1277  $UpdateModTime = TRUE;
1278  }
1279  break;
1280 
1282  $OldValue = $this->Get($Field);
1283  # value comes back as array (UserId => UserName), just get the Ids
1284  $OldValue = array_keys($OldValue);
1285 
1286  # input to Set() for these fields is one of
1287  # 1. an int specifying a UserId
1288  if (is_numeric($NewValue))
1289  {
1290  $NewValue = array($NewValue);
1291  }
1292  # 2. a CWUser object
1293  elseif ($NewValue instanceof CWUser)
1294  {
1295  $NewValue = array($NewValue->Id());
1296  }
1297  # 3. an array keyed by UserId (don't care about the values)
1298  elseif (is_array($NewValue))
1299  {
1300  $NewValue = array_keys($NewValue);
1301  }
1302  else
1303  {
1304  throw new Exception("Unknown format for NewValue in a User field");
1305  }
1306 
1307  # if this is a unique field, only accept the first of the options given
1308  if ($Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1309  {
1310  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1311  }
1312 
1313  # sort new and old values so we can directly compare
1314  sort($OldValue);
1315  sort($NewValue);
1316 
1317  # if the value has changed
1318  if ($OldValue != $NewValue)
1319  {
1320  if ($Reset || $Field->AllowMultiple() == FALSE )
1321  {
1322  $ToRemove = array_diff($OldValue, $NewValue);
1323  $this->RemoveAssociation(
1324  "ResourceUserInts", "UserId", $ToRemove, $Field);
1325  }
1326 
1327  # associate with resource if not already associated
1328  $this->AddAssociation("ResourceUserInts",
1329  "UserId",
1330  $NewValue, $Field);
1331 
1332  $UpdateModTime=TRUE;
1333  }
1334  break;
1335 
1337  # if we were given a date object
1338  if (is_object($NewValue))
1339  {
1340  # use supplied date object
1341  $Date = $NewValue;
1342  }
1343  else
1344  {
1345  # create date object
1346  $Date = new Date($NewValue);
1347  }
1348 
1349  $OldDate = new Date(
1350  $this->ValueCache[$DBFieldName."Begin"],
1351  $this->ValueCache[$DBFieldName."End"]);
1352 
1353  if ($OldDate->BeginDate() != $Date->BeginDate() ||
1354  $OldDate->EndDate() != $Date->EndDate() ||
1355  $OldDate->Precision() != $Date->Precision() )
1356  {
1357  # extract values from date object and store in DB
1358  $BeginDate = "'".$Date->BeginDate()."'";
1359  if (strlen($BeginDate) < 3) { $BeginDate = "NULL"; }
1360  $EndDate = "'".$Date->EndDate()."'";
1361  if (strlen($EndDate) < 3) { $EndDate = "NULL"; }
1362 
1363  $DB->Query("UPDATE Resources SET "
1364  .$DBFieldName."Begin = ".$BeginDate.", "
1365  .$DBFieldName."End = ".$EndDate.", "
1366  .$DBFieldName."Precision = '".$Date->Precision()."' "
1367  ."WHERE ResourceId = ".$ResourceId);
1368 
1369  # save values locally
1370  $this->ValueCache[$DBFieldName."Begin"] = $Date->BeginDate();
1371  $this->ValueCache[$DBFieldName."End"] = $Date->EndDate();
1372  $this->ValueCache[$DBFieldName."Precision"] = $Date->Precision();
1373  $UpdateModTime=TRUE;
1374  }
1375  break;
1376 
1378  if (is_null($NewValue) || !strlen(trim($NewValue)))
1379  {
1380  $DateValue = $NewValue;
1381 
1382  if (!is_null($this->ValueCache[$DBFieldName]))
1383  {
1384  # save value directly to DB
1385  $DB->Query("UPDATE Resources SET "
1386  ."`".$DBFieldName."` = NULL "
1387  ."WHERE ResourceId = ".$ResourceId);
1388  $UpdateModTime = TRUE;
1389  }
1390  }
1391  else
1392  {
1393  # assume value is date and use directly
1394  $TimestampValue = strtotime($NewValue);
1395 
1396  # use the new value if the date is valid
1397  if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1398  {
1399  $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1400 
1401  if ($this->ValueCache[$DBFieldName] != $DateValue)
1402  {
1403  # save value directly to DB
1404  $DB->Query("UPDATE Resources SET "
1405  ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1406  ."WHERE ResourceId = ".$ResourceId);
1407  $UpdateModTime=TRUE;
1408  }
1409  }
1410 
1411  # continue using the old value if invalid
1412  else
1413  {
1414  $DateValue = $this->Get($Field);
1415  }
1416  }
1417 
1418  # save value locally
1419  $this->ValueCache[$DBFieldName] = $DateValue;
1420  break;
1421 
1423  $OldValue = $this->Get($Field);
1424 
1425  # if incoming value is array
1426  if (is_array($NewValue))
1427  {
1428  if ($OldValue != $NewValue)
1429  {
1430  if ($Reset)
1431  {
1432  # remove values that were in the old value
1433  # but not the new one
1434  $ToRemove = array_diff(array_keys($OldValue),
1435  array_keys($NewValue));
1436  foreach ($ToRemove as $ClassificationId)
1437  {
1438  $this->RemoveAssociation("ResourceClassInts",
1439  "ClassificationId",
1440  $ClassificationId);
1441  $Class = new Classification($ClassificationId);
1442  $Class->RecalcResourceCount();
1443  }
1444  }
1445 
1446  # for each element of array
1447  foreach ($NewValue as
1448  $ClassificationId => $ClassificationName)
1449  {
1450  $Class = new Classification($ClassificationId);
1451  if ($Class->FieldId() == $Field->Id())
1452  {
1453  # associate with resource if not already associated
1454  if ($this->AddAssociation("ResourceClassInts",
1455  "ClassificationId", $ClassificationId))
1456  {
1457  $Class->UpdateLastAssigned();
1458  $Class->RecalcResourceCount();
1459  }
1460  }
1461  else
1462  {
1463  throw new Exception(
1464  "Attempting to store classification from "
1465  ."Field ".$Class->FieldId()." into Field "
1466  .$Field->Id() );
1467  }
1468 
1469  }
1470 
1471  $UpdateModTime=TRUE;
1472  }
1473  }
1474  else
1475  {
1476  # associate with resource if not already associated
1477  if (is_object($NewValue))
1478  {
1479  $Class = $NewValue;
1480  $NewValue = $Class->Id();
1481  }
1482  else
1483  {
1484  $Class = new Classification($NewValue);
1485  }
1486 
1487  if (!array_key_exists($Class->Id(), $OldValue))
1488  {
1489 
1490  $this->AddAssociation("ResourceClassInts",
1491  "ClassificationId",
1492  $NewValue);
1493  $Class->UpdateLastAssigned();
1494  $Class->RecalcResourceCount();
1495  $UpdateModTime=TRUE;
1496  }
1497  }
1498 
1499  # clear our classification cache
1500  if ($UpdateModTime)
1501  {
1502  unset($this->ClassificationCache);
1503  }
1504  break;
1505 
1508  $OldValue = $this->Get($Field);
1509 
1510  # input to Set() for these fields is one of
1511  # 1. an int specifying a ControlledNameId
1512  # 2. a ControlledName object
1513  # 3. an array with keys giving Ids and values giving ControlledNames
1514  #
1515  # normalize 1 and 2 into 3 for simplicity of processing
1516  if (is_object($NewValue) || !is_array($NewValue) )
1517  {
1518  if (!is_object($NewValue))
1519  {
1520  $NewValue = new ControlledName($NewValue);
1521  }
1522 
1523  $TmpValue = array();
1524  $TmpValue[$NewValue->Id()] = $NewValue->Name();
1525 
1526  $NewValue = $TmpValue;
1527  }
1528 
1529  # if this is a unique field, only accept the first of the options given
1530  # NB: all ControlledNames implicitly AllowMultiple
1531  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1532  $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1533  {
1534  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1535  }
1536 
1537  # if the value has changed
1538  if ($OldValue != $NewValue)
1539  {
1540  if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1541  && $Field->AllowMultiple() == FALSE ) )
1542  {
1543  $ToRemove = array_diff(array_keys($OldValue),
1544  array_keys($NewValue));
1545  foreach ($ToRemove as $CNId)
1546  {
1547  $this->RemoveAssociation("ResourceNameInts",
1548  "ControlledNameId",
1549  $CNId);
1550  }
1551  }
1552 
1553  # for each element of array
1554  foreach ($NewValue as $ControlledNameId => $ControlledName)
1555  {
1556  # associate with resource if not already associated
1557  if ($this->AddAssociation("ResourceNameInts",
1558  "ControlledNameId",
1559  $ControlledNameId))
1560  {
1561  $CN = new ControlledName($ControlledNameId);
1562  if ($CN->Status() != ControlledName::STATUS_OK)
1563  {
1564  $this->RemoveAssociation("ResourceNameInts",
1565  "ControlledNameId", $ControlledNameId);
1566  throw new InvalidArgumentException(
1567  "Attempt to set controlled name with"
1568  ." invalid ID (".$ControlledNameId.").");
1569  }
1570  $CN->UpdateLastAssigned();
1571  }
1572  }
1573  $UpdateModTime = TRUE;
1574  }
1575 
1576  if ($UpdateModTime)
1577  {
1578  # clear our controlled name cache
1579  unset($this->ControlledNameCache);
1580  unset($this->ControlledNameVariantCache);
1581 
1582  # clear visible count cache for any affected resources
1583  $ValueIds = array_keys($OldValue) + array_keys($NewValue);
1584  $DB->Query(
1585  "DELETE FROM VisibleResourceCounts WHERE "
1586  ."SchemaId=".intval($this->SchemaId)." AND "
1587  ."ValueId IN (".implode(",", $ValueIds).")");
1588  }
1589 
1590  break;
1591 
1593  # associate value(s) with resource
1594  $this->AddAssociation(
1595  "ResourceImageInts", "ImageId", $NewValue, $Field);
1596  # clear cached image mappings
1597  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1598  break;
1599 
1601  # convert incoming value to array if necessary
1602  if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1603 
1604  # for each incoming file
1605  $Factory = new FileFactory($Field->Id());
1606  foreach ($NewValue as $File)
1607  {
1608  # make copy of file
1609  $NewFile = $Factory->Copy($File);
1610 
1611  # associate copy with this resource and field
1612  $NewFile->ResourceId($this->Id);
1613  $NewFile->FieldId($Field->Id());
1614  }
1615  # Since we make a fresh copy of the File whenever Set is called,
1616  # we'll always update the modification time for this field.
1617  $UpdateModTime = TRUE;
1618  break;
1619 
1621  # convert incoming value to array to simplify the workflow
1622  if (is_scalar($NewValue) || $NewValue instanceof Resource)
1623  {
1624  $NewValue = array($NewValue);
1625  }
1626 
1627  # delete existing resource references
1628  $this->ClearByField($Field);
1629 
1630  # add each reference
1631  foreach ($NewValue as $ReferenceOrId)
1632  {
1633  # initially issume it's a reference ID and not an object...
1634  $ReferenceId = $ReferenceOrId;
1635 
1636  # ... but get the reference ID if it's an object
1637  if ($ReferenceOrId instanceof Resource)
1638  {
1639  $ReferenceId = $ReferenceOrId->Id();
1640  }
1641 
1642  # skip blank reference IDs
1643  if (strlen(trim($ReferenceId)) < 1)
1644  {
1645  continue;
1646  }
1647 
1648  # skip reference IDs that don't look right
1649  if (!is_numeric($ReferenceId))
1650  {
1651  continue;
1652  }
1653 
1654  # skip references to the current resource
1655  if ($ReferenceId == $this->Id())
1656  {
1657  continue;
1658  }
1659 
1660  # add the reference to the references table
1661  $DB->Query("
1662  INSERT INTO ReferenceInts (
1663  FieldId,
1664  SrcResourceId,
1665  DstResourceId)
1666  VALUES (
1667  ".addslashes($Field->Id()).",
1668  ".addslashes($this->Id()).",
1669  ".addslashes($ReferenceId).")");
1670  }
1671  break;
1672 
1673  default:
1674  # ERROR OUT
1675  exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1676  break;
1677  }
1678 
1679  if ($UpdateModTime && !$this->IsTempResource())
1680  {
1681  # update modification timestamps
1682  global $G_User;
1683  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1684  $DB->Query("DELETE FROM ResourceFieldTimestamps "
1685  ."WHERE ResourceId=".$this->Id." AND "
1686  ."FieldId=".$Field->Id() );
1687  $DB->Query("INSERT INTO ResourceFieldTimestamps "
1688  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1689  .$this->Id.",".$Field->Id().","
1690  .$UserId.",NOW())");
1691 
1692  # on resource modification, clear the UserPermsCache entry
1693  # so that stale permissions checks are not cached
1694  $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1695  }
1696  }
1697 
1705  public function SetByField($Field, $NewValue)
1706  {
1707  $this->Set($Field, $NewValue);
1708  }
1709 
1717  public function SetByFieldId($FieldId, $NewValue)
1718  {
1719  $this->Set($FieldId, $NewValue);
1720  }
1721 
1727  public function SetQualifier($FieldName, $NewValue)
1728  {
1729  $Field = $this->Schema()->GetFieldByName($FieldName);
1730  $this->SetQualifierByField($Field, $NewValue);
1731  }
1732 
1738  public function SetQualifierByFieldId($FieldId, $NewValue)
1739  {
1740  $Field = $this->Schema()->GetField($FieldId);
1741  $this->SetQualifierByField($Field, $NewValue);
1742  }
1743 
1749  public function SetQualifierByField($Field, $NewValue)
1750  {
1751  # if field uses qualifiers and uses item-level qualifiers
1752  if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1753  {
1754  # if qualifier object passed in
1755  if (is_object($NewValue))
1756  {
1757  # grab qualifier ID from object
1758  $QualifierId = $NewValue->Id();
1759  }
1760  else
1761  {
1762  # assume value passed in is qualifier ID
1763  $QualifierId = $NewValue;
1764  }
1765 
1766  # update qualifier value in database
1767  $DBFieldName = $Field->DBFieldName();
1768  $this->DB->Query("UPDATE Resources SET "
1769  .$DBFieldName."Qualifier = '".$QualifierId."' "
1770  ."WHERE ResourceId = ".$this->Id);
1771 
1772  # update local qualifier value
1773  $this->ValueCache[$DBFieldName."Qualifier"] = $QualifierId;
1774  }
1775  }
1776 
1783  public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1784  {
1785  $Field = $this->Schema()->GetField($FieldId);
1786  $this->Clear($Field, $ValueToClear);
1787  }
1788 
1795  public function Clear($Field, $ValueToClear = NULL)
1796  {
1797  # convert field name to object if necessary
1798  if (!is_object($Field))
1799  {
1800  $Field = $this->Schema()->GetFieldByName($Field);
1801  }
1802 
1803  # grab commonly-used values for local use
1804  $DB = $this->DB;
1805  $ResourceId = $this->Id;
1806 
1807  # grab database field name
1808  $DBFieldName = $Field->DBFieldName();
1809 
1810  $UpdateModTime=FALSE;
1811 
1812  # store value in DB based on field type
1813  switch ($Field->Type())
1814  {
1821  if (strlen($this->ValueCache[$DBFieldName])>0)
1822  {
1823  # clear value in DB
1824  $DB->Query("UPDATE Resources SET `"
1825  .$DBFieldName."` = NULL "
1826  ."WHERE ResourceId = ".$ResourceId);
1827 
1828  # clear value locally
1829  $this->ValueCache[$DBFieldName] = NULL;
1830  $UpdateModTime=TRUE;
1831  }
1832  break;
1833 
1835  if (!is_null($this->ValueCache[$DBFieldName."X"]) ||
1836  !is_null($this->ValueCache[$DBFieldName."Y"]) )
1837  {
1838  # Clear DB Values
1839  $DB->Query("UPDATE Resources SET "
1840  ."`".$DBFieldName."X` = NULL ,"
1841  ."`".$DBFieldName."Y` = NULL "
1842  ."WHERE ResourceId = ".$ResourceId);
1843 
1844  # Clear local values
1845  $this->ValueCache[$DBFieldName."X"] = NULL;
1846  $this->ValueCache[$DBFieldName."Y"] = NULL;
1847  $UpdateModTime=TRUE;
1848  }
1849  break;
1850 
1852  if (!is_null($this->ValueCache[$DBFieldName."Begin"]) ||
1853  !is_null($this->ValueCache[$DBFieldName."End"]) ||
1854  !is_null($this->ValueCache[$DBFieldName."Precision"]))
1855  {
1856  # clear date object values in DB
1857  $DB->Query("UPDATE Resources SET "
1858  .$DBFieldName."Begin = '', "
1859  .$DBFieldName."End = '', "
1860  .$DBFieldName."Precision = '' "
1861  ."WHERE ResourceId = ".$ResourceId);
1862 
1863  # clear value locally
1864  $this->ValueCache[$DBFieldName."Begin"] = NULL;
1865  $this->ValueCache[$DBFieldName."End"] = NULL;
1866  $this->ValueCache[$DBFieldName."Precision"] = NULL;
1867  $UpdateModTime=TRUE;
1868  }
1869  break;
1870 
1872  $OldValue = $this->Get($Field);
1873 
1874  # if value to clear supplied
1875  if ($ValueToClear !== NULL)
1876  {
1877  # if supplied value is array
1878  if (is_array($ValueToClear))
1879  {
1880  # for each element of array
1881  foreach ($ValueToClear as $ClassificationId => $Dummy)
1882  {
1883  if (array_key_exists($ClassificationId, $OldValue))
1884  {
1885  # remove association with resource (if any)
1886  $this->RemoveAssociation("ResourceClassInts",
1887  "ClassificationId",
1888  $ClassificationId);
1889  $Class = new Classification($ClassificationId);
1890  $Class->RecalcResourceCount();
1891  $UpdateModTime=TRUE;
1892  }
1893  }
1894  }
1895  else
1896  {
1897  if (array_key_exists($ValueToClear, $OldValue))
1898  {
1899  # remove association with resource (if any)
1900  $this->RemoveAssociation("ResourceClassInts",
1901  "ClassificationId",
1902  $ValueToClear);
1903  $Class = new Classification($ValueToClear);
1904  $Class->RecalcResourceCount();
1905  $UpdateModTime=TRUE;
1906  }
1907  }
1908  }
1909  else
1910  {
1911  if (count($OldValue)>0)
1912  {
1913  # remove all associations for resource and field
1914  $this->RemoveAllAssociations(
1915  "ResourceClassInts", "ClassificationId", $Field);
1916 
1917  # recompute resource count
1918  $Values = $this->Get($Field);
1919  foreach ($Values as $ClassificationId => $Dummy)
1920  {
1921  $Class = new Classification($ClassificationId);
1922  $Class->RecalcResourceCount();
1923  }
1924  $UpdateModTime=TRUE;
1925  }
1926  }
1927 
1928  # clear our classification cache
1929  if ($UpdateModTime)
1930  {
1931  unset($this->ClassificationCache);
1932  }
1933  break;
1934 
1937  $OldValue = $this->Get($Field);
1938  # if value to clear supplied
1939  if ($ValueToClear !== NULL)
1940  {
1941  # if incoming value is array
1942  if (is_array($ValueToClear))
1943  {
1944  # for each element of array
1945  foreach ($ValueToClear as $ControlledNameId =>
1946  $ControlledName)
1947  {
1948  if (array_key_exists($ControlledNameId, $OldValue))
1949  {
1950  # remove association with resource (if any)
1951  $this->RemoveAssociation("ResourceNameInts",
1952  "ControlledNameId",
1953  $ControlledNameId);
1954  $UpdateModTime=TRUE;
1955  }
1956  }
1957  }
1958  else
1959  {
1960  if (array_key_exists($ValueToClear, $OldValue))
1961  {
1962  # remove association with resource (if any)
1963  $this->RemoveAssociation("ResourceNameInts",
1964  "ControlledNameId",
1965  $ValueToClear);
1966  $UpdateModTime=TRUE;
1967  }
1968  }
1969  }
1970  else
1971  {
1972  if (count($OldValue)>0)
1973  {
1974  # remove all associations for resource and field
1975  $this->RemoveAllAssociations(
1976  "ResourceNameInts", "ControlledNameId", $Field);
1977  $UpdateModTime=TRUE;
1978  }
1979  }
1980 
1981  if ($UpdateModTime)
1982  {
1983  # clear our controlled name cache
1984  unset($this->ControlledNameCache);
1985  unset($this->ControlledNameVariantCache);
1986  }
1987  break;
1988 
1990  $OldValue = $this->Get($Field);
1991 
1992  # if value to clear supplied
1993  if ($ValueToClear !== NULL)
1994  {
1995  # if incoming value is array
1996  if (is_array($ValueToClear))
1997  {
1998  # for each element of array
1999  foreach ($ValueToClear as $UserId => $User)
2000  {
2001  if (array_key_exists($UserId, $OldValue))
2002  {
2003  # remove association with resource (if any)
2004  $this->RemoveAssociation("ResourceUserInts",
2005  "UserId",
2006  $UserId,
2007  $Field);
2008  $UpdateModTime=TRUE;
2009  }
2010  }
2011  }
2012  else
2013  {
2014  if (array_key_exists($ValueToClear, $OldValue))
2015  {
2016  # remove association with resource (if any)
2017  $this->RemoveAssociation("ResourceUserInts",
2018  "UserId",
2019  $UserId,
2020  $Field);
2021  $UpdateModTime=TRUE;
2022  }
2023  }
2024  }
2025  else
2026  {
2027  if (count($OldValue)>0)
2028  {
2029  # remove all associations for resource and field
2030  $this->RemoveAllAssociations(
2031  "ResourceUserInts", "UserId", $Field);
2032  $UpdateModTime=TRUE;
2033  }
2034  }
2035 
2036  break;
2037 
2039  # if value to clear supplied
2040  if ($ValueToClear !== NULL)
2041  {
2042  # convert value to array if necessary
2043  $Files = $ValueToClear;
2044  if (!is_array($Files)) { $Files = array($Files); }
2045 
2046  # convert values to objects if necessary
2047  foreach ($Files as $Index => $File)
2048  {
2049  if (!is_object($File))
2050  {
2051  $Files[$Index] = new File($File);
2052  }
2053  }
2054  }
2055  else
2056  {
2057  # use all files associated with resource
2058  $Files = $this->Get($Field, TRUE);
2059  }
2060 
2061  # delete files
2062  foreach ($Files as $File) { $File->Delete(); }
2063  break;
2064 
2066  # if value to clear supplied
2067  if ($ValueToClear !== NULL)
2068  {
2069  # convert value to array if necessary
2070  $Images = $ValueToClear;
2071  if (!is_array($Images)) { $Images = array($Images); }
2072 
2073  # convert values to objects if necessary
2074  foreach ($Images as $Index => $Image)
2075  {
2076  if (!is_object($Image))
2077  {
2078  $Images[$Index] = new SPTImage($Image);
2079  }
2080  }
2081  }
2082  else
2083  {
2084  # use all images associated with resource
2085  $Images = $this->Get($Field, TRUE);
2086  }
2087 
2088  # delete images if we are the last resource referencing
2089  # a particular image.
2090  foreach ($Images as $Image)
2091  {
2092  $Cnt = $this->DB->Query(
2093  "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
2094  "ImageId=".$Image->Id(), "Cnt");
2095  if ($Cnt==1)
2096  {
2097  $Image->Delete();
2098  }
2099  }
2100 
2101  # clear cached image mappings
2102  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
2103 
2104  # remove connections to images
2105  $UpdateModTime = $this->RemoveAssociation(
2106  "ResourceImageInts", "ImageId", $Images, $Field);
2107  break;
2108 
2110  # remove references from the references table
2111  $DB->Query("
2112  DELETE FROM ReferenceInts
2113  WHERE FieldId = '".addslashes($Field->Id())."'
2114  AND SrcResourceId = '".addslashes($this->Id())."'");
2115  break;
2116 
2117  default:
2118  # ERROR OUT
2119  exit("<br>SPT - ERROR: attempt to clear "
2120  ."unknown resource field type<br>\n");
2121  break;
2122  }
2123 
2124  if ($UpdateModTime && !$this->IsTempResource())
2125  {
2126  # update modification timestamps
2127  global $G_User;
2128  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
2129  $DB->Query("DELETE FROM ResourceFieldTimestamps "
2130  ."WHERE ResourceId=".$this->Id." AND "
2131  ."FieldId=".$Field->Id() );
2132  $DB->Query("INSERT INTO ResourceFieldTimestamps "
2133  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
2134  .$this->Id.",".$Field->Id().","
2135  .$UserId.",NOW())");
2136  }
2137  }
2138 
2147  public function ClearByField($Field, $ValueToClear = NULL)
2148  {
2149  $this->Clear($Field, $ValueToClear);
2150  }
2151 
2152  # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
2153 
2159  public function Classifications()
2160  {
2161  $DB = $this->DB;
2162 
2163  # start with empty array
2164  $Names = array();
2165 
2166  # for each controlled name
2167  $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2168  ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2169  ."Classifications, MetadataFields "
2170  ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2171  ."AND ResourceClassInts.ClassificationId = "
2172  ."Classifications.ClassificationId "
2173  ."AND Classifications.FieldId = MetadataFields.FieldId ");
2174  while ($Record = $DB->FetchRow())
2175  {
2176  # add name to array
2177  $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2178  $Record["ClassificationName"];
2179  }
2180 
2181  # return array to caller
2182  return $Names;
2183  }
2184 
2185 
2186  # --- Ratings Methods ---------------------------------------------------
2187 
2192  public function CumulativeRating()
2193  {
2194  return $this->CumulativeRating;
2195  }
2196 
2201  public function ScaledCumulativeRating()
2202  {
2203  if ($this->CumulativeRating == NULL)
2204  {
2205  return NULL;
2206  }
2207  else
2208  {
2209  return intval(($this->CumulativeRating + 5) / 10);
2210  }
2211  }
2212 
2217  public function NumberOfRatings()
2218  {
2219  # if number of ratings not already set
2220  if (!isset($this->NumberOfRatings))
2221  {
2222  # obtain number of ratings
2223  $this->NumberOfRatings =
2224  $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
2225  ."FROM ResourceRatings "
2226  ."WHERE ResourceId = ".$this->Id,
2227  "NumberOfRatings"
2228  );
2229 
2230  # recalculate cumulative rating if it looks erroneous
2231  if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
2232  {
2233  $this->UpdateCumulativeRating();
2234  }
2235  }
2236 
2237  # return number of ratings to caller
2238  return $this->NumberOfRatings;
2239  }
2240 
2248  public function Rating($NewRating = NULL, $UserId = NULL)
2249  {
2250  $DB = $this->DB;
2251 
2252  # if user ID not supplied
2253  if ($UserId == NULL)
2254  {
2255  # if user is logged in
2256  global $User;
2257  if ($User->IsLoggedIn())
2258  {
2259  # use ID of current user
2260  $UserId = $User->Get("UserId");
2261  }
2262  else
2263  {
2264  # return NULL to caller
2265  return NULL;
2266  }
2267  }
2268 
2269  # sanitize $NewRating
2270  if (!is_null($NewRating))
2271  {
2272  $NewRating = intval($NewRating);
2273  }
2274 
2275  # if there is a rating for resource and user
2276  $DB->Query("SELECT Rating FROM ResourceRatings "
2277  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2278  if ($Record = $DB->FetchRow())
2279  {
2280  # if new rating was supplied
2281  if ($NewRating != NULL)
2282  {
2283  # update existing rating
2284  $DB->Query("UPDATE ResourceRatings "
2285  ."SET Rating = ${NewRating}, DateRated = NOW() "
2286  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2287 
2288  # update cumulative rating value
2289  $this->UpdateCumulativeRating();
2290 
2291  # return value is new rating
2292  $Rating = $NewRating;
2293  }
2294  else
2295  {
2296  # get rating value to return to caller
2297  $Rating = $Record["Rating"];
2298  }
2299  }
2300  else
2301  {
2302  # if new rating was supplied
2303  if ($NewRating != NULL)
2304  {
2305  # add new rating
2306  $DB->Query("INSERT INTO ResourceRatings "
2307  ."(ResourceId, UserId, DateRated, Rating) "
2308  ."VALUES ("
2309  .$this->Id.", "
2310  ."${UserId}, "
2311  ."NOW(), "
2312  ."${NewRating})");
2313 
2314  # update cumulative rating value
2315  $this->UpdateCumulativeRating();
2316 
2317  # return value is new rating
2318  $Rating = $NewRating;
2319  }
2320  else
2321  {
2322  # return value is NULL
2323  $Rating = NULL;
2324  }
2325  }
2326 
2327  # return rating value to caller
2328  return $Rating;
2329  }
2330 
2331 
2332  # --- Resource Comment Methods ------------------------------------------
2333 
2338  public function Comments()
2339  {
2340  # read in comments if not already loaded
2341  if (!isset($this->Comments))
2342  {
2343  $this->DB->Query("SELECT MessageId FROM Messages "
2344  ."WHERE ParentId = ".$this->Id
2345  ." AND ParentType = 2 "
2346  ."ORDER BY DatePosted DESC");
2347  while ($MessageId = $this->DB->FetchField("MessageId"))
2348  {
2349  $this->Comments[] = new Message($MessageId);
2350  }
2351  }
2352 
2353  # return array of comments to caller
2354  return $this->Comments;
2355  }
2356 
2361  public function NumberOfComments()
2362  {
2363  # obtain number of comments if not already set
2364  if (!isset($this->NumberOfComments))
2365  {
2366  $this->NumberOfComments =
2367  $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2368  ."FROM Messages "
2369  ."WHERE ParentId = ".$this->Id
2370  ." AND ParentType = 2",
2371  "NumberOfComments"
2372  );
2373  }
2374 
2375  # return number of comments to caller
2376  return $this->NumberOfComments;
2377  }
2378 
2379 
2380  # --- Permission Methods -------------------------------------------------
2381 
2391  public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2392  {
2393  return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2394  }
2395 
2402  public function UserCanEdit($User)
2403  {
2404  return $this->CheckSchemaPermissions($User, "Edit");
2405  }
2406 
2413  public function UserCanAuthor($User)
2414  {
2415  return $this->CheckSchemaPermissions($User, "Author");
2416  }
2417 
2424  public function UserCanModify($User)
2425  {
2426  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2427  return $this->$CheckFn($User);
2428  }
2429 
2436  public function UserCanViewField($User, $FieldOrFieldName)
2437  {
2438  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "View" );
2439  }
2440 
2447  public function UserCanEditField($User, $FieldOrFieldName)
2448  {
2449  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Edit" );
2450  }
2451 
2458  public function UserCanAuthorField($User, $FieldOrFieldName)
2459  {
2460  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2461  }
2462 
2470  public function UserCanModifyField($User, $FieldOrFieldName)
2471  {
2472  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2473 
2474  return $this->$CheckFn($User, $FieldOrFieldName);
2475  }
2476 
2477  # --- Utility Methods ----------------------------------------------------
2478 
2483  {
2484  if (!$this->IsTempResource())
2485  {
2486  $SearchEngine = new SPTSearchEngine();
2487  $SearchEngine->QueueUpdateForItem($this);
2488 
2489  $Recommender = new SPTRecommender();
2490  $Recommender->QueueUpdateForItem($this);
2491  }
2492  }
2493 
2499  public static function GetSchemaForResource($ResourceId)
2500  {
2501  # if schema IDs are not loaded
2502  if (!isset(self::$SchemaIdCache))
2503  {
2504  # load schema IDs
2505  $DB = new Database();
2506  $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2507  self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2508  }
2509 
2510  # if multiple resources specified
2511  if (is_array($ResourceId))
2512  {
2513  # find schema IDs for specified resources
2514  $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2515  array_flip($ResourceId));
2516 
2517  # check that specified resource IDs were all valid
2518  if (count($SchemaIds) < count($ResourceId))
2519  {
2520  $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2521  throw new InvalidArgumentException("Unknown resource IDs ("
2522  .implode(", ", $BadIds).").");
2523  }
2524 
2525  # return schema IDs to caller
2526  return $SchemaIds;
2527  }
2528  else
2529  {
2530  # check that specified resource was valid
2531  if (!isset(self::$SchemaIdCache[$ResourceId]))
2532  {
2533  throw new InvalidArgumentException("Unknown resource ID ("
2534  .$ResourceId.").");
2535  }
2536 
2537  # return schema IDs for specified resource
2538  return self::$SchemaIdCache[$ResourceId];
2539  }
2540  }
2541 
2542 
2543  # ---- PRIVATE INTERFACE -------------------------------------------------
2544 
2545  private $ClassificationCache;
2546  private $Comments;
2547  private $ControlledNameCache;
2548  private $ControlledNameVariantCache;
2549  private $CumulativeRating;
2550  private $NumberOfComments;
2551  private $NumberOfRatings;
2552  private $PermissionCache;
2553  private $SchemaId;
2554 
2555  static private $Schemas;
2556  static private $SchemaIdCache;
2557 
2568  private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2569  {
2570  # construct a key to use for our permissions cache
2571  $CacheKey = "UserCan".$CheckType.$User->Id();
2572 
2573  # if we don't have a cached value for this perm, compute one
2574  if (!isset($this->PermissionCache[$CacheKey]))
2575  {
2576  # get privileges for schema
2577  $PermsFn = $CheckType."ingPrivileges";
2578  $SchemaPrivs = $this->Schema()->$PermsFn();
2579 
2580  # check passes if user privileges are greater than resource set
2581  $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2582 
2583  # save the result of this check in our cache
2584  $this->PermissionCache[$CacheKey] = $CheckResult;
2585  }
2586 
2587  $Value = $this->PermissionCache[$CacheKey];
2588 
2589  if ($AllowHooksToModify)
2590  {
2591  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2592  "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2593  array(
2594  "Resource" => $this,
2595  "User" => $User,
2596  "Can".$CheckType => $Value,
2597  "Schema" => $this->Schema(), ));
2598 
2599  $Value = $SignalResult["Can".$CheckType];
2600  }
2601 
2602  return $Value;
2603  }
2604 
2613  private function CheckFieldPermissions($User, $Field, $CheckType)
2614  {
2615  # get field object (if not supplied)
2616  if (!($Field instanceof MetadataField))
2617  {
2618  try
2619  {
2620  $Field = $this->Schema()->GetField($Field);
2621  }
2622  catch (InvalidArgumentException $Exception)
2623  {
2624  # (user cannot view/author/edit if field was invalid)
2625  return FALSE;
2626  }
2627  }
2628 
2629  # construct a key to use for our permissions cache
2630  $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2631 
2632  # if we don't have a cahced value, compute one
2633  if (!isset($this->PermissionCache[$CacheKey]))
2634  {
2635  # if field is enabled and editable, do permission check
2636  if ($Field->Enabled() &&
2637  ($CheckType == "View" || $Field->Editable()))
2638  {
2639  # be sure schema privs allow View/Edit/Author for this resource
2640  $SchemaCheckFn = "UserCan".$CheckType;
2641  if ($this->$SchemaCheckFn($User))
2642  {
2643  # get appropriate privilege set for field
2644  $PermsFn = $CheckType."ingPrivileges";
2645  $FieldPrivs = $Field->$PermsFn();
2646 
2647  # user can View/Edit/Author if privileges are greater than field set
2648  $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2649  }
2650  else
2651  {
2652  $CheckResult = FALSE;
2653  }
2654  }
2655  else
2656  {
2657  $CheckResult = FALSE;
2658  }
2659 
2660  # allow plugins to modify result of permission check
2661  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2662  "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2663  "Field" => $Field,
2664  "Resource" => $this,
2665  "User" => $User,
2666  "Can".$CheckType => $CheckResult));
2667  $CheckResult = $SignalResult["Can".$CheckType];
2668 
2669  # save the result of this check in our cache
2670  $this->PermissionCache[$CacheKey] = $CheckResult;
2671  }
2672 
2673  # return cached permission value
2674  return $this->PermissionCache[$CacheKey];
2675  }
2676 
2680  private function UpdateCumulativeRating()
2681  {
2682  # grab totals from DB
2683  $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2684  ."SUM(Rating) AS Total FROM ResourceRatings "
2685  ."WHERE ResourceId = ".$this->Id);
2686  $Record = $this->DB->FetchRow();
2687 
2688  # calculate new cumulative rating
2689  $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
2690 
2691  # save new cumulative rating in DB
2692  $this->DB->Query("UPDATE Resources "
2693  ."SET CumulativeRating = ".$this->CumulativeRating." "
2694  ."WHERE ResourceId = ".$this->Id);
2695  }
2696 
2708  private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2709  {
2710  # We should ignore duplicate key errors when doing inserts:
2711  $this->DB->SetQueryErrorsToIgnore( array(
2712  "/INSERT INTO ".$TableName."/" =>
2713  "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2714 
2715  # start out assuming no association will be added
2716  $AssociationAdded = FALSE;
2717 
2718  # convert new value to array if necessary
2719  $Values = is_array($Value) ? $Value : array($Value);
2720 
2721  # for each new value
2722  foreach ($Values as $Value)
2723  {
2724  # retrieve ID from value if necessary
2725  if (is_object($Value)) { $Value = $Value->Id(); }
2726 
2727  # Try to insert a new entry for this association.
2728  $this->DB->Query("INSERT INTO ".$TableName." SET"
2729  ." ResourceId = ".intval($this->Id)
2730  .", ".$FieldName." = ".intval($Value)
2731  .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2732 
2733  # If the insert ran without a duplicate key error,
2734  # then we added an assocation:
2735  if ($this->DB->IgnoredError() === FALSE)
2736  {
2737  $AssociationAdded = TRUE;
2738  }
2739  }
2740 
2741  # Clear ignored errors:
2742  $this->DB->SetQueryErrorsToIgnore( NULL );
2743 
2744  # report to caller whether association was added
2745  return $AssociationAdded;
2746  }
2747 
2759  private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2760  {
2761  # start out assuming no association will be removed
2762  $AssociationRemoved = FALSE;
2763 
2764  # convert value to array if necessary
2765  $Values = is_array($Value) ? $Value : array($Value);
2766 
2767  # for each value
2768  foreach ($Values as $Value)
2769  {
2770  # retrieve ID from value if necessary
2771  if (is_object($Value)) { $Value = $Value->Id(); }
2772 
2773  # remove any intersections with target ID from DB
2774  $this->DB->Query("DELETE FROM ".$TableName
2775  ." WHERE ResourceId = ".intval($this->Id)
2776  .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2777  ." AND ".$FieldName." = ".intval($Value));
2778  if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2779  }
2780 
2781  # report to caller whether association was added
2782  return $AssociationRemoved;
2783  }
2784 
2791  private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
2792  {
2793  # retrieve list of entries for this field and resource
2794  $Entries = $this->Get($Field);
2795 
2796  # divide them into chunks of not more than 100
2797  foreach (array_chunk($Entries, 100, TRUE) as $Chunk)
2798  {
2799  # remove assocations from this chunk
2800  $this->DB->Query("DELETE FROM ".$TableName
2801  ." WHERE ResourceId = ".intval($this->Id)
2802  ." AND ".$TargetFieldName." IN "
2803  ."(".implode(",", array_keys($Chunk)).")");
2804  }
2805  }
2806 
2813  static protected function SetDatabaseAccessValues($ClassName)
2814  {
2815  if (!isset(self::$ItemIdColumnNames[$ClassName]))
2816  {
2817  self::$ItemIdColumnNames[$ClassName] = "ResourceId";
2818  self::$ItemNameColumnNames[$ClassName] = NULL;
2819  self::$ItemTableNames[$ClassName] = "Resources";
2820  }
2821  }
2822 }
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:2391
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:1107
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1727
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:2470
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2482
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:811
Id()
Retrieve numerical resource ID.
Definition: Resource.php:287
$DB
Definition: Item.php:115
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2447
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1749
GetViewPageUrl()
Retrieve view page URL for this resource.
Definition: Resource.php:386
Rating($NewRating=NULL, $UserId=NULL)
Get/set rating by a specific user for resource.
Definition: Resource.php:2248
Definition: User.php:41
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2361
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2217
GetQualifier($FieldName, $ReturnObject=TRUE)
Retrieve qualifier by field name.
Definition: Resource.php:875
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:305
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:2402
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:2338
UpdateAutoupdateFields($UpdateType, $User=NULL)
Update the auto-updated fields as necessary.
Definition: Resource.php:255
CWIS-specific user factory class.
Get($Field, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field name or field object.
Definition: Resource.php:410
static GetSchemaForResource($ResourceId)
Get schema ID for specified resource(s).
Definition: Resource.php:2499
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:889
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:2458
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1795
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2424
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2413
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:316
SetByField($Field, $NewValue)
Method replaced by Resource::Set(), preserved for backward compatibility.
Definition: Resource.php:1705
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:24
GetMapped($MappedName, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using standard (mapped) field name.
Definition: Resource.php:857
$Id
Definition: Item.php:116
static SetDatabaseAccessValues($ClassName)
Set the database access values (table name, ID column name, name column name) for specified class...
Definition: Resource.php:2813
Represents a "resource" in CWIS.
Definition: Resource.php:13
GetQualifierByField($Field, $ReturnObject=TRUE)
Retrieve qualifier by Field object.
Definition: Resource.php:903
ClearByFieldId($FieldId, $ValueToClear=NULL)
Clear field value specified by field ID.
Definition: Resource.php:1783
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1738
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:296
ScaledCumulativeRating()
Return cumulative rating scaled to 1/10th.
Definition: Resource.php:2201
Set($Field, $NewValue, $Reset=FALSE)
Set value using field name or field object.
Definition: Resource.php:1142
const UPDATEMETHOD_ONRECORDCREATE
static Create($SchemaId)
Create a new resource.
Definition: Resource.php:47
UserCanViewField($User, $FieldOrFieldName)
Check whether user is allowed to view specified metadata field.
Definition: Resource.php:2436
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1717
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:2159
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:2147
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:2192
FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
Determine if the value for a field is set.
Definition: Resource.php:1037
Delete()
Remove resource (and accompanying associations) from database and delete any associated files...
Definition: Resource.php:138