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-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
13 class Resource
14 {
15 
16  # ---- PUBLIC INTERFACE --------------------------------------------------
17 
24  public function __construct($ResourceId)
25  {
26  $this->DB = new Database();
27 
28  # save resource ID
29  $this->Id = intval($ResourceId);
30 
31  # locate resource in database
32  $this->DB->Query("SELECT * FROM Resources WHERE ResourceId = ".$this->Id);
33 
34  # if unable to locate resource
35  $Record = $this->DB->FetchRow();
36  if ($Record == FALSE)
37  {
38  # set status to -1 to indicate that creation failed
39  $this->LastStatus = -1;
40  }
41  else
42  {
43  # load in attributes from database
44  $this->DBFields = $Record;
45  $this->CumulativeRating = $Record["CumulativeRating"];
46 
47  # load our local metadata schema
48  $this->SchemaId = $this->DBFields["SchemaId"];
49  if (!isset(self::$Schemas[$this->SchemaId]))
50  {
51  self::$Schemas[$this->SchemaId] =
52  new MetadataSchema($this->SchemaId);
53  }
54 
55  # set status to 1 to indicate that creation succeeded
56  $this->LastStatus = 1;
57  }
58  }
59 
66  public static function Create($SchemaId)
67  {
68  # clean out any temp resource records more than three days old
69  $RFactory = new ResourceFactory();
70  $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
71 
72  # lock DB tables to prevent next ID from being grabbed
73  $DB = new Database;
74  $DB->Query("LOCK TABLES Resources WRITE");
75 
76  # find next temp resource ID
77  $Id = $RFactory->GetNextTempItemId();
78 
79  # write out new resource record with temp resource ID
80  # Set DateLastModified = NOW() to avoid being pruned as a
81  # stale temp resource.
82  $DB->Query(
83  "INSERT INTO Resources
84  SET `ResourceId` = '".intval($Id)."',
85  `SchemaId` = '".intval($SchemaId)."',
86  `DateLastModified` = NOW() " );
87 
88  # release DB tables
89  $DB->Query("UNLOCK TABLES");
90 
91  # create new Resource object
92  $Resource = new Resource($Id);
93 
94  if ($Resource->Status() == -1)
95  {
96  throw new Exception("Resource creation failed");
97  }
98 
99  # set some additional fields for default resources
100  if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
101  {
102  $Resource->Set("Added By Id", $GLOBALS["G_User"]->Id());
103  $Resource->Set("Last Modified By Id", $GLOBALS["G_User"]->Id());
104  $Resource->Set("Date Of Record Creation", date("Y-m-d H:i:s"));
105  $Resource->Set("Date Last Modified", date("Y-m-d H:i:s"));
106  }
107 
108  # for each field that can have a default value
109  $Schema = new MetadataSchema($SchemaId);
110  $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
115  foreach ($Fields as $Field)
116  {
117  # if there is a default value available
118  $DefaultValue = $Field->DefaultValue();
119  if ($DefaultValue !== NULL)
120  {
121  # if the default value is an array
122  if (is_array($DefaultValue))
123  {
124  # if there are values in the array
125  if (!empty($DefaultValue))
126  {
127  # flip values for Set() if necessary
128  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
129  {
130  $DefaultValue = array_flip($DefaultValue);
131  }
132 
133  # set default value
134  $Resource->Set($Field, $DefaultValue);
135  }
136  }
137  else
138  {
139  # set default value
140  $Resource->Set($Field, $DefaultValue);
141  }
142  }
143  }
144 
145  # update timestamps as required
146  $TimestampFields = $Schema->GetFields(MetadataSchema::MDFTYPE_TIMESTAMP);
147  foreach ($TimestampFields as $Field)
148  {
149  if ($Field->UpdateMethod() ==
151  {
152  $Resource->SetByField($Field, "now");
153  }
154  }
155 
156  # signal resource creation
157  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
158  "Resource" => $Resource,
159  ));
160 
161  # return new Resource object to caller
162  return $Resource;
163  }
164 
169  public function Delete()
170  {
171  global $SysConfig;
172 
173  # signal that resource deletion is about to occur
174  global $AF;
175  $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
176  "Resource" => $this,
177  ));
178 
179  # grab list of classifications
180  $Classifications = $this->Classifications();
181 
182  # delete resource/classification intersections
183  $DB = $this->DB;
184  $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
185 
186  # for each classification type
187  foreach ($Classifications as $ClassType => $ClassesOfType)
188  {
189  # for each classification of that type
190  foreach ($ClassesOfType as $ClassId => $ClassName)
191  {
192  # recalculate resource count for classification
193  $Class = new Classification($ClassId);
194  $Class->RecalcResourceCount();
195  }
196  }
197 
198  # delete resource references
199  $DB->Query("
200  DELETE FROM ReferenceInts
201  WHERE SrcResourceId = '".addslashes($this->Id())."'
202  OR DstResourceId = '".addslashes($this->Id())."'");
203 
204  # delete resource/name intersections
205  $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
206 
207  # delete resource/user intersections
208  $DB->Query("DELETE FROM ResourceUserInts WHERE ResourceId = ".$this->Id());
209 
210  # get the list of all images associated with this resource
211  $DB->Query("SELECT ImageId FROM ResourceImageInts"
212  ." WHERE ResourceId = ".intval($this->Id()));
213  $ImageIds = $DB->FetchColumn("ImageId");
214 
215  # disassociate this resource from all images
216  $DB->Query("DELETE FROM ResourceImageInts"
217  ." WHERE ResourceId = ".intval($this->Id()));
218 
219  # delete any images that no longer belong to any resources
220  foreach ($ImageIds as $ImageId)
221  {
222  $DB->Query("SELECT ResourceId FROM ResourceImageInts"
223  ." WHERE ImageId = ".intval($ImageId) );
224  if ($DB->NumRowsSelected() == 0)
225  {
226  $Image = new SPTImage($ImageId);
227  $Image->Delete();
228  }
229  }
230 
231  # delete any associated files
232  $Factory = new FileFactory(NULL);
233  $Files = $Factory->GetFilesForResource($this->Id());
234  foreach ($Files as $File)
235  {
236  $File->Delete();
237  }
238 
239  # delete resource record from database
240  $DB->Query("DELETE FROM Resources WHERE ResourceId = ".$this->Id());
241 
242  # drop item from search engine and recommender system
243  if ($SysConfig->SearchDBEnabled())
244  {
245  $SearchEngine = new SPTSearchEngine();
246  $SearchEngine->DropItem($this->Id());
247  }
248  if ($SysConfig->RecommenderDBEnabled())
249  {
250  $Recommender = new SPTRecommender();
251  $Recommender->DropItem($this->Id());
252  }
253 
254  # get the folders containing the resource
255  $FolderFactory = new FolderFactory();
256  $Folders = $FolderFactory->GetFoldersContainingItem(
257  $this->Id,
258  "Resource");
259 
260  # drop the resource from each folder it belongs to
261  foreach ($Folders as $Folder)
262  {
263  # mixed item type folder
264  if ($Folder->ContainsItem($this->Id, "Resource"))
265  {
266  $Folder->RemoveItem($this->Id, "Resource");
267  }
268 
269  # single item type folder
270  else
271  {
272  $Folder->RemoveItem($this->Id);
273  }
274  }
275 
276  # delete any resource comments
277  $DB->Query("DELETE FROM Messages WHERE ParentId = ".$this->Id);
278  }
279 
284  public function Status()
285  {
286  return $this->LastStatus;
287  }
288 
293  public function Id()
294  {
295  return $this->Id;
296  }
297 
302  public function SchemaId()
303  {
304  return $this->SchemaId;
305  }
306 
311  public function Schema()
312  {
313  return self::$Schemas[$this->SchemaId];
314  }
315 
322  public function IsTempResource($NewSetting = NULL)
323  {
324  # if new temp resource setting supplied
325  if (!is_null($NewSetting))
326  {
327  # if caller requested to switch
328  $DB = $this->DB;
329  if ((($this->Id() < 0) && ($NewSetting == FALSE))
330  || (($this->Id() >= 0) && ($NewSetting == TRUE)))
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  $Factory = new ResourceFactory($this->SchemaId);
338  if ($NewSetting == TRUE)
339  {
340  $this->Id = $Factory->GetNextTempItemId();
341  }
342  else
343  {
344  $this->Id = $Factory->GetNextItemId();
345  }
346 
347  # change resource ID
348  $DB->Query("UPDATE Resources SET ResourceId = ".
349  $this->Id. " WHERE ResourceId = ".$OldResourceId);
350 
351  # release DB tables
352  $DB->Query("UNLOCK TABLES");
353 
354  # change associations
355  unset($this->ClassificationCache);
356  $DB->Query("UPDATE ResourceClassInts SET ResourceId = ".
357  $this->Id. " WHERE ResourceId = ".$OldResourceId);
358  unset($this->ControlledNameCache);
359  unset($this->ControlledNameVariantCache);
360  $DB->Query("UPDATE ResourceNameInts SET ResourceId = ".
361  $this->Id. " WHERE ResourceId = ".$OldResourceId);
362  $DB->Query("UPDATE Files SET ResourceId = ".
363  $this->Id. " WHERE ResourceId = ".$OldResourceId);
364  $DB->Query("UPDATE ReferenceInts SET SrcResourceId = ".
365  $this->Id. " WHERE SrcResourceId = ".$OldResourceId);
366  $DB->Query("UPDATE ResourceImageInts SET ResourceId = ".
367  $this->Id. " WHERE ResourceId = ".$OldResourceId);
368  $DB->Query("UPDATE ResourceUserInts SET ResourceId = ".
369  $this->Id. " WHERE ResourceId = ".$OldResourceId);
370 
371  # signal event as appropriate
372  if ($NewSetting === FALSE)
373  {
374  $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_ADD", array(
375  "Resource" => $this,
376  ));
377  }
378  }
379  }
380 
381  # report to caller whether we are a temp resource
382  return ($this->Id() < 0) ? TRUE : FALSE;
383  }
384 
385 
386  # --- Generic Attribute Retrieval Methods -------------------------------
387 
392  public function GetViewPageUrl()
393  {
394  # put our Id into the ViewPage from our schema
395  $Url = str_replace(
396  "\$ID", $this->Id(),
397  $this->Schema()->ViewPage());
398 
399  # return clean url, if one is available
400  return $GLOBALS["AF"]->GetCleanUrlForPath($Url);
401  }
402 
416  public function Get($Field, $ReturnObject = FALSE, $IncludeVariants = FALSE)
417  {
418  # load field object if not already supplied
419  $Field = is_object($Field) ? $Field
420  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
421  : $this->Schema()->GetFieldByName($Field));
422 
423  # return no value found if we don't have a valid field
424  if (!($Field instanceof MetadataField)) { return NULL; }
425 
426  if ($Field->SchemaId() != $this->SchemaId())
427  {
428  throw new Exception("Attempt to get a value for a field"
429  ." from a different schema."
430  ." (Field: ".$Field->Name()." [".$Field->Id()
431  ."], Field Schema: ".$Field->SchemaId()
432  .", Resource Schema: ".$this->SchemaId()
433  .")");
434  }
435 
436  # grab database field name
437  $DBFieldName = $Field->DBFieldName();
438 
439  # format return value based on field type
440  switch ($Field->Type())
441  {
445  $ReturnValue = isset($this->DBFields[$DBFieldName])
446  ? (string)$this->DBFields[$DBFieldName] : NULL;
447  break;
448 
450  $ReturnValue = isset($this->DBFields[$DBFieldName])
451  ? (int)$this->DBFields[$DBFieldName] : NULL;
452  break;
453 
455  $ReturnValue = isset($this->DBFields[$DBFieldName])
456  ? (bool)$this->DBFields[$DBFieldName] : NULL;
457  break;
458 
460  $ReturnValue = array("X" => (float)$this->DBFields[$DBFieldName."X"],
461  "Y" => (float)$this->DBFields[$DBFieldName."Y"]);
462  break;
463 
465  $Date = new Date($this->DBFields[$DBFieldName."Begin"],
466  $this->DBFields[$DBFieldName."End"],
467  $this->DBFields[$DBFieldName."Precision"]);
468  if ($ReturnObject)
469  {
470  $ReturnValue = $Date;
471  }
472  else
473  {
474  $ReturnValue = $Date->Formatted();
475  }
476  break;
477 
479  $ReturnValue = $this->DBFields[$DBFieldName];
480  break;
481 
483  # start with empty array
484  $ReturnValue = array();
485 
486  # if classification cache has not been loaded
487  if (!isset($this->ClassificationCache))
488  {
489  # load all classifications associated with this resource into cache
490  $this->ClassificationCache = array();
491  $this->DB->Query(
492  "SELECT Classifications.ClassificationId,"
493  ." Classifications.FieldId,ClassificationName"
494  ." FROM ResourceClassInts, Classifications"
495  ." WHERE ResourceClassInts.ResourceId = ".$this->Id
496  ." AND ResourceClassInts.ClassificationId"
497  ." = Classifications.ClassificationId");
498  while ($Record = $this->DB->FetchRow())
499  {
500  $ClassId = $Record["ClassificationId"];
501  $this->ClassificationCache[$ClassId]["Name"]
502  = $Record["ClassificationName"];
503  $this->ClassificationCache[$ClassId]["FieldId"]
504  = $Record["FieldId"];
505  }
506  }
507  # for each entry in classification cache
508  foreach ($this->ClassificationCache as
509  $ClassificationId => $ClassificationInfo)
510  {
511  # if classification ID matches field we are looking for
512  if ($ClassificationInfo["FieldId"] == $Field->Id())
513  {
514  # add field to result
515  if ($ReturnObject)
516  {
517  $ReturnValue[$ClassificationId] =
518  new Classification($ClassificationId);
519  }
520  else
521  {
522  $ReturnValue[$ClassificationId] = $ClassificationInfo["Name"];
523  }
524  }
525  }
526  break;
527 
530  # start with empty array
531  $ReturnValue = array();
532 
533  # if controlled name cache has not been loaded
534  if (!isset($this->ControlledNameCache))
535  {
536  # load all controlled names associated with this resource into cache
537  $this->ControlledNameCache = array();
538  $this->DB->Query(
539  "SELECT ControlledNames.ControlledNameId,"
540  ." ControlledNames.FieldId,ControlledName"
541  ." FROM ResourceNameInts, ControlledNames"
542  ." WHERE ResourceNameInts.ResourceId = ".$this->Id
543  ." AND ResourceNameInts.ControlledNameId"
544  ." = ControlledNames.ControlledNameId"
545  ." ORDER BY ControlledNames.ControlledName ASC");
546  while ($Record = $this->DB->FetchRow())
547  {
548  $CNameId = $Record["ControlledNameId"];
549  $this->ControlledNameCache[$CNameId]["Name"]
550  = $Record["ControlledName"];
551  $this->ControlledNameCache[$CNameId]["FieldId"]
552  = $Record["FieldId"];
553  }
554  }
555 
556  # if variant names requested and variant name cache has not been loaded
557  if ($IncludeVariants && !isset($this->ControlledNameVariantCache))
558  {
559  # load all controlled names associated with this resource into cache
560  $this->ControlledNameVariantCache = array();
561  $this->DB->Query("SELECT ControlledNames.ControlledNameId,"
562  ." ControlledNames.FieldId,"
563  ." ControlledName, VariantName"
564  ." FROM ResourceNameInts, ControlledNames, VariantNames"
565  ." WHERE ResourceNameInts.ResourceId = ".$this->Id
566  ." AND ResourceNameInts.ControlledNameId"
567  ." = ControlledNames.ControlledNameId"
568  ." AND VariantNames.ControlledNameId"
569  ." = ControlledNames.ControlledNameId");
570  while ($Record = $this->DB->FetchRow())
571  {
572  $this->ControlledNameVariantCache[$Record["ControlledNameId"]][]
573  = $Record["VariantName"];
574  }
575  }
576 
577  # for each entry in controlled name cache
578  foreach ($this->ControlledNameCache as
579  $CNameId => $ControlledNameInfo)
580  {
581  # if controlled name type matches field we are looking for
582  if ($ControlledNameInfo["FieldId"] == $Field->Id())
583  {
584  # if objects requested
585  if ($ReturnObject)
586  {
587  $ReturnValue[$CNameId] =
588  new ControlledName($CNameId);
589  }
590  else
591  {
592  # if variant names requested
593  if ($IncludeVariants)
594  {
595  # add field to result
596  $ReturnValue[] = $ControlledNameInfo["Name"];
597 
598  # add any variant names to result
599  if (isset($this->ControlledNameVariantCache[$CNameId]))
600  {
601  $ReturnValue = array_merge(
602  $ReturnValue,
603  $this->ControlledNameVariantCache[$CNameId]);
604  }
605  }
606  else
607  {
608  # add field with index to result
609  $ReturnValue[$CNameId] =
610  $ControlledNameInfo["Name"];
611  }
612  }
613  }
614  }
615  break;
616 
618  # start out assuming no associated users
619  $ReturnValue = array();
620 
621  # query the database to get the associated userids
622  $this->DB->Query(
623  "SELECT UserId FROM ResourceUserInts WHERE ".
624  "ResourceId=".intval($this->Id).
625  " AND FieldId=".intval($Field->Id()));
626  $UserIds = $this->DB->FetchColumn("UserId");
627 
628  # convert each userid to either a name or a CWUser object
629  foreach ($UserIds as $UserId)
630  {
631  $User = new CWUser(intval($UserId));
632  if ($ReturnObject)
633  {
634  $ReturnValue[$UserId] = $User;
635  }
636  else
637  {
638  $ReturnValue[$UserId] = $User->Get("UserName");
639  }
640  }
641  break;
642 
644  # start out assuming no images will be found
645  $ReturnValue = array();
646 
647  # find all images associated with this resource
648  $this->DB->Query("SELECT ImageId FROM ResourceImageInts"
649  ." WHERE ResourceId = ".intval($this->Id())
650  ." AND FieldId = ".intval($Field->Id()));
651 
652  # if images were found
653  if ($this->DB->NumRowsSelected())
654  {
655  # if we are to return an object
656  $ImageIds = $this->DB->FetchColumn("ImageId");
657  if ($ReturnObject)
658  {
659  # load array of Image objects for return value
660  foreach ($ImageIds as $ImageId)
661  {
662  $ReturnValue[$ImageId] = new SPTImage($ImageId);
663  }
664  }
665  else
666  {
667  # load array of Image ids for return value
668  $ReturnValue = $ImageIds;
669  }
670  }
671  break;
672 
674  # retrieve files using factory
675  $Factory = new FileFactory($Field->Id());
676  $ReturnValue = $Factory->GetFilesForResource(
677  $this->Id, $ReturnObject);
678  break;
679 
681  # query for resource references
682  $this->DB->Query("
683  SELECT * FROM ReferenceInts
684  WHERE FieldId = '".addslashes($Field->Id())."'
685  AND SrcResourceId = '".addslashes($this->Id())."'");
686 
687  $ReturnValue = array();
688 
689  # return each reference as a Resource object
690  if ($ReturnObject)
691  {
692  $FoundErrors = FALSE;
693 
694  while (FALSE !== ($Record = $this->DB->FetchRow()))
695  {
696  $ReferenceId = $Record["DstResourceId"];
697  $Reference = new Resource($ReferenceId);
698 
699  # the reference is bad, so flag that there were errors
700  if ($Reference->Status() != 1)
701  {
702  $FoundErrors = TRUE;
703  }
704 
705  else
706  {
707  $ReturnValue[$ReferenceId] = $Reference;
708  }
709  }
710 
711  # try to fix the errors by removing any references to
712  # resources that were bad
713  if ($FoundErrors)
714  {
715  $this->Set($Field, $ReturnValue);
716  }
717  }
718 
719  # return each reference as a resource ID
720  else
721  {
722  while (FALSE !== ($Record = $this->DB->FetchRow()))
723  {
724  $ReferenceId = $Record["DstResourceId"];
725  $ReturnValue[$ReferenceId] = $ReferenceId;
726  }
727  }
728  break;
729 
730  default:
731  # ERROR OUT
732  exit("<br>SPT - ERROR: attempt to retrieve "
733  ."unknown resource field type (".$Field->Type().")<br>\n");
734  break;
735  }
736 
737  # return formatted value to caller
738  return $ReturnValue;
739  }
740 
760  public function GetForDisplay(
761  $FieldNameOrObject, $ReturnObject = TRUE, $IncludeVariants = FALSE)
762  {
763  # normalize metadata field for use by any hooked code
764  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
765  : $this->Schema()->GetFieldByName($FieldNameOrObject);
766 
767  # retrieve value
768  $Value = $this->Get($Field, $ReturnObject, $IncludeVariants);
769 
770  # signal event to allowed hooked code to modify value
771  $SignalResult = $GLOBALS["AF"]->SignalEvent(
772  "EVENT_FIELD_DISPLAY_FILTER", array(
773  "Field" => $Field,
774  "Resource" => $this,
775  "Value" => $Value));
776 
777  # return possibly modified value to caller
778  return $SignalResult["Value"];
779  }
780 
796  public function GetByField($FieldNameOrObject,
797  $ReturnObject = FALSE, $IncludeVariants = FALSE)
798  {
799  return $this->Get($FieldNameOrObject, $ReturnObject, $IncludeVariants);
800  }
801 
816  public function GetByFieldId(
817  $FieldId, $ReturnObject = FALSE, $IncludeVariants = FALSE)
818  {
819  return $this->Get($FieldId, $ReturnObject, $IncludeVariants);
820  }
821 
834  public function GetAsArray($IncludeDisabledFields = FALSE, $ReturnObjects = TRUE)
835  {
836  # retrieve field info
837  $Fields = $this->Schema()->GetFields();
838 
839  # for each field
840  foreach ($Fields as $Field)
841  {
842  # if field is enabled or caller requested disabled fields
843  if ($Field->Enabled() || $IncludeDisabledFields)
844  {
845  # retrieve info and add it to the array
846  $FieldStrings[$Field->Name()] = $this->Get($Field, $ReturnObjects);
847 
848  # if field uses qualifiers
849  if ($Field->UsesQualifiers())
850  {
851  # get qualifier attributes and add to the array
852  $FieldStrings[$Field->Name()." Qualifier"] =
853  $this->GetQualifierByField($Field, $ReturnObjects);
854  }
855  }
856  }
857 
858  # add in internal values
859  $FieldStrings["ResourceId"] = $this->Id();
860  $FieldStrings["CumulativeRating"] = $this->CumulativeRating();
861 
862  # return array to caller
863  return $FieldStrings;
864  }
865 
880  public function GetMapped(
881  $MappedName, $ReturnObject = FALSE, $IncludeVariants = FALSE)
882  {
883  $Schema = $this->Schema();
884  $FieldId = $Schema->StdNameToFieldMapping($MappedName);
885  return $FieldId
886  ? $this->Get($FieldId, $ReturnObject, $IncludeVariants)
887  : NULL;
888  }
889 
898  public function GetQualifier($FieldName, $ReturnObject = TRUE)
899  {
900  $Field = $this->Schema()->GetFieldByName($FieldName);
901  return $this->GetQualifierByField($Field, $ReturnObject);
902  }
903 
912  public function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
913  {
914  $Field = $this->Schema()->GetField($FieldId);
915  return ($Field) ? $this->GetQualifierByField($Field, $ReturnObject) : NULL;
916  }
917 
926  public function GetQualifierByField($Field, $ReturnObject = TRUE)
927  {
928  # return NULL if field is invalid
929  if (!($Field instanceof MetadataField)) { return NULL; }
930 
931  # assume no qualifiers if not otherwise determined
932  $ReturnValue = NULL;
933 
934  # if field uses qualifiers
935  if ($Field->UsesQualifiers())
936  {
937  # retrieve qualifiers based on field type
938  switch ($Field->Type())
939  {
943  # retrieve list of items
944  $Items = $this->Get($Field);
945 
946  # if field uses item-level qualifiers
947  if ($Field->HasItemLevelQualifiers())
948  {
949  # determine general item name in DB
950  $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
951  ? "Classification" : "ControlledName";
952 
953  # for each item
954  foreach ($Items as $ItemId => $ItemName)
955  {
956  # look up qualifier for item
957  $QualId = $this->DB->Query(
958  "SELECT * FROM ".$TableName."s"
959  ." WHERE ".$TableName."Id = ".$ItemId,
960  "QualifierId");
961 
962 
963  if ($QualId > 0)
964  {
965  # if object was requested by caller
966  if ($ReturnObject)
967  {
968  # load qualifier and add to return value array
969  $ReturnValue[$ItemId] = new Qualifier($QualId);
970  }
971  else
972  {
973  # add qualifier ID to return value array
974  $ReturnValue[$ItemId] = $QualId;
975  }
976  }
977  else
978  {
979  # add NULL to return value array for this item
980  $ReturnValue[$ItemId] = NULL;
981  }
982  }
983  }
984  else
985  {
986  # for each item
987  foreach ($Items as $ItemId => $ItemName)
988  {
989  # if object was requested by caller
990  if ($ReturnObject)
991  {
992  # load default qualifier and add to return value array
993  $ReturnValue[$ItemId] = new Qualifier(
994  $Field->DefaultQualifier());
995  }
996  else
997  {
998  # add default qualifier ID to return value array
999  $ReturnValue[$ItemId] = $Field->DefaultQualifier();
1000  }
1001  }
1002  }
1003  break;
1004 
1005  default:
1006  # if field uses item-level qualifiers
1007  if ($Field->HasItemLevelQualifiers())
1008  {
1009  # if qualifier available
1010  if ($this->DBFields[$Field->DBFieldName()."Qualifier"] > 0)
1011  {
1012  # if object was requested by caller
1013  $QFieldName = $Field->DBFieldName()."Qualifier";
1014  if ($ReturnObject)
1015  {
1016  # return qualifier for field
1017  $ReturnValue = new Qualifier(
1018  $this->DBFields[$QFieldName]);
1019  }
1020  else
1021  {
1022  # return qualifier ID for field
1023  $ReturnValue = $this->DBFields[$QFieldName];
1024  }
1025  }
1026  }
1027  else
1028  {
1029  # if default qualifier available
1030  if ($Field->DefaultQualifier() > 0)
1031  {
1032  # if object was requested by caller
1033  if ($ReturnObject)
1034  {
1035  # return default qualifier
1036  $ReturnValue = new Qualifier($Field->DefaultQualifier());
1037  }
1038  else
1039  {
1040  # return default qualifier ID
1041  $ReturnValue = $Field->DefaultQualifier();
1042  }
1043  }
1044  }
1045  break;
1046  }
1047  }
1048 
1049  # return qualifier object or ID (or array of same) to caller
1050  return $ReturnValue;
1051  }
1052 
1060  public function FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
1061  {
1062  # load field object if needed
1063  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1064  : $this->Schema()->GetFieldByName($FieldNameOrObject);
1065 
1066  # return no value found if we don't have a valid field
1067  if (!($Field instanceof MetadataField)) { return FALSE; }
1068 
1069  # get the value
1070  $Value = $this->Get($Field);
1071 
1072  # checks depend on the field type
1073  switch ($Field->Type())
1074  {
1079  return isset($Value)
1080  && strlen($Value)
1081  && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1082 
1084  return isset($Value)
1085  && strlen($Value);
1086 
1088  return isset($Value["X"])
1089  && isset($Value["Y"])
1090  && strlen(trim($Value["X"]))
1091  && strlen(trim($Value["Y"]));
1092 
1094  return isset($Value)
1095  && strlen(trim($Value))
1096  && $Value != "0000-00-00";
1097 
1099  return isset($Value)
1100  && strlen(trim($Value))
1101  && $Value != "0000-00-00 00:00:00";
1102 
1109  return count($Value) > 0;
1110 
1112  $Factory = new CWUserFactory();
1113  return isset($Value)
1114  && strlen($Value)
1115  && $Factory->UserNameExists($Value);
1116 
1117  default:
1118  return FALSE;
1119  }
1120  }
1121 
1130  public function GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
1131  {
1132  $Result = array();
1133 
1134  # get our target field and extract its values
1135  $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1136  : $this->Schema()->GetField($FieldNameOrObject);
1137  $Images = $this->Get($Field, TRUE);
1138 
1139  # iterate over our images getting URLs for each
1140  $Index = 0;
1141  foreach ($Images as $Image)
1142  {
1143  $Result[$Image->Id()] = $Image->GetImageUrlForResource(
1144  $this->Id(), $Field->Id(), $Index, $ImageSize);
1145  $Index++;
1146  }
1147 
1148  return $Result;
1149  }
1150 
1151  # --- Generic Attribute Setting Methods ---------------------------------
1152 
1165  public function Set($Field, $NewValue, $Reset=FALSE)
1166  {
1167  # load field object if not already supplied
1168  $Field = is_object($Field) ? $Field
1169  : (is_numeric($Field) ? $this->Schema()->GetField($Field)
1170  : $this->Schema()->GetFieldByName($Field));
1171 
1172  # return if we don't have a valid field
1173  if (!($Field instanceof MetadataField)) { return; }
1174 
1175  if ($Field->SchemaId() != $this->SchemaId())
1176  {
1177  throw new Exception("Attempt to set a value for a field "
1178  ."from a different schema.");
1179  }
1180 
1181  # grab commonly-used values for local use
1182  $DB = $this->DB;
1183  $ResourceId = $this->Id;
1184 
1185  # grab database field name
1186  $DBFieldName = $Field->DBFieldName();
1187 
1188  # Flag to deterimine if we've actually changed anything.
1189  $UpdateModTime = FALSE;
1190 
1191  # store value in DB based on field type
1192  switch ($Field->Type())
1193  {
1197  if ($this->DBFields[$DBFieldName] != $NewValue)
1198  {
1199  # save value directly to DB
1200  $DB->Query("UPDATE Resources SET `"
1201  .$DBFieldName."` = '".addslashes($NewValue)."' "
1202  ."WHERE ResourceId = ".$ResourceId);
1203 
1204  # save value locally
1205  $this->DBFields[$DBFieldName] = $NewValue;
1206  $UpdateModTime=TRUE;
1207  }
1208  break;
1209 
1211  if ( $this->DBFields[$DBFieldName] != $NewValue )
1212  {
1213  # save value directly to DB
1214  if (is_null($NewValue))
1215  {
1216  $DB->Query("UPDATE Resources SET `"
1217  .$DBFieldName."` = NULL"
1218  ." WHERE ResourceId = ".$ResourceId);
1219  }
1220  else
1221  {
1222  $DB->Query("UPDATE Resources SET `"
1223  .$DBFieldName."` = ".intval($NewValue)
1224  ." WHERE ResourceId = ".$ResourceId);
1225  }
1226 
1227  # save value locally
1228  $this->DBFields[$DBFieldName] = $NewValue;
1229  $UpdateModTime = TRUE;
1230  }
1231  break;
1232 
1233 
1235  if ($this->DBFields[$DBFieldName."X"] != $NewValue["X"] ||
1236  $this->DBFields[$DBFieldName."Y"] != $NewValue["Y"] )
1237  {
1238  if (is_null($NewValue))
1239  {
1240  $DB->Query("UPDATE Resources SET "
1241  ."`".$DBFieldName."X` = NULL, "
1242  ."`".$DBFieldName."Y` = NULL "
1243  ."WHERE ResourceId = ".$ResourceId);
1244  $this->DBFields[$DBFieldName."X"] = NULL;
1245  $this->DBFields[$DBFieldName."Y"] = NULL;
1246  }
1247  else
1248  {
1249  $DB->Query("UPDATE Resources SET "
1250  ."`".$DBFieldName."X` = " .(strlen($NewValue["X"])
1251  ? "'".$NewValue["X"]."'" : "NULL").", "
1252  ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
1253  ? "'".$NewValue["Y"]."'" : "NULL")
1254  ." WHERE ResourceId = ".$ResourceId);
1255 
1256  $Digits = $Field->PointDecimalDigits();
1257 
1258  $this->DBFields[$DBFieldName."X"] =
1259  strlen($NewValue["X"]) ?
1260  round($NewValue["X"], $Digits) : NULL;
1261  $this->DBFields[$DBFieldName."Y"] =
1262  strlen($NewValue["Y"]) ?
1263  round($NewValue["Y"], $Digits) : NULL;
1264  }
1265  $UpdateModTime = TRUE;
1266  }
1267  break;
1268 
1270  if ($this->DBFields[$DBFieldName] != $NewValue)
1271  {
1272  # save value directly to DB
1273  if (is_null($NewValue))
1274  {
1275  $DB->Query("UPDATE Resources SET `"
1276  .$DBFieldName."` = NULL"
1277  ." WHERE ResourceId = ".$ResourceId);
1278  }
1279  else
1280  {
1281  $NewValue = $NewValue ? "1" : "0";
1282  $DB->Query("UPDATE Resources SET `"
1283  .$DBFieldName."` = ".$NewValue
1284  ." WHERE ResourceId = ".$ResourceId);
1285  }
1286 
1287  $this->DBFields[$DBFieldName] = $NewValue;
1288 
1289  # recalculate counts for any associated classifications if necessary
1290  if ($DBFieldName == "ReleaseFlag")
1291  {
1292  $DB->Query("SELECT ClassificationId FROM ResourceClassInts"
1293  ." WHERE ResourceId = ".$ResourceId);
1294  while ($ClassId = $DB->FetchField("ClassificationId"))
1295  {
1296  $Class = new Classification($ClassId);
1297  $Class->RecalcResourceCount();
1298  }
1299  }
1300  $UpdateModTime = TRUE;
1301  }
1302  break;
1303 
1305  $OldValue = $this->Get($Field);
1306  # value comes back as array (UserId => UserName), just get the Ids
1307  $OldValue = array_keys($OldValue);
1308 
1309  # input to Set() for these fields is one of
1310  # 1. an int specifying a UserId
1311  if (is_numeric($NewValue))
1312  {
1313  $NewValue = array($NewValue);
1314  }
1315  # 2. a CWUser object
1316  elseif ($NewValue instanceof CWUser)
1317  {
1318  $NewValue = array($NewValue->Id());
1319  }
1320  # 3. an array keyed by UserId (don't care about the values)
1321  elseif (is_array($NewValue))
1322  {
1323  $NewValue = array_keys($NewValue);
1324  }
1325  else
1326  {
1327  throw new Exception("Unknown format for NewValue in a User field");
1328  }
1329 
1330  # if this is a unique field, only accept the first of the options given
1331  if ($Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1332  {
1333  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1334  }
1335 
1336  # sort new and old values so we can directly compare
1337  sort($OldValue);
1338  sort($NewValue);
1339 
1340  # if the value has changed
1341  if ($OldValue != $NewValue)
1342  {
1343  if ($Reset || $Field->AllowMultiple() == FALSE )
1344  {
1345  $ToRemove = array_diff($OldValue, $NewValue);
1346  $this->RemoveAssociation(
1347  "ResourceUserInts", "UserId", $ToRemove, $Field);
1348  }
1349 
1350  # associate with resource if not already associated
1351  $this->AddAssociation("ResourceUserInts",
1352  "UserId",
1353  $NewValue, $Field);
1354 
1355  $UpdateModTime=TRUE;
1356  }
1357  break;
1358 
1360  # if we were given a date object
1361  if (is_object($NewValue))
1362  {
1363  # use supplied date object
1364  $Date = $NewValue;
1365  }
1366  else
1367  {
1368  # create date object
1369  $Date = new Date($NewValue);
1370  }
1371 
1372  $OldDate = new Date(
1373  $this->DBFields[$DBFieldName."Begin"],
1374  $this->DBFields[$DBFieldName."End"]);
1375 
1376  if ($OldDate->BeginDate() != $Date->BeginDate() ||
1377  $OldDate->EndDate() != $Date->EndDate() ||
1378  $OldDate->Precision() != $Date->Precision() )
1379  {
1380  # extract values from date object and store in DB
1381  $BeginDate = "'".$Date->BeginDate()."'";
1382  if (strlen($BeginDate) < 3) { $BeginDate = "NULL"; }
1383  $EndDate = "'".$Date->EndDate()."'";
1384  if (strlen($EndDate) < 3) { $EndDate = "NULL"; }
1385 
1386  $DB->Query("UPDATE Resources SET "
1387  .$DBFieldName."Begin = ".$BeginDate.", "
1388  .$DBFieldName."End = ".$EndDate.", "
1389  .$DBFieldName."Precision = '".$Date->Precision()."' "
1390  ."WHERE ResourceId = ".$ResourceId);
1391 
1392  # save values locally
1393  $this->DBFields[$DBFieldName."Begin"] = $Date->BeginDate();
1394  $this->DBFields[$DBFieldName."End"] = $Date->EndDate();
1395  $this->DBFields[$DBFieldName."Precision"] = $Date->Precision();
1396  $UpdateModTime=TRUE;
1397  }
1398  break;
1399 
1401  if (is_null($NewValue) || !strlen(trim($NewValue)))
1402  {
1403  $DateValue = $NewValue;
1404 
1405  if (!is_null($this->DBFields[$DBFieldName]))
1406  {
1407  # save value directly to DB
1408  $DB->Query("UPDATE Resources SET "
1409  ."`".$DBFieldName."` = NULL "
1410  ."WHERE ResourceId = ".$ResourceId);
1411  $UpdateModTime = TRUE;
1412  }
1413  }
1414  else
1415  {
1416  # assume value is date and use directly
1417  $TimestampValue = strtotime($NewValue);
1418 
1419  # use the new value if the date is valid
1420  if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1421  {
1422  $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1423 
1424  if ($this->DBFields[$DBFieldName] != $DateValue)
1425  {
1426  # save value directly to DB
1427  $DB->Query("UPDATE Resources SET "
1428  ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1429  ."WHERE ResourceId = ".$ResourceId);
1430  $UpdateModTime=TRUE;
1431  }
1432  }
1433 
1434  # continue using the old value if invalid
1435  else
1436  {
1437  $DateValue = $this->Get($Field);
1438  }
1439  }
1440 
1441  # save value locally
1442  $this->DBFields[$DBFieldName] = $DateValue;
1443  break;
1444 
1446  $OldValue = $this->Get($Field);
1447 
1448  # if incoming value is array
1449  if (is_array($NewValue))
1450  {
1451  if ($OldValue != $NewValue)
1452  {
1453  if ($Reset)
1454  {
1455  # remove values that were in the old value
1456  # but not the new one
1457  $ToRemove = array_diff(array_keys($OldValue),
1458  array_keys($NewValue));
1459  foreach ($ToRemove as $ClassificationId)
1460  {
1461  $this->RemoveAssociation("ResourceClassInts",
1462  "ClassificationId",
1463  $ClassificationId);
1464  $Class = new Classification($ClassificationId);
1465  if ($Class->Status() == Classification::CLASSSTAT_OK)
1466  {
1467  $Class->RecalcResourceCount();
1468  }
1469  }
1470  }
1471 
1472  # for each element of array
1473  foreach ($NewValue as
1474  $ClassificationId => $ClassificationName)
1475  {
1476  $Class = new Classification($ClassificationId);
1477  if ($Class->FieldId() == $Field->Id())
1478  {
1479  if ($Class->Status() == Classification::CLASSSTAT_OK)
1480  {
1481  # associate with resource if not already associated
1482  if ($this->AddAssociation("ResourceClassInts",
1483  "ClassificationId",
1484  $ClassificationId) )
1485  {
1486  $Class->UpdateLastAssigned();
1487  $Class->RecalcResourceCount();
1488  }
1489  }
1490  }
1491  else
1492  {
1493  throw new Exception(
1494  "Attempting to store classification from "
1495  ."Field ".$Class->FieldId()." into Field "
1496  .$Field->Id() );
1497  }
1498 
1499  }
1500 
1501  $UpdateModTime=TRUE;
1502  }
1503  }
1504  else
1505  {
1506  # associate with resource if not already associated
1507  if (is_object($NewValue))
1508  {
1509  $Class = $NewValue;
1510  $NewValue = $Class->Id();
1511  }
1512  else
1513  {
1514  $Class = new Classification($NewValue);
1515  }
1516 
1517  if (!array_key_exists($Class->Id(), $OldValue))
1518  {
1519 
1520  $this->AddAssociation("ResourceClassInts",
1521  "ClassificationId",
1522  $NewValue);
1523  $Class->UpdateLastAssigned();
1524  $Class->RecalcResourceCount();
1525  $UpdateModTime=TRUE;
1526  }
1527  }
1528 
1529  # clear our classification cache
1530  if ($UpdateModTime)
1531  {
1532  unset($this->ClassificationCache);
1533  }
1534  break;
1535 
1538  $OldValue = $this->Get($Field);
1539 
1540  # input to Set() for these fields is one of
1541  # 1. an int specifying a ControlledNameId
1542  # 2. a ControlledName object
1543  # 3. an array with keys giving Ids and values giving ControlledNames
1544  #
1545  # normalize 1 and 2 into 3 for simplicity of processing
1546  if (is_object($NewValue) || !is_array($NewValue) )
1547  {
1548  if (!is_object($NewValue))
1549  {
1550  $NewValue = new ControlledName($NewValue);
1551  }
1552 
1553  $TmpValue = array();
1554  $TmpValue[$NewValue->Id()] = $NewValue->Name();
1555 
1556  $NewValue = $TmpValue;
1557  }
1558 
1559  # if this is a unique field, only accept the first of the options given
1560  # NB: all ControlledNames implicitly AllowMultiple
1561  if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1562  $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1563  {
1564  $NewValue = array_slice($NewValue, 0, 1, TRUE);
1565  }
1566 
1567  # if the value has changed
1568  if ($OldValue != $NewValue)
1569  {
1570  if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1571  && $Field->AllowMultiple() == FALSE ) )
1572  {
1573  $ToRemove = array_diff(array_keys($OldValue),
1574  array_keys($NewValue));
1575  foreach ($ToRemove as $CNId)
1576  {
1577  $this->RemoveAssociation("ResourceNameInts",
1578  "ControlledNameId",
1579  $CNId);
1580  }
1581  }
1582 
1583  # for each element of array
1584  foreach ($NewValue as $ControlledNameId => $ControlledName)
1585  {
1586  # associate with resource if not already associated
1587  if ($this->AddAssociation("ResourceNameInts",
1588  "ControlledNameId",
1589  $ControlledNameId))
1590  {
1591  $CN = new ControlledName($ControlledNameId);
1592  if ($CN->Status() != ControlledName::STATUS_OK)
1593  {
1594  $this->RemoveAssociation("ResourceNameInts",
1595  "ControlledNameId", $ControlledNameId);
1596  throw new InvalidArgumentException(
1597  "Attempt to set controlled name with"
1598  ." invalid ID (".$ControlledNameId.").");
1599  }
1600  $CN->UpdateLastAssigned();
1601  }
1602  }
1603  $UpdateModTime = TRUE;
1604  }
1605 
1606  if ($UpdateModTime)
1607  {
1608  # clear our controlled name cache
1609  unset($this->ControlledNameCache);
1610  unset($this->ControlledNameVariantCache);
1611 
1612  # clear visible count cache for any affected resources
1613  $ValueIds = array_keys($OldValue) + array_keys($NewValue);
1614  $DB->Query(
1615  "DELETE FROM VisibleResourceCounts WHERE "
1616  ."SchemaId=".intval($this->SchemaId)." AND "
1617  ."ValueId IN (".implode(",", $ValueIds).")");
1618  }
1619 
1620  break;
1621 
1623  # associate value(s) with resource
1624  $this->AddAssociation(
1625  "ResourceImageInts", "ImageId", $NewValue, $Field);
1626  # clear cached image mappings
1627  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1628  break;
1629 
1631  # convert incoming value to array if necessary
1632  if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1633 
1634  # for each incoming file
1635  $Factory = new FileFactory($Field->Id());
1636  foreach ($NewValue as $File)
1637  {
1638  # make copy of file
1639  $NewFile = $Factory->Copy($File);
1640 
1641  # associate copy with this resource and field
1642  $NewFile->ResourceId($this->Id);
1643  $NewFile->FieldId($Field->Id());
1644  }
1645  # Since we make a fresh copy of the File whenever Set is called,
1646  # we'll always update the modification time for this field.
1647  $UpdateModTime = TRUE;
1648  break;
1649 
1651  # convert incoming value to array to simplify the workflow
1652  if (is_scalar($NewValue) || $NewValue instanceof Resource)
1653  {
1654  $NewValue = array($NewValue);
1655  }
1656 
1657  # delete existing resource references
1658  $this->ClearByField($Field);
1659 
1660  # add each reference
1661  foreach ($NewValue as $ReferenceOrId)
1662  {
1663  # initially issume it's a reference ID and not an object...
1664  $ReferenceId = $ReferenceOrId;
1665 
1666  # ... but get the reference ID if it's an object
1667  if ($ReferenceOrId instanceof Resource)
1668  {
1669  $ReferenceId = $ReferenceOrId->Id();
1670  }
1671 
1672  # skip blank reference IDs
1673  if (strlen(trim($ReferenceId)) < 1)
1674  {
1675  continue;
1676  }
1677 
1678  # skip reference IDs that don't look right
1679  if (!is_numeric($ReferenceId))
1680  {
1681  continue;
1682  }
1683 
1684  # skip references to the current resource
1685  if ($ReferenceId == $this->Id())
1686  {
1687  continue;
1688  }
1689 
1690  # add the reference to the references table
1691  $DB->Query("
1692  INSERT INTO ReferenceInts (
1693  FieldId,
1694  SrcResourceId,
1695  DstResourceId)
1696  VALUES (
1697  ".addslashes($Field->Id()).",
1698  ".addslashes($this->Id()).",
1699  ".addslashes($ReferenceId).")");
1700  }
1701  break;
1702 
1703  default:
1704  # ERROR OUT
1705  exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1706  break;
1707  }
1708 
1709  if ($UpdateModTime && !$this->IsTempResource())
1710  {
1711  # update modification timestamps
1712  global $G_User;
1713  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1714  $DB->Query("DELETE FROM ResourceFieldTimestamps "
1715  ."WHERE ResourceId=".$this->Id." AND "
1716  ."FieldId=".$Field->Id() );
1717  $DB->Query("INSERT INTO ResourceFieldTimestamps "
1718  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1719  .$this->Id.",".$Field->Id().","
1720  .$UserId.",NOW())");
1721 
1722  # on resource modification, clear the UserPermsCache entry
1723  # so that stale permissions checks are not cached
1724  $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1725  }
1726  }
1727 
1735  public function SetByField($Field, $NewValue)
1736  {
1737  $this->Set($Field, $NewValue);
1738  }
1739 
1747  public function SetByFieldId($FieldId, $NewValue)
1748  {
1749  $this->Set($FieldId, $NewValue);
1750  }
1751 
1757  public function SetQualifier($FieldName, $NewValue)
1758  {
1759  $Field = $this->Schema()->GetFieldByName($FieldName);
1760  $this->SetQualifierByField($Field, $NewValue);
1761  }
1762 
1768  public function SetQualifierByFieldId($FieldId, $NewValue)
1769  {
1770  $Field = $this->Schema()->GetField($FieldId);
1771  $this->SetQualifierByField($Field, $NewValue);
1772  }
1773 
1779  public function SetQualifierByField($Field, $NewValue)
1780  {
1781  # if field uses qualifiers and uses item-level qualifiers
1782  if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1783  {
1784  # if qualifier object passed in
1785  if (is_object($NewValue))
1786  {
1787  # grab qualifier ID from object
1788  $QualifierId = $NewValue->Id();
1789  }
1790  else
1791  {
1792  # assume value passed in is qualifier ID
1793  $QualifierId = $NewValue;
1794  }
1795 
1796  # update qualifier value in database
1797  $DBFieldName = $Field->DBFieldName();
1798  $this->DB->Query("UPDATE Resources SET "
1799  .$DBFieldName."Qualifier = '".$QualifierId."' "
1800  ."WHERE ResourceId = ".$this->Id);
1801 
1802  # update local qualifier value
1803  $this->DBFields[$DBFieldName."Qualifier"] = $QualifierId;
1804  }
1805  }
1806 
1813  public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1814  {
1815  $Field = $this->Schema()->GetField($FieldId);
1816  $this->Clear($Field, $ValueToClear);
1817  }
1818 
1825  public function Clear($Field, $ValueToClear = NULL)
1826  {
1827  # convert field name to object if necessary
1828  if (!is_object($Field))
1829  {
1830  $Field = $this->Schema()->GetFieldByName($Field);
1831  }
1832 
1833  # grab commonly-used values for local use
1834  $DB = $this->DB;
1835  $ResourceId = $this->Id;
1836 
1837  # grab database field name
1838  $DBFieldName = $Field->DBFieldName();
1839 
1840  $UpdateModTime=FALSE;
1841 
1842  # store value in DB based on field type
1843  switch ($Field->Type())
1844  {
1851  if (strlen($this->DBFields[$DBFieldName])>0)
1852  {
1853  # clear value in DB
1854  $DB->Query("UPDATE Resources SET `"
1855  .$DBFieldName."` = NULL "
1856  ."WHERE ResourceId = ".$ResourceId);
1857 
1858  # clear value locally
1859  $this->DBFields[$DBFieldName] = NULL;
1860  $UpdateModTime=TRUE;
1861  }
1862  break;
1863 
1865  if (!is_null($this->DBFields[$DBFieldName."X"]) ||
1866  !is_null($this->DBFields[$DBFieldName."Y"]) )
1867  {
1868  # Clear DB Values
1869  $DB->Query("UPDATE Resources SET "
1870  ."`".$DBFieldName."X` = NULL ,"
1871  ."`".$DBFieldName."Y` = NULL "
1872  ."WHERE ResourceId = ".$ResourceId);
1873 
1874  # Clear local values
1875  $this->DBFields[$DBFieldName."X"] = NULL;
1876  $this->DBFields[$DBFieldName."Y"] = NULL;
1877  $UpdateModTime=TRUE;
1878  }
1879  break;
1880 
1882  if (!is_null($this->DBFields[$DBFieldName."Begin"]) ||
1883  !is_null($this->DBFields[$DBFieldName."End"]) ||
1884  !is_null($this->DBFields[$DBFieldName."Precision"]))
1885  {
1886  # clear date object values in DB
1887  $DB->Query("UPDATE Resources SET "
1888  .$DBFieldName."Begin = '', "
1889  .$DBFieldName."End = '', "
1890  .$DBFieldName."Precision = '' "
1891  ."WHERE ResourceId = ".$ResourceId);
1892 
1893  # clear value locally
1894  $this->DBFields[$DBFieldName."Begin"] = NULL;
1895  $this->DBFields[$DBFieldName."End"] = NULL;
1896  $this->DBFields[$DBFieldName."Precision"] = NULL;
1897  $UpdateModTime=TRUE;
1898  }
1899  break;
1900 
1902  $OldValue = $this->Get($Field);
1903 
1904  # if value to clear supplied
1905  if ($ValueToClear !== NULL)
1906  {
1907  # if supplied value is array
1908  if (is_array($ValueToClear))
1909  {
1910  # for each element of array
1911  foreach ($ValueToClear as $ClassificationId => $Dummy)
1912  {
1913  if (array_key_exists($ClassificationId, $OldValue))
1914  {
1915  # remove association with resource (if any)
1916  $this->RemoveAssociation("ResourceClassInts",
1917  "ClassificationId",
1918  $ClassificationId);
1919  $Class = new Classification($ClassificationId);
1920  $Class->RecalcResourceCount();
1921  $UpdateModTime=TRUE;
1922  }
1923  }
1924  }
1925  else
1926  {
1927  if (array_key_exists($ValueToClear, $OldValue))
1928  {
1929  # remove association with resource (if any)
1930  $this->RemoveAssociation("ResourceClassInts",
1931  "ClassificationId",
1932  $ValueToClear);
1933  $Class = new Classification($ValueToClear);
1934  $Class->RecalcResourceCount();
1935  $UpdateModTime=TRUE;
1936  }
1937  }
1938  }
1939  else
1940  {
1941  if (count($OldValue)>0)
1942  {
1943  # remove all associations for resource and field
1944  $this->RemoveAllAssociations(
1945  "ResourceClassInts", "ClassificationId", $Field);
1946 
1947  # recompute resource count
1948  $Values = $this->Get($Field);
1949  foreach ($Values as $ClassificationId => $Dummy)
1950  {
1951  $Class = new Classification($ClassificationId);
1952  $Class->RecalcResourceCount();
1953  }
1954  $UpdateModTime=TRUE;
1955  }
1956  }
1957 
1958  # clear our classification cache
1959  if ($UpdateModTime)
1960  {
1961  unset($this->ClassificationCache);
1962  }
1963  break;
1964 
1967  $OldValue = $this->Get($Field);
1968  # if value to clear supplied
1969  if ($ValueToClear !== NULL)
1970  {
1971  # if incoming value is array
1972  if (is_array($ValueToClear))
1973  {
1974  # for each element of array
1975  foreach ($ValueToClear as $ControlledNameId =>
1976  $ControlledName)
1977  {
1978  if (array_key_exists($ControlledNameId, $OldValue))
1979  {
1980  # remove association with resource (if any)
1981  $this->RemoveAssociation("ResourceNameInts",
1982  "ControlledNameId",
1983  $ControlledNameId);
1984  $UpdateModTime=TRUE;
1985  }
1986  }
1987  }
1988  else
1989  {
1990  if (array_key_exists($ValueToClear, $OldValue))
1991  {
1992  # remove association with resource (if any)
1993  $this->RemoveAssociation("ResourceNameInts",
1994  "ControlledNameId",
1995  $ValueToClear);
1996  $UpdateModTime=TRUE;
1997  }
1998  }
1999  }
2000  else
2001  {
2002  if (count($OldValue)>0)
2003  {
2004  # remove all associations for resource and field
2005  $this->RemoveAllAssociations(
2006  "ResourceNameInts", "ControlledNameId", $Field);
2007  $UpdateModTime=TRUE;
2008  }
2009  }
2010 
2011  if ($UpdateModTime)
2012  {
2013  # clear our controlled name cache
2014  unset($this->ControlledNameCache);
2015  unset($this->ControlledNameVariantCache);
2016  }
2017  break;
2018 
2020  $OldValue = $this->Get($Field);
2021 
2022  # if value to clear supplied
2023  if ($ValueToClear !== NULL)
2024  {
2025  # if incoming value is array
2026  if (is_array($ValueToClear))
2027  {
2028  # for each element of array
2029  foreach ($ValueToClear as $UserId => $User)
2030  {
2031  if (array_key_exists($UserId, $OldValue))
2032  {
2033  # remove association with resource (if any)
2034  $this->RemoveAssociation("ResourceUserInts",
2035  "UserId",
2036  $UserId,
2037  $Field);
2038  $UpdateModTime=TRUE;
2039  }
2040  }
2041  }
2042  else
2043  {
2044  if (array_key_exists($ValueToClear, $OldValue))
2045  {
2046  # remove association with resource (if any)
2047  $this->RemoveAssociation("ResourceUserInts",
2048  "UserId",
2049  $UserId,
2050  $Field);
2051  $UpdateModTime=TRUE;
2052  }
2053  }
2054  }
2055  else
2056  {
2057  if (count($OldValue)>0)
2058  {
2059  # remove all associations for resource and field
2060  $this->RemoveAllAssociations(
2061  "ResourceUserInts", "UserId", $Field);
2062  $UpdateModTime=TRUE;
2063  }
2064  }
2065 
2066  break;
2067 
2069  # if value to clear supplied
2070  if ($ValueToClear !== NULL)
2071  {
2072  # convert value to array if necessary
2073  $Files = $ValueToClear;
2074  if (!is_array($Files)) { $Files = array($Files); }
2075 
2076  # convert values to objects if necessary
2077  foreach ($Files as $Index => $File)
2078  {
2079  if (!is_object($File))
2080  {
2081  $Files[$Index] = new File($File);
2082  }
2083  }
2084  }
2085  else
2086  {
2087  # use all files associated with resource
2088  $Files = $this->Get($Field, TRUE);
2089  }
2090 
2091  # delete files
2092  foreach ($Files as $File) { $File->Delete(); }
2093  break;
2094 
2096  # if value to clear supplied
2097  if ($ValueToClear !== NULL)
2098  {
2099  # convert value to array if necessary
2100  $Images = $ValueToClear;
2101  if (!is_array($Images)) { $Images = array($Images); }
2102 
2103  # convert values to objects if necessary
2104  foreach ($Images as $Index => $Image)
2105  {
2106  if (!is_object($Image))
2107  {
2108  $Images[$Index] = new SPTImage($Image);
2109  }
2110  }
2111  }
2112  else
2113  {
2114  # use all images associated with resource
2115  $Images = $this->Get($Field, TRUE);
2116  }
2117 
2118  # delete images if we are the last resource referencing
2119  # a particular image.
2120  foreach ($Images as $Image)
2121  {
2122  $Cnt = $this->DB->Query(
2123  "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
2124  "ImageId=".$Image->Id(), "Cnt");
2125  if ($Cnt==1)
2126  {
2127  $Image->Delete();
2128  }
2129  }
2130 
2131  # clear cached image mappings
2132  SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
2133 
2134  # remove connections to images
2135  $UpdateModTime = $this->RemoveAssociation(
2136  "ResourceImageInts", "ImageId", $Images, $Field);
2137  break;
2138 
2140  # remove references from the references table
2141  $DB->Query("
2142  DELETE FROM ReferenceInts
2143  WHERE FieldId = '".addslashes($Field->Id())."'
2144  AND SrcResourceId = '".addslashes($this->Id())."'");
2145  break;
2146 
2147  default:
2148  # ERROR OUT
2149  exit("<br>SPT - ERROR: attempt to clear "
2150  ."unknown resource field type<br>\n");
2151  break;
2152  }
2153 
2154  if ($UpdateModTime && !$this->IsTempResource())
2155  {
2156  # update modification timestamps
2157  global $G_User;
2158  $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
2159  $DB->Query("DELETE FROM ResourceFieldTimestamps "
2160  ."WHERE ResourceId=".$this->Id." AND "
2161  ."FieldId=".$Field->Id() );
2162  $DB->Query("INSERT INTO ResourceFieldTimestamps "
2163  ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
2164  .$this->Id.",".$Field->Id().","
2165  .$UserId.",NOW())");
2166  }
2167  }
2168 
2177  public function ClearByField($Field, $ValueToClear = NULL)
2178  {
2179  $this->Clear($Field, $ValueToClear);
2180  }
2181 
2182  # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
2183 
2189  public function Classifications()
2190  {
2191  $DB = $this->DB;
2192 
2193  # start with empty array
2194  $Names = array();
2195 
2196  # for each controlled name
2197  $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2198  ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2199  ."Classifications, MetadataFields "
2200  ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2201  ."AND ResourceClassInts.ClassificationId = "
2202  ."Classifications.ClassificationId "
2203  ."AND Classifications.FieldId = MetadataFields.FieldId ");
2204  while ($Record = $DB->FetchRow())
2205  {
2206  # add name to array
2207  $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2208  $Record["ClassificationName"];
2209  }
2210 
2211  # return array to caller
2212  return $Names;
2213  }
2214 
2215 
2216  # --- Ratings Methods ---------------------------------------------------
2217 
2222  public function CumulativeRating()
2223  {
2224  return $this->CumulativeRating;
2225  }
2226 
2231  public function ScaledCumulativeRating()
2232  {
2233  if ($this->CumulativeRating == NULL)
2234  {
2235  return NULL;
2236  }
2237  else
2238  {
2239  return intval(($this->CumulativeRating + 5) / 10);
2240  }
2241  }
2242 
2247  public function NumberOfRatings()
2248  {
2249  # if number of ratings not already set
2250  if (!isset($this->NumberOfRatings))
2251  {
2252  # obtain number of ratings
2253  $this->NumberOfRatings =
2254  $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
2255  ."FROM ResourceRatings "
2256  ."WHERE ResourceId = ".$this->Id,
2257  "NumberOfRatings"
2258  );
2259 
2260  # recalculate cumulative rating if it looks erroneous
2261  if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
2262  {
2263  $this->UpdateCumulativeRating();
2264  }
2265  }
2266 
2267  # return number of ratings to caller
2268  return $this->NumberOfRatings;
2269  }
2270 
2278  public function Rating($NewRating = NULL, $UserId = NULL)
2279  {
2280  $DB = $this->DB;
2281 
2282  # if user ID not supplied
2283  if ($UserId == NULL)
2284  {
2285  # if user is logged in
2286  global $User;
2287  if ($User->IsLoggedIn())
2288  {
2289  # use ID of current user
2290  $UserId = $User->Get("UserId");
2291  }
2292  else
2293  {
2294  # return NULL to caller
2295  return NULL;
2296  }
2297  }
2298 
2299  # sanitize $NewRating
2300  if (!is_null($NewRating))
2301  {
2302  $NewRating = intval($NewRating);
2303  }
2304 
2305  # if there is a rating for resource and user
2306  $DB->Query("SELECT Rating FROM ResourceRatings "
2307  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2308  if ($Record = $DB->FetchRow())
2309  {
2310  # if new rating was supplied
2311  if ($NewRating != NULL)
2312  {
2313  # update existing rating
2314  $DB->Query("UPDATE ResourceRatings "
2315  ."SET Rating = ${NewRating}, DateRated = NOW() "
2316  ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2317 
2318  # update cumulative rating value
2319  $this->UpdateCumulativeRating();
2320 
2321  # return value is new rating
2322  $Rating = $NewRating;
2323  }
2324  else
2325  {
2326  # get rating value to return to caller
2327  $Rating = $Record["Rating"];
2328  }
2329  }
2330  else
2331  {
2332  # if new rating was supplied
2333  if ($NewRating != NULL)
2334  {
2335  # add new rating
2336  $DB->Query("INSERT INTO ResourceRatings "
2337  ."(ResourceId, UserId, DateRated, Rating) "
2338  ."VALUES ("
2339  .$this->Id.", "
2340  ."${UserId}, "
2341  ."NOW(), "
2342  ."${NewRating})");
2343 
2344  # update cumulative rating value
2345  $this->UpdateCumulativeRating();
2346 
2347  # return value is new rating
2348  $Rating = $NewRating;
2349  }
2350  else
2351  {
2352  # return value is NULL
2353  $Rating = NULL;
2354  }
2355  }
2356 
2357  # return rating value to caller
2358  return $Rating;
2359  }
2360 
2361 
2362  # --- Resource Comment Methods ------------------------------------------
2363 
2368  public function Comments()
2369  {
2370  # read in comments if not already loaded
2371  if (!isset($this->Comments))
2372  {
2373  $this->DB->Query("SELECT MessageId FROM Messages "
2374  ."WHERE ParentId = ".$this->Id
2375  ." AND ParentType = 2 "
2376  ."ORDER BY DatePosted DESC");
2377  while ($MessageId = $this->DB->FetchField("MessageId"))
2378  {
2379  $this->Comments[] = new Message($MessageId);
2380  }
2381  }
2382 
2383  # return array of comments to caller
2384  return $this->Comments;
2385  }
2386 
2391  public function NumberOfComments()
2392  {
2393  # obtain number of comments if not already set
2394  if (!isset($this->NumberOfComments))
2395  {
2396  $this->NumberOfComments =
2397  $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2398  ."FROM Messages "
2399  ."WHERE ParentId = ".$this->Id
2400  ." AND ParentType = 2",
2401  "NumberOfComments"
2402  );
2403  }
2404 
2405  # return number of comments to caller
2406  return $this->NumberOfComments;
2407  }
2408 
2409 
2410  # --- Permission Methods -------------------------------------------------
2411 
2421  public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2422  {
2423  return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2424  }
2425 
2432  public function UserCanEdit($User)
2433  {
2434  return $this->CheckSchemaPermissions($User, "Edit");
2435  }
2436 
2443  public function UserCanAuthor($User)
2444  {
2445  return $this->CheckSchemaPermissions($User, "Author");
2446  }
2447 
2454  public function UserCanModify($User)
2455  {
2456  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2457  return $this->$CheckFn($User);
2458  }
2459 
2466  public function UserCanViewField($User, $FieldOrFieldName)
2467  {
2468  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "View" );
2469  }
2470 
2477  public function UserCanEditField($User, $FieldOrFieldName)
2478  {
2479  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Edit" );
2480  }
2481 
2488  public function UserCanAuthorField($User, $FieldOrFieldName)
2489  {
2490  return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2491  }
2492 
2500  public function UserCanModifyField($User, $FieldOrFieldName)
2501  {
2502  $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2503 
2504  return $this->$CheckFn($User, $FieldOrFieldName);
2505  }
2506 
2507  # --- Utility Methods ----------------------------------------------------
2508 
2513  {
2514  if (!$this->IsTempResource())
2515  {
2516  $SearchEngine = new SPTSearchEngine();
2517  $SearchEngine->QueueUpdateForItem($this);
2518 
2519  $Recommender = new SPTRecommender();
2520  $Recommender->QueueUpdateForItem($this);
2521  }
2522  }
2523 
2529  public static function GetSchemaForResource($ResourceId)
2530  {
2531  # if schema IDs are not loaded
2532  if (!isset(self::$SchemaIdCache))
2533  {
2534  # load schema IDs
2535  $DB = new Database();
2536  $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2537  self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2538  }
2539 
2540  # if multiple resources specified
2541  if (is_array($ResourceId))
2542  {
2543  # find schema IDs for specified resources
2544  $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2545  array_flip($ResourceId));
2546 
2547  # check that specified resource IDs were all valid
2548  if (count($SchemaIds) < count($ResourceId))
2549  {
2550  $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2551  throw new InvalidArgumentException("Unknown resource IDs ("
2552  .implode(", ", $BadIds).").");
2553  }
2554 
2555  # return schema IDs to caller
2556  return $SchemaIds;
2557  }
2558  else
2559  {
2560  # check that specified resource was valid
2561  if (!isset(self::$SchemaIdCache[$ResourceId]))
2562  {
2563  throw new InvalidArgumentException("Unknown resource ID ("
2564  .$ResourceId.").");
2565  }
2566 
2567  # return schema IDs for specified resource
2568  return self::$SchemaIdCache[$ResourceId];
2569  }
2570  }
2571 
2572 
2573  # ---- PRIVATE INTERFACE -------------------------------------------------
2574 
2575  protected $DB;
2576 
2577  private $ClassificationCache;
2578  private $Comments;
2579  private $ControlledNameCache;
2580  private $ControlledNameVariantCache;
2581  private $CumulativeRating;
2582  private $DBFields;
2583  private $LastStatus;
2584  private $NumberOfComments;
2585  private $NumberOfRatings;
2586  private $PermissionCache;
2587  private $SchemaId;
2588 
2589  static private $Schemas;
2590  static private $SchemaIdCache;
2591 
2602  private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2603  {
2604  # checks against invalid resources should always fail
2605  if ($this->Status() !== 1) { return FALSE; }
2606 
2607  # construct a key to use for our permissions cache
2608  $CacheKey = "UserCan".$CheckType.$User->Id();
2609 
2610  # if we don't have a cached value for this perm, compute one
2611  if (!isset($this->PermissionCache[$CacheKey]))
2612  {
2613  # get privileges for schema
2614  $PermsFn = $CheckType."ingPrivileges";
2615  $SchemaPrivs = $this->Schema()->$PermsFn();
2616 
2617  # check passes if user privileges are greater than resource set
2618  $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2619 
2620  # save the result of this check in our cache
2621  $this->PermissionCache[$CacheKey] = $CheckResult;
2622  }
2623 
2624  $Value = $this->PermissionCache[$CacheKey];
2625 
2626  if ($AllowHooksToModify)
2627  {
2628  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2629  "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2630  array(
2631  "Resource" => $this,
2632  "User" => $User,
2633  "Can".$CheckType => $Value,
2634  "Schema" => $this->Schema(), ));
2635 
2636  $Value = $SignalResult["Can".$CheckType];
2637  }
2638 
2639  return $Value;
2640  }
2641 
2650  private function CheckFieldPermissions($User, $Field, $CheckType)
2651  {
2652  # checks against invalid resources should always fail
2653  if ($this->Status() !== 1) { return FALSE; }
2654 
2655  # get field object (if not supplied)
2656  if (!($Field instanceof MetadataField))
2657  {
2658  try
2659  {
2660  $Field = $this->Schema()->GetField($Field);
2661  }
2662  catch (InvalidArgumentException $Exception)
2663  {
2664  # (user cannot view/author/edit if field was invalid)
2665  return FALSE;
2666  }
2667  }
2668 
2669  # construct a key to use for our permissions cache
2670  $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2671 
2672  # if we don't have a cahced value, compute one
2673  if (!isset($this->PermissionCache[$CacheKey]))
2674  {
2675  # if field is enabled and editable, do permission check
2676  if ($Field->Enabled() &&
2677  ($CheckType == "View" || $Field->Editable()))
2678  {
2679  # be sure schema privs allow View/Edit/Author for this resource
2680  $SchemaCheckFn = "UserCan".$CheckType;
2681  if ($this->$SchemaCheckFn($User))
2682  {
2683  # get appropriate privilege set for field
2684  $PermsFn = $CheckType."ingPrivileges";
2685  $FieldPrivs = $Field->$PermsFn();
2686 
2687  # user can View/Edit/Author if privileges are greater than field set
2688  $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2689  }
2690  else
2691  {
2692  $CheckResult = FALSE;
2693  }
2694  }
2695  else
2696  {
2697  $CheckResult = FALSE;
2698  }
2699 
2700  # allow plugins to modify result of permission check
2701  $SignalResult = $GLOBALS["AF"]->SignalEvent(
2702  "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2703  "Field" => $Field,
2704  "Resource" => $this,
2705  "User" => $User,
2706  "Can".$CheckType => $CheckResult));
2707  $CheckResult = $SignalResult["Can".$CheckType];
2708 
2709  # save the result of this check in our cache
2710  $this->PermissionCache[$CacheKey] = $CheckResult;
2711  }
2712 
2713  # return cached permission value
2714  return $this->PermissionCache[$CacheKey];
2715  }
2716 
2720  private function UpdateCumulativeRating()
2721  {
2722  # grab totals from DB
2723  $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2724  ."SUM(Rating) AS Total FROM ResourceRatings "
2725  ."WHERE ResourceId = ".$this->Id);
2726  $Record = $this->DB->FetchRow();
2727 
2728  # calculate new cumulative rating
2729  $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
2730 
2731  # save new cumulative rating in DB
2732  $this->DB->Query("UPDATE Resources "
2733  ."SET CumulativeRating = ".$this->CumulativeRating." "
2734  ."WHERE ResourceId = ".$this->Id);
2735  }
2736 
2748  private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2749  {
2750  # We should ignore duplicate key errors when doing inserts:
2751  $this->DB->SetQueryErrorsToIgnore( array(
2752  "/INSERT INTO ".$TableName."/" =>
2753  "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2754 
2755  # start out assuming no association will be added
2756  $AssociationAdded = FALSE;
2757 
2758  # convert new value to array if necessary
2759  $Values = is_array($Value) ? $Value : array($Value);
2760 
2761  # for each new value
2762  foreach ($Values as $Value)
2763  {
2764  # retrieve ID from value if necessary
2765  if (is_object($Value)) { $Value = $Value->Id(); }
2766 
2767  # Try to insert a new entry for this association.
2768  $this->DB->Query("INSERT INTO ".$TableName." SET"
2769  ." ResourceId = ".intval($this->Id)
2770  .", ".$FieldName." = ".intval($Value)
2771  .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2772 
2773  # If the insert ran without a duplicate key error,
2774  # then we added an assocation:
2775  if ($this->DB->IgnoredError() === FALSE)
2776  {
2777  $AssociationAdded = TRUE;
2778  }
2779  }
2780 
2781  # Clear ignored errors:
2782  $this->DB->SetQueryErrorsToIgnore( NULL );
2783 
2784  # report to caller whether association was added
2785  return $AssociationAdded;
2786  }
2787 
2799  private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2800  {
2801  # start out assuming no association will be removed
2802  $AssociationRemoved = FALSE;
2803 
2804  # convert value to array if necessary
2805  $Values = is_array($Value) ? $Value : array($Value);
2806 
2807  # for each value
2808  foreach ($Values as $Value)
2809  {
2810  # retrieve ID from value if necessary
2811  if (is_object($Value)) { $Value = $Value->Id(); }
2812 
2813  # remove any intersections with target ID from DB
2814  $this->DB->Query("DELETE FROM ".$TableName
2815  ." WHERE ResourceId = ".intval($this->Id)
2816  .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2817  ." AND ".$FieldName." = ".intval($Value));
2818  if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2819  }
2820 
2821  # report to caller whether association was added
2822  return $AssociationRemoved;
2823  }
2824 
2831  private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
2832  {
2833  # retrieve list of entries for this field and resource
2834  $Entries = $this->Get($Field);
2835 
2836  # divide them into chunks of not more than 100
2837  foreach (array_chunk($Entries, 100, TRUE) as $Chunk)
2838  {
2839  # remove assocations from this chunk
2840  $this->DB->Query("DELETE FROM ".$TableName
2841  ." WHERE ResourceId = ".intval($this->Id)
2842  ." AND ".$TargetFieldName." IN "
2843  ."(".implode(",", array_keys($Chunk)).")");
2844  }
2845  }
2846 }
GetByField($FieldNameOrObject, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Old method for retrieving values, deprecated in favor of Get().
Definition: Resource.php:796
UserCanView(User $User, $AllowHooksToModify=TRUE)
Determine if the given user can view the resource, e.g., on the full record page. ...
Definition: Resource.php:2421
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:1130
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1757
Metadata schema (in effect a Factory class for MetadataField).
Abstraction for forum messages and resource comments.
Definition: Message.php:15
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:2500
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2512
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:834
Id()
Retrieve numerical resource ID.
Definition: Resource.php:293
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2477
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1779
GetViewPageUrl()
Retrieve view page URL for this resource.
Definition: Resource.php:392
Rating($NewRating=NULL, $UserId=NULL)
Get/set rating by a specific user for resource.
Definition: Resource.php:2278
Definition: User.php:41
Status()
Retrieve result of last operation if available.
Definition: Resource.php:284
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2391
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2247
GetQualifier($FieldName, $ReturnObject=TRUE)
Retrieve qualifier by field name.
Definition: Resource.php:898
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:311
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:2432
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:760
Comments()
Get comments for resource.
Definition: Resource.php:2368
CWIS-specific user factory class.
Get($Field, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field name or field object.
Definition: Resource.php:416
static GetSchemaForResource($ResourceId)
Get schema ID for specified resource(s).
Definition: Resource.php:2529
Factory for manipulating File objects.
Definition: FileFactory.php:13
GetQualifierByFieldId($FieldId, $ReturnObject=TRUE)
Retrieve qualifier by field ID.
Definition: Resource.php:912
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:2488
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1825
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2454
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2443
GetByFieldId($FieldId, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field ID.
Definition: Resource.php:816
IsTempResource($NewSetting=NULL)
Get/set whether resource is a temporary record.
Definition: Resource.php:322
SetByField($Field, $NewValue)
Method replaced by Resource::Set(), preserved for backward compatibility.
Definition: Resource.php:1735
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:880
Represents a "resource" in CWIS.
Definition: Resource.php:13
GetQualifierByField($Field, $ReturnObject=TRUE)
Retrieve qualifier by Field object.
Definition: Resource.php:926
ClearByFieldId($FieldId, $ValueToClear=NULL)
Clear field value specified by field ID.
Definition: Resource.php:1813
const CLASSSTAT_OK
Status code indicating operation completed successfully.
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1768
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:302
ScaledCumulativeRating()
Return cumulative rating scaled to 1/10th.
Definition: Resource.php:2231
Set($Field, $NewValue, $Reset=FALSE)
Set value using field name or field object.
Definition: Resource.php:1165
const UPDATEMETHOD_ONRECORDCREATE
static Create($SchemaId)
Create a new resource.
Definition: Resource.php:66
UserCanViewField($User, $FieldOrFieldName)
Check whether user is allowed to view specified metadata field.
Definition: Resource.php:2466
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1747
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:2189
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:2177
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:2222
FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
Determine if the value for a field is set.
Definition: Resource.php:1060
Delete()
Remove resource (and accompanying associations) from database and delete any associated files...
Definition: Resource.php:169