CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

Resource.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Resource.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9
13 class Resource extends Item
14 {
15
16 # ---- PUBLIC INTERFACE --------------------------------------------------
17
25 public function __construct($ResourceId)
26 {
27 # call parent contstructor to load info from DB
28 parent::__construct($ResourceId);
29
30 # load local attributes from database value cache
31 $this->CumulativeRating = $this->ValueCache["CumulativeRating"];
32
33 # load our local metadata schema
34 $this->SchemaId = $this->ValueCache["SchemaId"];
35 if (!isset(self::$Schemas[$this->SchemaId]))
36 {
37 self::$Schemas[$this->SchemaId] =
38 new MetadataSchema($this->SchemaId);
39 }
40 }
41
48 public static function Create($SchemaId)
49 {
50 # clean out any temp resource records more than three days old
51 $RFactory = new ResourceFactory();
52 $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
53
54 # lock DB tables to prevent next ID from being grabbed
55 $DB = new Database;
56 $DB->Query("LOCK TABLES Resources WRITE");
57
58 # find next temp resource ID
59 $Id = $RFactory->GetNextTempItemId();
60
61 # write out new resource record with temp resource ID
62 # Set DateLastModified = NOW() to avoid being pruned as a
63 # stale temp resource.
64 $DB->Query(
65 "INSERT INTO Resources
66 SET `ResourceId` = '".intval($Id)."',
67 `SchemaId` = '".intval($SchemaId)."',
68 `DateLastModified` = NOW() " );
69
70 # release DB tables
71 $DB->Query("UNLOCK TABLES");
72
73 # create new Resource object
74 $Resource = new Resource($Id);
75
76 # set some additional fields for default resources
77 if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
78 {
79 $Resource->Set("Date Of Record Creation", date("Y-m-d H:i:s"));
80 $Resource->Set("Date Last Modified", date("Y-m-d H:i:s"));
81 if ($GLOBALS["G_User"]->IsLoggedIn())
82 {
83 $Resource->Set("Added By Id", $GLOBALS["G_User"]->Id());
84 $Resource->Set("Last Modified By Id", $GLOBALS["G_User"]->Id());
85 }
86 }
87
88 # for each field that can have a default value
89 $Schema = new MetadataSchema($SchemaId);
90 $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
91 |MetadataSchema::MDFTYPE_TEXT
92 |MetadataSchema::MDFTYPE_FLAG
93 |MetadataSchema::MDFTYPE_NUMBER
94 |MetadataSchema::MDFTYPE_POINT);
95 foreach ($Fields as $Field)
96 {
97 # if there is a default value available
98 $DefaultValue = $Field->DefaultValue();
99 if ($DefaultValue !== NULL)
100 {
101 # if the default value is an array
102 if (is_array($DefaultValue))
103 {
104 # if there are values in the array
105 if (!empty($DefaultValue))
106 {
107 # flip values for Set() if necessary
108 if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
109 {
110 $DefaultValue = array_flip($DefaultValue);
111 }
112
113 # set default value
114 $Resource->Set($Field, $DefaultValue);
115 }
116 }
117 else
118 {
119 # set default value
120 $Resource->Set($Field, $DefaultValue);
121 }
122 }
123 }
124
125 $Resource->UpdateAutoupdateFields(
126 MetadataField::UPDATEMETHOD_ONRECORDCREATE,
127 $GLOBALS["G_User"]);
128
129 # signal resource creation
130 $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
131 "Resource" => $Resource,
132 ));
133
134 # return new Resource object to caller
135 return $Resource;
136 }
137
142 public function Delete()
143 {
144 global $G_SysConfig;
145
146 # signal that resource deletion is about to occur
147 global $AF;
148 $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
149 "Resource" => $this,
150 ));
151
152 # grab list of classifications
153 $Classifications = $this->Classifications();
154
155 # delete resource/classification intersections
156 $DB = $this->DB;
157 $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
158
159 # for each classification type
160 foreach ($Classifications as $ClassType => $ClassesOfType)
161 {
162 # for each classification of that type
163 foreach ($ClassesOfType as $ClassId => $ClassName)
164 {
165 # recalculate resource count for classification
166 $Class = new Classification($ClassId);
167 $Class->RecalcResourceCount();
168 }
169 }
170
171 # delete resource references
172 $DB->Query("
173 DELETE FROM ReferenceInts
174 WHERE SrcResourceId = '".addslashes($this->Id())."'
175 OR DstResourceId = '".addslashes($this->Id())."'");
176
177 # delete resource/name intersections
178 $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
179
180 # delete resource/user intersections
181 $DB->Query("DELETE FROM ResourceUserInts WHERE ResourceId = ".$this->Id());
182
183 # get the list of all images associated with this resource
184 $DB->Query("SELECT ImageId FROM ResourceImageInts"
185 ." WHERE ResourceId = ".intval($this->Id()));
186 $ImageIds = $DB->FetchColumn("ImageId");
187
188 # disassociate this resource from all images
189 $DB->Query("DELETE FROM ResourceImageInts"
190 ." WHERE ResourceId = ".intval($this->Id()));
191
192 # delete any images that no longer belong to any resources
193 foreach ($ImageIds as $ImageId)
194 {
195 $DB->Query("SELECT ResourceId FROM ResourceImageInts"
196 ." WHERE ImageId = ".intval($ImageId) );
197 if ($DB->NumRowsSelected() == 0)
198 {
199 $Image = new SPTImage($ImageId);
200 $Image->Delete();
201 }
202 }
203
204 # delete any associated files
205 $Factory = new FileFactory(NULL);
206 $Files = $Factory->GetFilesForResource($this->Id());
207 foreach ($Files as $File)
208 {
209 $File->Delete();
210 }
211
212 # delete resource ratings
213 $DB->Query("DELETE FROM ResourceRatings WHERE ResourceId = ".$this->Id());
214
215 # delete resource record from database
216 $DB->Query("DELETE FROM Resources WHERE ResourceId = ".$this->Id());
217
218 # drop item from search engine and recommender system
219 if ($G_SysConfig->SearchDBEnabled())
220 {
221 $SearchEngine = new SPTSearchEngine();
222 $SearchEngine->DropItem($this->Id());
223 }
224 if ($G_SysConfig->RecommenderDBEnabled())
225 {
226 $Recommender = new SPTRecommender();
227 $Recommender->DropItem($this->Id());
228 }
229
230 # get the folders containing the resource
231 $FolderFactory = new FolderFactory();
232 $Folders = $FolderFactory->GetFoldersContainingItem(
233 $this->Id,
234 "Resource");
235
236 # drop the resource from each folder it belongs to
237 foreach ($Folders as $Folder)
238 {
239 # mixed item type folder
240 if ($Folder->ContainsItem($this->Id, "Resource"))
241 {
242 $Folder->RemoveItem($this->Id, "Resource");
243 }
244
245 # single item type folder
246 else
247 {
248 $Folder->RemoveItem($this->Id);
249 }
250 }
251
252 # delete any resource comments
253 $DB->Query("DELETE FROM Messages WHERE ParentId = ".$this->Id);
254 }
255
262 public function UpdateAutoupdateFields($UpdateType, $User=NULL)
263 {
264 # update all the timestamp fields as required
265 $TimestampFields = $this->Schema()->GetFields(
266 MetadataSchema::MDFTYPE_TIMESTAMP);
267 foreach ($TimestampFields as $Field)
268 {
269 if ($Field->UpdateMethod() == $UpdateType)
270 {
271 $this->Set($Field, "now");
272 }
273 }
274
275 # if a user was provided, update the user fields as well
276 if (!is_null($User) && !$User->IsAnonymous())
277 {
278 $UserFields = $this->Schema()->GetFields(
279 MetadataSchema::MDFTYPE_USER);
280 foreach ($UserFields as $Field)
281 {
282 if ($Field->UpdateMethod() == $UpdateType)
283 {
284 $this->Set($Field, $User);
285 }
286 }
287 }
288 }
289
294 public function Id()
295 {
296 return $this->Id;
297 }
298
303 public function SchemaId()
304 {
305 return $this->SchemaId;
306 }
307
312 public function Schema()
313 {
314 return self::$Schemas[$this->SchemaId];
315 }
316
323 public function IsTempResource($NewSetting = NULL)
324 {
325 # if new temp resource setting supplied
326 if (!is_null($NewSetting))
327 {
328 # if caller requested to switch
329 $DB = $this->DB;
330 if ((($this->Id() < 0) && ($NewSetting == FALSE))
331 || (($this->Id() >= 0) && ($NewSetting == TRUE)))
332 {
333 $Factory = new ResourceFactory($this->SchemaId);
334
335 # lock DB tables to prevent next ID from being grabbed
336 $DB->Query("LOCK TABLES Resources WRITE");
337
338 # get next resource ID as appropriate
339 $OldResourceId = $this->Id;
340 if ($NewSetting == TRUE)
341 {
342 $this->Id = $Factory->GetNextTempItemId();
343 }
344 else
345 {
346 $this->Id = $Factory->GetNextItemId();
347 }
348
349 # change resource ID
350 $DB->Query("UPDATE Resources SET ResourceId = ".
351 $this->Id. " WHERE ResourceId = ".$OldResourceId);
352
353 # release DB tables
354 $DB->Query("UNLOCK TABLES");
355
356 # change associations
357 unset($this->ClassificationCache);
358 $DB->Query("UPDATE ResourceClassInts SET ResourceId = ".
359 $this->Id. " WHERE ResourceId = ".$OldResourceId);
360 unset($this->ControlledNameCache);
361 unset($this->ControlledNameVariantCache);
362 $DB->Query("UPDATE ResourceNameInts SET ResourceId = ".
363 $this->Id. " WHERE ResourceId = ".$OldResourceId);
364 $DB->Query("UPDATE Files SET ResourceId = ".
365 $this->Id. " WHERE ResourceId = ".$OldResourceId);
366 $DB->Query("UPDATE ReferenceInts SET SrcResourceId = ".
367 $this->Id. " WHERE SrcResourceId = ".$OldResourceId);
368 $DB->Query("UPDATE ResourceImageInts SET ResourceId = ".
369 $this->Id. " WHERE ResourceId = ".$OldResourceId);
370 $DB->Query("UPDATE ResourceUserInts SET ResourceId = ".
371 $this->Id. " WHERE ResourceId = ".$OldResourceId);
372 $DB->Query("UPDATE ResourceRatings SET ResourceId = ".
373 $this->Id. " WHERE ResourceId = ".$OldResourceId);
374
375 # signal event as appropriate
376 if ($NewSetting === FALSE)
377 {
378 $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_ADD", array(
379 "Resource" => $this,
380 ));
381 }
382 }
383 }
384
385 # report to caller whether we are a temp resource
386 return ($this->Id() < 0) ? TRUE : FALSE;
387 }
388
389
390 # --- Generic Attribute Retrieval Methods -------------------------------
391
396 public function GetViewPageUrl()
397 {
398 # put our Id into the ViewPage from our schema
399 $Url = str_replace(
400 "\$ID", $this->Id(),
401 $this->Schema()->ViewPage());
402
403 # return clean url, if one is available
404 return $GLOBALS["AF"]->GetCleanUrlForPath($Url);
405 }
406
420 public function Get($Field, $ReturnObject = FALSE, $IncludeVariants = FALSE)
421 {
422 # load field object if not already supplied
423 $Field = is_object($Field) ? $Field : $this->Schema()->GetField($Field);
424
425 if ($Field->SchemaId() != $this->SchemaId())
426 {
427 throw new Exception("Attempt to get a value for a field"
428 ." from a different schema."
429 ." (Field: ".$Field->Name()." [".$Field->Id()
430 ."], Field Schema: ".$Field->SchemaId()
431 .", Resource Schema: ".$this->SchemaId()
432 .")");
433 }
434
435 # grab database field name
436 $DBFieldName = $Field->DBFieldName();
437
438 # format return value based on field type
439 switch ($Field->Type())
440 {
441 case MetadataSchema::MDFTYPE_TEXT:
442 case MetadataSchema::MDFTYPE_PARAGRAPH:
443 case MetadataSchema::MDFTYPE_URL:
444 $ReturnValue = isset($this->ValueCache[$DBFieldName])
445 ? (string)$this->ValueCache[$DBFieldName] : NULL;
446 break;
447
448 case MetadataSchema::MDFTYPE_NUMBER:
449 $ReturnValue = isset($this->ValueCache[$DBFieldName])
450 ? (int)$this->ValueCache[$DBFieldName] : NULL;
451 break;
452
453 case MetadataSchema::MDFTYPE_FLAG:
454 $ReturnValue = isset($this->ValueCache[$DBFieldName])
455 ? (bool)$this->ValueCache[$DBFieldName] : NULL;
456 break;
457
458 case MetadataSchema::MDFTYPE_POINT:
459 if (is_null($this->ValueCache[$DBFieldName."X"]) &&
460 is_null($this->ValueCache[$DBFieldName."Y"]))
461 {
462 $ReturnValue = ["X" => NULL, "Y" => NULL];
463 }
464 else
465 {
466 $ReturnValue = [
467 "X" => (float)$this->ValueCache[$DBFieldName."X"],
468 "Y" => (float)$this->ValueCache[$DBFieldName."Y"]
469 ];
470 }
471 break;
472
473 case MetadataSchema::MDFTYPE_DATE:
474 $Date = new Date($this->ValueCache[$DBFieldName."Begin"],
475 $this->ValueCache[$DBFieldName."End"],
476 $this->ValueCache[$DBFieldName."Precision"]);
477 if ($ReturnObject)
478 {
479 $ReturnValue = $Date;
480 }
481 else
482 {
483 $ReturnValue = $Date->Formatted();
484 }
485 break;
486
487 case MetadataSchema::MDFTYPE_TIMESTAMP:
488 $ReturnValue = $this->ValueCache[$DBFieldName];
489 break;
490
491 case MetadataSchema::MDFTYPE_TREE:
492 # start with empty array
493 $ReturnValue = array();
494
495 # if classification cache has not been loaded
496 if (!isset($this->ClassificationCache))
497 {
498 # load all classifications associated with this resource into cache
499 $this->ClassificationCache = array();
500 $this->DB->Query(
501 "SELECT Classifications.ClassificationId,"
502 ." Classifications.FieldId,ClassificationName"
503 ." FROM ResourceClassInts, Classifications"
504 ." WHERE ResourceClassInts.ResourceId = ".$this->Id
505 ." AND ResourceClassInts.ClassificationId"
506 ." = Classifications.ClassificationId");
507 while ($Record = $this->DB->FetchRow())
508 {
509 $ClassId = $Record["ClassificationId"];
510 $this->ClassificationCache[$ClassId]["Name"]
511 = $Record["ClassificationName"];
512 $this->ClassificationCache[$ClassId]["FieldId"]
513 = $Record["FieldId"];
514 }
515 }
516 # for each entry in classification cache
517 foreach ($this->ClassificationCache as
518 $ClassificationId => $ClassificationInfo)
519 {
520 # if classification ID matches field we are looking for
521 if ($ClassificationInfo["FieldId"] == $Field->Id())
522 {
523 # add field to result
524 if ($ReturnObject)
525 {
526 $ReturnValue[$ClassificationId] =
527 new Classification($ClassificationId);
528 }
529 else
530 {
531 $ReturnValue[$ClassificationId] = $ClassificationInfo["Name"];
532 }
533 }
534 }
535 break;
536
537 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
538 case MetadataSchema::MDFTYPE_OPTION:
539 # start with empty array
540 $ReturnValue = array();
541
542 # if controlled name cache has not been loaded
543 if (!isset($this->ControlledNameCache))
544 {
545 # load all controlled names associated with this resource into cache
546 $this->ControlledNameCache = array();
547 $this->DB->Query(
548 "SELECT ControlledNames.ControlledNameId,"
549 ." ControlledNames.FieldId,ControlledName"
550 ." FROM ResourceNameInts, ControlledNames"
551 ." WHERE ResourceNameInts.ResourceId = ".$this->Id
552 ." AND ResourceNameInts.ControlledNameId"
553 ." = ControlledNames.ControlledNameId"
554 ." ORDER BY ControlledNames.ControlledName ASC");
555 while ($Record = $this->DB->FetchRow())
556 {
557 $CNameId = $Record["ControlledNameId"];
558 $this->ControlledNameCache[$CNameId]["Name"]
559 = $Record["ControlledName"];
560 $this->ControlledNameCache[$CNameId]["FieldId"]
561 = $Record["FieldId"];
562 }
563 }
564
565 # if variant names requested and variant name cache has not been loaded
566 if ($IncludeVariants && !isset($this->ControlledNameVariantCache))
567 {
568 # load all controlled names associated with this resource into cache
569 $this->ControlledNameVariantCache = array();
570 $this->DB->Query("SELECT ControlledNames.ControlledNameId,"
571 ." ControlledNames.FieldId,"
572 ." ControlledName, VariantName"
573 ." FROM ResourceNameInts, ControlledNames, VariantNames"
574 ." WHERE ResourceNameInts.ResourceId = ".$this->Id
575 ." AND ResourceNameInts.ControlledNameId"
576 ." = ControlledNames.ControlledNameId"
577 ." AND VariantNames.ControlledNameId"
578 ." = ControlledNames.ControlledNameId");
579 while ($Record = $this->DB->FetchRow())
580 {
581 $this->ControlledNameVariantCache[$Record["ControlledNameId"]][]
582 = $Record["VariantName"];
583 }
584 }
585
586 # for each entry in controlled name cache
587 foreach ($this->ControlledNameCache as
588 $CNameId => $ControlledNameInfo)
589 {
590 # if controlled name type matches field we are looking for
591 if ($ControlledNameInfo["FieldId"] == $Field->Id())
592 {
593 # if objects requested
594 if ($ReturnObject)
595 {
596 $ReturnValue[$CNameId] =
597 new ControlledName($CNameId);
598 }
599 else
600 {
601 # if variant names requested
602 if ($IncludeVariants)
603 {
604 # add field to result
605 $ReturnValue[] = $ControlledNameInfo["Name"];
606
607 # add any variant names to result
608 if (isset($this->ControlledNameVariantCache[$CNameId]))
609 {
610 $ReturnValue = array_merge(
611 $ReturnValue,
612 $this->ControlledNameVariantCache[$CNameId]);
613 }
614 }
615 else
616 {
617 # add field with index to result
618 $ReturnValue[$CNameId] =
619 $ControlledNameInfo["Name"];
620 }
621 }
622 }
623 }
624 break;
625
626 case MetadataSchema::MDFTYPE_USER:
627 # start out assuming no associated users
628 $ReturnValue = array();
629
630 # query the database to get the associated userids
631 $this->DB->Query(
632 "SELECT UserId FROM ResourceUserInts WHERE ".
633 "ResourceId=".intval($this->Id).
634 " AND FieldId=".intval($Field->Id())
635 ." AND UserId IN (SELECT UserId FROM APUsers)"
636 );
637 $UserIds = $this->DB->FetchColumn("UserId");
638
639 # convert each userid to either a name or a CWUser object
640 foreach ($UserIds as $UserId)
641 {
642 $User = new CWUser(intval($UserId));
643 if ($ReturnObject)
644 {
645 $ReturnValue[$UserId] = $User;
646 }
647 else
648 {
649 $ReturnValue[$UserId] = $User->Get("UserName");
650 }
651 }
652 break;
653
654 case MetadataSchema::MDFTYPE_IMAGE:
655 # start out assuming no images will be found
656 $ReturnValue = array();
657
658 # find all images associated with this resource
659 $this->DB->Query("SELECT ImageId FROM ResourceImageInts"
660 ." WHERE ResourceId = ".intval($this->Id())
661 ." AND FieldId = ".intval($Field->Id()));
662
663 # if images were found
664 if ($this->DB->NumRowsSelected())
665 {
666 # if we are to return an object
667 $ImageIds = $this->DB->FetchColumn("ImageId");
668 if ($ReturnObject)
669 {
670 # load array of Image objects for return value
671 foreach ($ImageIds as $ImageId)
672 {
673 $ReturnValue[$ImageId] = new SPTImage($ImageId);
674 }
675 }
676 else
677 {
678 # load array of Image ids for return value
679 $ReturnValue = $ImageIds;
680 }
681 }
682 break;
683
684 case MetadataSchema::MDFTYPE_FILE:
685 # retrieve files using factory
686 $Factory = new FileFactory($Field->Id());
687 $ReturnValue = $Factory->GetFilesForResource(
688 $this->Id, $ReturnObject);
689 break;
690
691 case MetadataSchema::MDFTYPE_REFERENCE:
692 # query for resource references
693 $this->DB->Query("
694 SELECT * FROM ReferenceInts
695 WHERE FieldId = '".addslashes($Field->Id())."'
696 AND SrcResourceId = '".addslashes($this->Id())."'");
697
698 $ReturnValue = array();
699
700 # return each reference as a Resource object
701 if ($ReturnObject)
702 {
703 $FoundErrors = FALSE;
704
705 while (FALSE !== ($Record = $this->DB->FetchRow()))
706 {
707 $ReferenceId = $Record["DstResourceId"];
708 $Reference = new Resource($ReferenceId);
709 $ReturnValue[$ReferenceId] = $Reference;
710 }
711 }
712
713 # return each reference as a resource ID
714 else
715 {
716 while (FALSE !== ($Record = $this->DB->FetchRow()))
717 {
718 $ReferenceId = $Record["DstResourceId"];
719 $ReturnValue[$ReferenceId] = $ReferenceId;
720 }
721 }
722 break;
723
724 default:
725 # ERROR OUT
726 throw new Exception("Attempt to retrieve "
727 ."unknown field type (".$Field->Type().")");
728 break;
729 }
730
731 # return formatted value to caller
732 return $ReturnValue;
733 }
734
754 public function GetForDisplay(
755 $FieldNameOrObject, $ReturnObject = TRUE, $IncludeVariants = FALSE)
756 {
757 # normalize metadata field for use by any hooked code
758 $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
759 : $this->Schema()->GetFieldByName($FieldNameOrObject);
760
761 # retrieve value
762 $Value = $this->Get($Field, $ReturnObject, $IncludeVariants);
763
764 # signal event to allowed hooked code to modify value
765 $SignalResult = $GLOBALS["AF"]->SignalEvent(
766 "EVENT_FIELD_DISPLAY_FILTER", array(
767 "Field" => $Field,
768 "Resource" => $this,
769 "Value" => $Value));
770
771 # return possibly modified value to caller
772 return $SignalResult["Value"];
773 }
774
790 public function GetByField($FieldNameOrObject,
791 $ReturnObject = FALSE, $IncludeVariants = FALSE)
792 {
793 return $this->Get($FieldNameOrObject, $ReturnObject, $IncludeVariants);
794 }
795
810 public function GetByFieldId(
811 $FieldId, $ReturnObject = FALSE, $IncludeVariants = FALSE)
812 {
813 return $this->Get($FieldId, $ReturnObject, $IncludeVariants);
814 }
815
828 public function GetAsArray($IncludeDisabledFields = FALSE, $ReturnObjects = TRUE)
829 {
830 # retrieve field info
831 $Fields = $this->Schema()->GetFields();
832
833 # for each field
834 foreach ($Fields as $Field)
835 {
836 # if field is enabled or caller requested disabled fields
837 if ($Field->Enabled() || $IncludeDisabledFields)
838 {
839 # retrieve info and add it to the array
840 $FieldStrings[$Field->Name()] = $this->Get($Field, $ReturnObjects);
841
842 # if field uses qualifiers
843 if ($Field->UsesQualifiers())
844 {
845 # get qualifier attributes and add to the array
846 $FieldStrings[$Field->Name()." Qualifier"] =
847 $this->GetQualifierByField($Field, $ReturnObjects);
848 }
849 }
850 }
851
852 # add in internal values
853 $FieldStrings["ResourceId"] = $this->Id();
854 $FieldStrings["CumulativeRating"] = $this->CumulativeRating();
855
856 # return array to caller
857 return $FieldStrings;
858 }
859
874 public function GetMapped(
875 $MappedName, $ReturnObject = FALSE, $IncludeVariants = FALSE)
876 {
877 $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
878 return $FieldId
879 ? $this->Get($FieldId, $ReturnObject, $IncludeVariants)
880 : NULL;
881 }
882
891 public function GetQualifier($FieldName, $ReturnObject = TRUE)
892 {
893 $Field = $this->Schema()->GetFieldByName($FieldName);
894 return $this->GetQualifierByField($Field, $ReturnObject);
895 }
896
905 public function GetQualifierByFieldId($FieldId, $ReturnObject = TRUE)
906 {
907 $Field = $this->Schema()->GetField($FieldId);
908 return ($Field) ? $this->GetQualifierByField($Field, $ReturnObject) : NULL;
909 }
910
919 public function GetQualifierByField($Field, $ReturnObject = TRUE)
920 {
921 # return NULL if field is invalid
922 if (!($Field instanceof MetadataField)) { return NULL; }
923
924 # assume no qualifiers if not otherwise determined
925 $ReturnValue = NULL;
926
927 # if field uses qualifiers
928 if ($Field->UsesQualifiers())
929 {
930 # retrieve qualifiers based on field type
931 switch ($Field->Type())
932 {
933 case MetadataSchema::MDFTYPE_TREE:
934 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
935 case MetadataSchema::MDFTYPE_OPTION:
936 # retrieve list of items
937 $Items = $this->Get($Field);
938
939 # if field uses item-level qualifiers
940 if ($Field->HasItemLevelQualifiers())
941 {
942 # determine general item name in DB
943 $TableName = ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
944 ? "Classification" : "ControlledName";
945
946 # for each item
947 foreach ($Items as $ItemId => $ItemName)
948 {
949 # look up qualifier for item
950 $QualId = $this->DB->Query(
951 "SELECT * FROM ".$TableName."s"
952 ." WHERE ".$TableName."Id = ".$ItemId,
953 "QualifierId");
954
955
956 if ($QualId > 0)
957 {
958 # if object was requested by caller
959 if ($ReturnObject)
960 {
961 # load qualifier and add to return value array
962 $ReturnValue[$ItemId] = new Qualifier($QualId);
963 }
964 else
965 {
966 # add qualifier ID to return value array
967 $ReturnValue[$ItemId] = $QualId;
968 }
969 }
970 else
971 {
972 # add NULL to return value array for this item
973 $ReturnValue[$ItemId] = NULL;
974 }
975 }
976 }
977 else
978 {
979 # for each item
980 foreach ($Items as $ItemId => $ItemName)
981 {
982 # if object was requested by caller
983 if ($ReturnObject)
984 {
985 # load default qualifier and add to return value array
986 $ReturnValue[$ItemId] = new Qualifier(
987 $Field->DefaultQualifier());
988 }
989 else
990 {
991 # add default qualifier ID to return value array
992 $ReturnValue[$ItemId] = $Field->DefaultQualifier();
993 }
994 }
995 }
996 break;
997
998 default:
999 # if field uses item-level qualifiers
1000 if ($Field->HasItemLevelQualifiers())
1001 {
1002 # if qualifier available
1003 if ($this->ValueCache[$Field->DBFieldName()."Qualifier"] > 0)
1004 {
1005 # if object was requested by caller
1006 $QFieldName = $Field->DBFieldName()."Qualifier";
1007 if ($ReturnObject)
1008 {
1009 # return qualifier for field
1010 $ReturnValue = new Qualifier(
1011 $this->ValueCache[$QFieldName]);
1012 }
1013 else
1014 {
1015 # return qualifier ID for field
1016 $ReturnValue = $this->ValueCache[$QFieldName];
1017 }
1018 }
1019 }
1020 else
1021 {
1022 # if default qualifier available
1023 if ($Field->DefaultQualifier() > 0)
1024 {
1025 # if object was requested by caller
1026 if ($ReturnObject)
1027 {
1028 # return default qualifier
1029 $ReturnValue = new Qualifier($Field->DefaultQualifier());
1030 }
1031 else
1032 {
1033 # return default qualifier ID
1034 $ReturnValue = $Field->DefaultQualifier();
1035 }
1036 }
1037 }
1038 break;
1039 }
1040 }
1041
1042 # return qualifier object or ID (or array of same) to caller
1043 return $ReturnValue;
1044 }
1045
1053 public function FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
1054 {
1055 # load field object if needed
1056 $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1057 : $this->Schema()->GetFieldByName($FieldNameOrObject);
1058
1059 # return no value found if we don't have a valid field
1060 if (!($Field instanceof MetadataField)) { return FALSE; }
1061
1062 # get the value
1063 $Value = $this->Get($Field);
1064
1065 # checks depend on the field type
1066 switch ($Field->Type())
1067 {
1068 case MetadataSchema::MDFTYPE_TEXT:
1069 case MetadataSchema::MDFTYPE_PARAGRAPH:
1070 case MetadataSchema::MDFTYPE_NUMBER:
1071 case MetadataSchema::MDFTYPE_URL:
1072 return !is_null($Value)
1073 && strlen($Value)
1074 && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1075
1076 case MetadataSchema::MDFTYPE_FLAG:
1077 return !is_null($Value)
1078 && strlen($Value);
1079
1080 case MetadataSchema::MDFTYPE_POINT:
1081 return !is_null($Value["X"])
1082 && !is_null($Value["Y"])
1083 && strlen(trim($Value["X"]))
1084 && strlen(trim($Value["Y"]));
1085
1086 case MetadataSchema::MDFTYPE_DATE:
1087 return !is_null($Value)
1088 && strlen(trim($Value))
1089 && $Value != "0000-00-00";
1090
1091 case MetadataSchema::MDFTYPE_TIMESTAMP:
1092 return !is_null($Value)
1093 && strlen(trim($Value))
1094 && $Value != "0000-00-00 00:00:00";
1095
1096 case MetadataSchema::MDFTYPE_TREE:
1097 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
1098 case MetadataSchema::MDFTYPE_OPTION:
1099 case MetadataSchema::MDFTYPE_FILE:
1100 case MetadataSchema::MDFTYPE_IMAGE:
1101 case MetadataSchema::MDFTYPE_REFERENCE:
1102 case MetadataSchema::MDFTYPE_USER:
1103 return count($Value) > 0 ? TRUE : FALSE;
1104
1105 default:
1106 return FALSE;
1107 }
1108 }
1109
1118 public function GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
1119 {
1120 $Result = array();
1121
1122 # get our target field and extract its values
1123 $Field = is_object($FieldNameOrObject) ? $FieldNameOrObject
1124 : $this->Schema()->GetField($FieldNameOrObject);
1125 $Images = $this->Get($Field, TRUE);
1126
1127 # iterate over our images getting URLs for each
1128 $Index = 0;
1129 foreach ($Images as $Image)
1130 {
1131 $Result[$Image->Id()] = $Image->GetImageUrlForResource(
1132 $this->Id(), $Field->Id(), $Index, $ImageSize);
1133 $Index++;
1134 }
1135
1136 return $Result;
1137 }
1138
1139 # --- Generic Attribute Setting Methods ---------------------------------
1140
1153 public function Set($Field, $NewValue, $Reset=FALSE)
1154 {
1155 # load field object if not already supplied
1156 $Field = is_object($Field) ? $Field
1157 : (is_numeric($Field) ? $this->Schema()->GetField($Field)
1158 : $this->Schema()->GetFieldByName($Field));
1159
1160 # return if we don't have a valid field
1161 if (!($Field instanceof MetadataField)) { return; }
1162
1163 if ($Field->SchemaId() != $this->SchemaId())
1164 {
1165 throw new Exception("Attempt to set a value for a field "
1166 ."from a different schema.");
1167 }
1168
1169 # grab commonly-used values for local use
1170 $DB = $this->DB;
1171 $ResourceId = $this->Id;
1172
1173 # grab database field name
1174 $DBFieldName = $Field->DBFieldName();
1175
1176 # Flag to deterimine if we've actually changed anything.
1177 $UpdateModTime = FALSE;
1178
1179 # store value in DB based on field type
1180 switch ($Field->Type())
1181 {
1182 case MetadataSchema::MDFTYPE_TEXT:
1183 case MetadataSchema::MDFTYPE_PARAGRAPH:
1184 case MetadataSchema::MDFTYPE_URL:
1185 if ($this->ValueCache[$DBFieldName] != $NewValue)
1186 {
1187 # save value directly to DB
1188 $DB->Query("UPDATE Resources SET `"
1189 .$DBFieldName."` = '".addslashes($NewValue)."' "
1190 ."WHERE ResourceId = ".$ResourceId);
1191
1192 # save value locally
1193 $this->ValueCache[$DBFieldName] = $NewValue;
1194 $UpdateModTime=TRUE;
1195 }
1196 break;
1197
1198 case MetadataSchema::MDFTYPE_NUMBER:
1199 if ( $this->ValueCache[$DBFieldName] != $NewValue )
1200 {
1201 # save value directly to DB
1202 if (is_null($NewValue))
1203 {
1204 $DB->Query("UPDATE Resources SET `"
1205 .$DBFieldName."` = NULL"
1206 ." WHERE ResourceId = ".$ResourceId);
1207 }
1208 else
1209 {
1210 $DB->Query("UPDATE Resources SET `"
1211 .$DBFieldName."` = ".intval($NewValue)
1212 ." WHERE ResourceId = ".$ResourceId);
1213 }
1214
1215 # save value locally
1216 $this->ValueCache[$DBFieldName] = $NewValue;
1217 $UpdateModTime = TRUE;
1218 }
1219 break;
1220
1221
1222 case MetadataSchema::MDFTYPE_POINT:
1223 if ($this->ValueCache[$DBFieldName."X"] != $NewValue["X"] ||
1224 $this->ValueCache[$DBFieldName."Y"] != $NewValue["Y"] )
1225 {
1226 if (is_null($NewValue))
1227 {
1228 $DB->Query("UPDATE Resources SET "
1229 ."`".$DBFieldName."X` = NULL, "
1230 ."`".$DBFieldName."Y` = NULL "
1231 ."WHERE ResourceId = ".$ResourceId);
1232 $this->ValueCache[$DBFieldName."X"] = NULL;
1233 $this->ValueCache[$DBFieldName."Y"] = NULL;
1234 }
1235 else
1236 {
1237 $DB->Query("UPDATE Resources SET "
1238 ."`".$DBFieldName."X` = " .(strlen($NewValue["X"])
1239 ? "'".$NewValue["X"]."'" : "NULL").", "
1240 ."`".$DBFieldName."Y` = ".(strlen($NewValue["Y"])
1241 ? "'".$NewValue["Y"]."'" : "NULL")
1242 ." WHERE ResourceId = ".$ResourceId);
1243
1244 $Digits = $Field->PointDecimalDigits();
1245
1246 $this->ValueCache[$DBFieldName."X"] =
1247 strlen($NewValue["X"]) ?
1248 round($NewValue["X"], $Digits) : NULL;
1249 $this->ValueCache[$DBFieldName."Y"] =
1250 strlen($NewValue["Y"]) ?
1251 round($NewValue["Y"], $Digits) : NULL;
1252 }
1253 $UpdateModTime = TRUE;
1254 }
1255 break;
1256
1257 case MetadataSchema::MDFTYPE_FLAG:
1258 if ($this->ValueCache[$DBFieldName] != $NewValue)
1259 {
1260 # save value directly to DB
1261 if (is_null($NewValue))
1262 {
1263 $DB->Query("UPDATE Resources SET `"
1264 .$DBFieldName."` = NULL"
1265 ." WHERE ResourceId = ".$ResourceId);
1266 }
1267 else
1268 {
1269 $NewValue = $NewValue ? "1" : "0";
1270 $DB->Query("UPDATE Resources SET `"
1271 .$DBFieldName."` = ".$NewValue
1272 ." WHERE ResourceId = ".$ResourceId);
1273 }
1274
1275 $this->ValueCache[$DBFieldName] = $NewValue;
1276
1277 $UpdateModTime = TRUE;
1278 }
1279 break;
1280
1281 case MetadataSchema::MDFTYPE_USER:
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
1336 case MetadataSchema::MDFTYPE_DATE:
1337 if (is_null($NewValue))
1338 {
1339 if (!is_null($this->ValueCache[$DBFieldName."Begin"]) ||
1340 !is_null($this->ValueCache[$DBFieldName."End"]) ||
1341 !is_null($this->ValueCache[$DBFieldName."Precision"]))
1342 {
1343 # clear date object values in DB
1344 $DB->Query("UPDATE Resources SET "
1345 .$DBFieldName."Begin = '', "
1346 .$DBFieldName."End = '', "
1347 .$DBFieldName."Precision = '' "
1348 ."WHERE ResourceId = ".$ResourceId);
1349
1350 # clear value locally
1351 $this->ValueCache[$DBFieldName."Begin"] = NULL;
1352 $this->ValueCache[$DBFieldName."End"] = NULL;
1353 $this->ValueCache[$DBFieldName."Precision"] = NULL;
1354 $UpdateModTime=TRUE;
1355 }
1356 }
1357 else
1358 {
1359
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->ValueCache[$DBFieldName."Begin"],
1374 $this->ValueCache[$DBFieldName."End"],
1375 $this->ValueCache[$DBFieldName."Precision"]);
1376
1377 if ($OldDate->BeginDate() != $Date->BeginDate() ||
1378 $OldDate->EndDate() != $Date->EndDate() ||
1379 $OldDate->Precision() != $Date->Precision() )
1380 {
1381 # extract values from date object and store in DB
1382 $BeginDate = !is_null($Date->BeginDate()) ?
1383 "'".$Date->BeginDate()."'" : "NULL" ;
1384 $EndDate = !is_null($Date->EndDate()) ?
1385 "'".$Date->EndDate()."'" : "NULL" ;
1386
1387 $DB->Query("UPDATE Resources SET "
1388 .$DBFieldName."Begin = ".$BeginDate.", "
1389 .$DBFieldName."End = ".$EndDate.", "
1390 .$DBFieldName."Precision = '".$Date->Precision()."' "
1391 ."WHERE ResourceId = ".$ResourceId);
1392
1393 # save values locally
1394 $this->ValueCache[$DBFieldName."Begin"] = $Date->BeginDate();
1395 $this->ValueCache[$DBFieldName."End"] = $Date->EndDate();
1396 $this->ValueCache[$DBFieldName."Precision"] = $Date->Precision();
1397 $UpdateModTime=TRUE;
1398 }
1399 }
1400 break;
1401
1402 case MetadataSchema::MDFTYPE_TIMESTAMP:
1403 if (is_null($NewValue) || !strlen(trim($NewValue)))
1404 {
1405 $DateValue = $NewValue;
1406
1407 if (!is_null($this->ValueCache[$DBFieldName]))
1408 {
1409 # save value directly to DB
1410 $DB->Query("UPDATE Resources SET "
1411 ."`".$DBFieldName."` = NULL "
1412 ."WHERE ResourceId = ".$ResourceId);
1413 $UpdateModTime = TRUE;
1414 }
1415 }
1416 else
1417 {
1418 # assume value is date and use directly
1419 $TimestampValue = strtotime($NewValue);
1420
1421 # use the new value if the date is valid
1422 if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1423 {
1424 $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1425
1426 if ($this->ValueCache[$DBFieldName] != $DateValue)
1427 {
1428 # save value directly to DB
1429 $DB->Query("UPDATE Resources SET "
1430 ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1431 ."WHERE ResourceId = ".$ResourceId);
1432 $UpdateModTime=TRUE;
1433 }
1434 }
1435
1436 # continue using the old value if invalid
1437 else
1438 {
1439 $DateValue = $this->Get($Field);
1440 }
1441 }
1442
1443 # save value locally
1444 $this->ValueCache[$DBFieldName] = $DateValue;
1445 break;
1446
1447 case MetadataSchema::MDFTYPE_TREE:
1448 $OldValue = $this->Get($Field);
1449
1450 # if incoming value is array
1451 if (is_array($NewValue))
1452 {
1453 if ($OldValue != $NewValue)
1454 {
1455 if ($Reset)
1456 {
1457 # remove values that were in the old value
1458 # but not the new one
1459 $ToRemove = array_diff(array_keys($OldValue),
1460 array_keys($NewValue));
1461 foreach ($ToRemove as $ClassificationId)
1462 {
1463 $this->RemoveAssociation("ResourceClassInts",
1464 "ClassificationId",
1465 $ClassificationId);
1466 $Class = new Classification($ClassificationId);
1467 $Class->RecalcResourceCount();
1468 }
1469 }
1470
1471 # for each element of array
1472 foreach ($NewValue as
1473 $ClassificationId => $ClassificationName)
1474 {
1475 $Class = new Classification($ClassificationId);
1476 if ($Class->FieldId() == $Field->Id())
1477 {
1478 # associate with resource if not already associated
1479 if ($this->AddAssociation("ResourceClassInts",
1480 "ClassificationId", $ClassificationId))
1481 {
1482 $Class->UpdateLastAssigned();
1483 $Class->RecalcResourceCount();
1484 }
1485 }
1486 else
1487 {
1488 throw new Exception(
1489 "Attempting to store classification from "
1490 ."Field ".$Class->FieldId()." into Field "
1491 .$Field->Id() );
1492 }
1493
1494 }
1495
1496 $UpdateModTime=TRUE;
1497 }
1498 }
1499 else
1500 {
1501 # associate with resource if not already associated
1502 if (is_object($NewValue))
1503 {
1504 $Class = $NewValue;
1505 $NewValue = $Class->Id();
1506 }
1507 else
1508 {
1509 $Class = new Classification($NewValue);
1510 }
1511
1512 if (!array_key_exists($Class->Id(), $OldValue))
1513 {
1514
1515 $this->AddAssociation("ResourceClassInts",
1516 "ClassificationId",
1517 $NewValue);
1518 $Class->UpdateLastAssigned();
1519 $Class->RecalcResourceCount();
1520 $UpdateModTime=TRUE;
1521 }
1522 }
1523
1524 # clear our classification cache
1525 if ($UpdateModTime)
1526 {
1527 unset($this->ClassificationCache);
1528 }
1529 break;
1530
1531 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
1532 case MetadataSchema::MDFTYPE_OPTION:
1533 $OldValue = $this->Get($Field);
1534
1535 # input to Set() for these fields is one of
1536 # 1. an int specifying a ControlledNameId
1537 # 2. a ControlledName object
1538 # 3. an array with keys giving Ids and values giving ControlledNames
1539 #
1540 # normalize 1 and 2 into 3 for simplicity of processing
1541 if (is_object($NewValue) || !is_array($NewValue) )
1542 {
1543 if (!is_object($NewValue))
1544 {
1545 $NewValue = new ControlledName($NewValue);
1546 }
1547
1548 $TmpValue = array();
1549 $TmpValue[$NewValue->Id()] = $NewValue->Name();
1550
1551 $NewValue = $TmpValue;
1552 }
1553
1554 # if this is a unique field, only accept the first of the options given
1555 # NB: all ControlledNames implicitly AllowMultiple
1556 if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1557 $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1558 {
1559 $NewValue = array_slice($NewValue, 0, 1, TRUE);
1560 }
1561
1562 # if the value has changed
1563 if ($OldValue != $NewValue)
1564 {
1565 if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1566 && $Field->AllowMultiple() == FALSE ) )
1567 {
1568 $ToRemove = array_diff(array_keys($OldValue),
1569 array_keys($NewValue));
1570 foreach ($ToRemove as $CNId)
1571 {
1572 $this->RemoveAssociation("ResourceNameInts",
1573 "ControlledNameId",
1574 $CNId);
1575 }
1576 }
1577
1578 # for each element of array
1579 foreach ($NewValue as $ControlledNameId => $ControlledName)
1580 {
1581 # associate with resource if not already associated
1582 if ($this->AddAssociation("ResourceNameInts",
1583 "ControlledNameId",
1584 $ControlledNameId))
1585 {
1586
1587 if (ControlledName::ItemExists($ControlledNameId))
1588 {
1589 $CN = new ControlledName($ControlledNameId);
1590 $CN->UpdateLastAssigned();
1591 }
1592 else
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 }
1601 }
1602 $UpdateModTime = TRUE;
1603 }
1604
1605 if ($UpdateModTime)
1606 {
1607 # clear our controlled name cache
1608 unset($this->ControlledNameCache);
1609 unset($this->ControlledNameVariantCache);
1610
1611 # clear visible count cache for any affected CNames
1612 $RFactory = new ResourceFactory($this->SchemaId);
1613 $RFactory->ClearVisibleResourceCountForValues(
1614 array_keys($OldValue + $NewValue) );
1615 }
1616
1617 break;
1618
1619 case MetadataSchema::MDFTYPE_IMAGE:
1620 # associate value(s) with resource
1621 $this->AddAssociation(
1622 "ResourceImageInts", "ImageId", $NewValue, $Field);
1623 # clear cached image mappings
1624 SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1625 break;
1626
1627 case MetadataSchema::MDFTYPE_FILE:
1628 # convert incoming value to array if necessary
1629 if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1630
1631 # for each incoming file
1632 $Factory = new FileFactory($Field->Id());
1633 foreach ($NewValue as $File)
1634 {
1635 # make copy of file
1636 $NewFile = $Factory->Copy($File);
1637
1638 # associate copy with this resource and field
1639 $NewFile->ResourceId($this->Id);
1640 $NewFile->FieldId($Field->Id());
1641 }
1642 # Since we make a fresh copy of the File whenever Set is called,
1643 # we'll always update the modification time for this field.
1644 $UpdateModTime = TRUE;
1645 break;
1646
1647 case MetadataSchema::MDFTYPE_REFERENCE:
1648 # convert incoming value to array to simplify the workflow
1649 if (!is_array($NewValue))
1650 {
1651 $NewValue = [$NewValue];
1652 }
1653
1654 # delete existing resource references
1655 $this->DB->Query(
1656 "DELETE FROM ReferenceInts "
1657 ."WHERE FieldId = '".addslashes($Field->Id())."' "
1658 ."AND SrcResourceId = '".addslashes($this->Id())."'");
1659
1660 # add each reference
1661 foreach ($NewValue as $ReferenceId)
1662 {
1663 if ($ReferenceId instanceof Resource)
1664 {
1665 $ReferenceId = $ReferenceId->Id();
1666 }
1667
1668 # skip blank reference IDs
1669 if (strlen(trim($ReferenceId)) < 1)
1670 {
1671 continue;
1672 }
1673
1674 # skip reference IDs that don't look right
1675 if (!is_numeric($ReferenceId))
1676 {
1677 continue;
1678 }
1679
1680 # skip references to the current resource
1681 if ($ReferenceId == $this->Id())
1682 {
1683 continue;
1684 }
1685
1686 # add the reference to the references table
1687 $DB->Query(
1688 "INSERT INTO ReferenceInts ("
1689 ."FieldId, "
1690 ."SrcResourceId, "
1691 ."DstResourceId"
1692 .") VALUES ("
1693 .addslashes($Field->Id()).","
1694 .addslashes($this->Id()).","
1695 .addslashes($ReferenceId).")");
1696 }
1697 break;
1698
1699 default:
1700 # ERROR OUT
1701 exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1702 break;
1703 }
1704
1705 if ($UpdateModTime && !$this->IsTempResource())
1706 {
1707 # update modification timestamps
1708 global $G_User;
1709 $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1710 $DB->Query("DELETE FROM ResourceFieldTimestamps "
1711 ."WHERE ResourceId=".$this->Id." AND "
1712 ."FieldId=".$Field->Id() );
1713 $DB->Query("INSERT INTO ResourceFieldTimestamps "
1714 ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1715 .$this->Id.",".$Field->Id().","
1716 .$UserId.",NOW())");
1717
1718 # on resource modification, clear the UserPermsCache entry
1719 # so that stale permissions checks are not cached
1720 $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1721
1722 # if this field is not an option or a cname, but it is
1723 # checked for visibility, then we need to clear resource
1724 # visibility cache (for example, if this is AddedById and
1725 # our schema allows users to view resources where they are
1726 # the AddedById)
1727 if (!in_array($Field->Type(),
1728 [MetadataSchema::MDFTYPE_OPTION,
1729 MetadataSchema::MDFTYPE_CONTROLLEDNAME]) &&
1730 $this->Schema()->ViewingPrivileges()->ChecksField($Field->Id()))
1731 {
1732 $RFactory = new ResourceFactory($this->SchemaId);
1733 $RFactory->ClearVisibleResourceCount($this);
1734 }
1735 }
1736 }
1737
1745 public function SetByField($Field, $NewValue)
1746 {
1747 $this->Set($Field, $NewValue);
1748 }
1749
1757 public function SetByFieldId($FieldId, $NewValue)
1758 {
1759 $this->Set($FieldId, $NewValue);
1760 }
1761
1767 public function SetQualifier($FieldName, $NewValue)
1768 {
1769 $Field = $this->Schema()->GetFieldByName($FieldName);
1770 $this->SetQualifierByField($Field, $NewValue);
1771 }
1772
1778 public function SetQualifierByFieldId($FieldId, $NewValue)
1779 {
1780 $Field = $this->Schema()->GetField($FieldId);
1781 $this->SetQualifierByField($Field, $NewValue);
1782 }
1783
1789 public function SetQualifierByField($Field, $NewValue)
1790 {
1791 # if field uses qualifiers and uses item-level qualifiers
1792 if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1793 {
1794 # if qualifier object passed in
1795 if (is_object($NewValue))
1796 {
1797 # grab qualifier ID from object
1798 $QualifierId = $NewValue->Id();
1799 }
1800 else
1801 {
1802 # assume value passed in is qualifier ID
1803 $QualifierId = $NewValue;
1804 }
1805
1806 # update qualifier value in database
1807 $DBFieldName = $Field->DBFieldName();
1808 $this->DB->Query("UPDATE Resources SET "
1809 .$DBFieldName."Qualifier = '".$QualifierId."' "
1810 ."WHERE ResourceId = ".$this->Id);
1811
1812 # update local qualifier value
1813 $this->ValueCache[$DBFieldName."Qualifier"] = $QualifierId;
1814 }
1815 }
1816
1823 public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1824 {
1825 $Field = $this->Schema()->GetField($FieldId);
1826 $this->Clear($Field, $ValueToClear);
1827 }
1828
1835 public function Clear($Field, $ValueToClear = NULL)
1836 {
1837 # convert field name to object if necessary
1838 if (!is_object($Field))
1839 {
1840 $Field = $this->Schema()->GetFieldByName($Field);
1841 }
1842
1843 $UpdateModTime = FALSE;
1844
1845 # store value in DB based on field type
1846 switch ($Field->Type())
1847 {
1848 case MetadataSchema::MDFTYPE_TEXT:
1849 case MetadataSchema::MDFTYPE_PARAGRAPH:
1850 case MetadataSchema::MDFTYPE_NUMBER:
1851 case MetadataSchema::MDFTYPE_FLAG:
1852 case MetadataSchema::MDFTYPE_TIMESTAMP:
1853 case MetadataSchema::MDFTYPE_URL:
1854 case MetadataSchema::MDFTYPE_POINT:
1855 case MetadataSchema::MDFTYPE_DATE:
1856 $this->Set($Field, NULL);
1857 break;
1858
1859 case MetadataSchema::MDFTYPE_TREE:
1860 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
1861 case MetadataSchema::MDFTYPE_OPTION:
1862 case MetadataSchema::MDFTYPE_USER:
1863 # if value to clear supplied
1864 if ($ValueToClear !== NULL)
1865 {
1866 $Value = $this->Get($Field);
1867
1868 if (!is_array($ValueToClear))
1869 {
1870 $ValueToClear = [$ValueToClear => "Dummy"];
1871 }
1872
1873 # for each element of array
1874 foreach ($ValueToClear as $Id => $Dummy)
1875 {
1876 if (array_key_exists($Id, $Value))
1877 {
1878 unset($Value[$Id]);
1879 }
1880 }
1881
1882 $this->Set($Field, $Value, TRUE);
1883 }
1884 else
1885 {
1886 $this->Set($Field, [], TRUE);
1887 }
1888
1889 break;
1890
1891 case MetadataSchema::MDFTYPE_FILE:
1892 # if value to clear supplied
1893 if ($ValueToClear !== NULL)
1894 {
1895 # convert value to array if necessary
1896 $Files = $ValueToClear;
1897 if (!is_array($Files)) { $Files = array($Files); }
1898
1899 # convert values to objects if necessary
1900 foreach ($Files as $Index => $File)
1901 {
1902 if (!is_object($File))
1903 {
1904 $Files[$Index] = new File($File);
1905 }
1906 }
1907 }
1908 else
1909 {
1910 # use all files associated with resource
1911 $Files = $this->Get($Field, TRUE);
1912 }
1913
1914 # delete files
1915 foreach ($Files as $File) { $File->Delete(); }
1916 break;
1917
1918 case MetadataSchema::MDFTYPE_IMAGE:
1919 # if value to clear supplied
1920 if ($ValueToClear !== NULL)
1921 {
1922 # convert value to array if necessary
1923 $Images = $ValueToClear;
1924 if (!is_array($Images)) { $Images = array($Images); }
1925
1926 # convert values to objects if necessary
1927 foreach ($Images as $Index => $Image)
1928 {
1929 if (!is_object($Image))
1930 {
1931 $Images[$Index] = new SPTImage($Image);
1932 }
1933 }
1934 }
1935 else
1936 {
1937 # use all images associated with resource
1938 $Images = $this->Get($Field, TRUE);
1939 }
1940
1941 # delete images if we are the last resource referencing
1942 # a particular image.
1943 foreach ($Images as $Image)
1944 {
1945 $Cnt = $this->DB->Query(
1946 "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
1947 "ImageId=".$Image->Id(), "Cnt");
1948 if ($Cnt==1)
1949 {
1950 $Image->Delete();
1951 }
1952 }
1953
1954 # clear cached image mappings
1955 SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1956
1957 # remove connections to images
1958 $UpdateModTime = $this->RemoveAssociation(
1959 "ResourceImageInts", "ImageId", $Images, $Field);
1960 break;
1961
1962 case MetadataSchema::MDFTYPE_REFERENCE:
1963 $this->Set($Field, []);
1964 break;
1965
1966 default:
1967 # ERROR OUT
1968 exit("<br>SPT - ERROR: attempt to clear "
1969 ."unknown resource field type<br>\n");
1970 break;
1971 }
1972
1973 if ($UpdateModTime && !$this->IsTempResource())
1974 {
1975 # update modification timestamps
1976 global $G_User;
1977 $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1978 $this->DB->Query("DELETE FROM ResourceFieldTimestamps "
1979 ."WHERE ResourceId=".$this->Id." AND "
1980 ."FieldId=".$Field->Id() );
1981 $this->DB->Query("INSERT INTO ResourceFieldTimestamps "
1982 ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1983 .$this->Id.",".$Field->Id().","
1984 .$UserId.",NOW())");
1985 }
1986 }
1987
1996 public function ClearByField($Field, $ValueToClear = NULL)
1997 {
1998 $this->Clear($Field, $ValueToClear);
1999 }
2000
2001 # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
2002
2008 public function Classifications()
2009 {
2010 $DB = $this->DB;
2011
2012 # start with empty array
2013 $Names = array();
2014
2015 # for each controlled name
2016 $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2017 ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2018 ."Classifications, MetadataFields "
2019 ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2020 ."AND ResourceClassInts.ClassificationId = "
2021 ."Classifications.ClassificationId "
2022 ."AND Classifications.FieldId = MetadataFields.FieldId ");
2023 while ($Record = $DB->FetchRow())
2024 {
2025 # add name to array
2026 $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2027 $Record["ClassificationName"];
2028 }
2029
2030 # return array to caller
2031 return $Names;
2032 }
2033
2034
2035 # --- Ratings Methods ---------------------------------------------------
2036
2041 public function CumulativeRating()
2042 {
2043 return $this->CumulativeRating;
2044 }
2045
2050 public function ScaledCumulativeRating()
2051 {
2052 if ($this->CumulativeRating == NULL)
2053 {
2054 return NULL;
2055 }
2056 else
2057 {
2058 return intval(($this->CumulativeRating + 5) / 10);
2059 }
2060 }
2061
2066 public function NumberOfRatings()
2067 {
2068 # if number of ratings not already set
2069 if (!isset($this->NumberOfRatings))
2070 {
2071 $this->FetchAndPossiblyUpdateCumulativeRating();
2072 }
2073
2074 # return number of ratings to caller
2075 return $this->NumberOfRatings;
2076 }
2077
2085 public function Rating($NewRating = NULL, $UserId = NULL)
2086 {
2087 $DB = $this->DB;
2088
2089 # if user ID not supplied
2090 if ($UserId == NULL)
2091 {
2092 # if user is logged in
2093 global $G_User;
2094 if ($G_User->IsLoggedIn())
2095 {
2096 # use ID of current user
2097 $UserId = $G_User->Get("UserId");
2098 }
2099 else
2100 {
2101 # return NULL to caller
2102 return NULL;
2103 }
2104 }
2105
2106 # sanitize $NewRating
2107 if (!is_null($NewRating))
2108 {
2109 $NewRating = intval($NewRating);
2110 }
2111
2112 # if there is a rating for resource and user
2113 $DB->Query("SELECT Rating FROM ResourceRatings "
2114 ."WHERE UserId = ".intval($UserId)." AND ResourceId = ".$this->Id);
2115 if ($Record = $DB->FetchRow())
2116 {
2117 # if new rating was supplied
2118 if ($NewRating != NULL)
2119 {
2120 # update existing rating
2121 $DB->Query("UPDATE ResourceRatings "
2122 ."SET Rating = ".$NewRating.", DateRated = NOW() "
2123 ."WHERE UserId = ".intval($UserId)
2124 ." AND ResourceId = ".$this->Id);
2125
2126 # update cumulative rating value
2127 $this->FetchAndPossiblyUpdateCumulativeRating();
2128
2129 # return value is new rating
2130 $Rating = $NewRating;
2131 }
2132 else
2133 {
2134 # get rating value to return to caller
2135 $Rating = $Record["Rating"];
2136 }
2137 }
2138 else
2139 {
2140 # if new rating was supplied
2141 if ($NewRating != NULL)
2142 {
2143 # add new rating
2144 $DB->Query(
2145 "INSERT INTO ResourceRatings "
2146 ."(ResourceId, UserId, DateRated, Rating) "
2147 ."VALUES ("
2148 .$this->Id.", "
2149 .intval($UserId).", "
2150 ."NOW(), "
2151 .$NewRating.")");
2152
2153 # update cumulative rating value
2154 $this->FetchAndPossiblyUpdateCumulativeRating();
2155
2156 # return value is new rating
2157 $Rating = $NewRating;
2158 }
2159 else
2160 {
2161 # return value is NULL
2162 $Rating = NULL;
2163 }
2164 }
2165
2166 # return rating value to caller
2167 return $Rating;
2168 }
2169
2170
2171 # --- Resource Comment Methods ------------------------------------------
2172
2177 public function Comments()
2178 {
2179 # read in comments if not already loaded
2180 if (!isset($this->Comments))
2181 {
2182 $this->DB->Query("SELECT MessageId FROM Messages "
2183 ."WHERE ParentId = ".$this->Id
2184 ." AND ParentType = 2 "
2185 ."ORDER BY DatePosted DESC");
2186 while ($MessageId = $this->DB->FetchField("MessageId"))
2187 {
2188 $this->Comments[] = new Message($MessageId);
2189 }
2190 }
2191
2192 # return array of comments to caller
2193 return $this->Comments;
2194 }
2195
2200 public function NumberOfComments()
2201 {
2202 # obtain number of comments if not already set
2203 if (!isset($this->NumberOfComments))
2204 {
2205 $this->NumberOfComments =
2206 $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2207 ."FROM Messages "
2208 ."WHERE ParentId = ".$this->Id
2209 ." AND ParentType = 2",
2210 "NumberOfComments"
2211 );
2212 }
2213
2214 # return number of comments to caller
2215 return $this->NumberOfComments;
2216 }
2217
2218
2219 # --- Permission Methods -------------------------------------------------
2220
2230 public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2231 {
2232 return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2233 }
2234
2241 public function UserCanEdit($User)
2242 {
2243 return $this->CheckSchemaPermissions($User, "Edit");
2244 }
2245
2252 public function UserCanAuthor($User)
2253 {
2254 return $this->CheckSchemaPermissions($User, "Author");
2255 }
2256
2263 public function UserCanModify($User)
2264 {
2265 $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2266 return $this->$CheckFn($User);
2267 }
2268
2275 public function UserCanViewField($User, $FieldOrFieldName)
2276 {
2277 return $this->CheckFieldPermissions($User, $FieldOrFieldName, "View");
2278 }
2279
2286 public function UserCanViewMappedField($User, $MappedName)
2287 {
2288 $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
2289 return ($FieldId === NULL) ? FALSE
2290 : $this->CheckFieldPermissions($User, $FieldId, "View");
2291 }
2292
2299 public function UserCanEditField($User, $FieldOrFieldName)
2300 {
2301 return $this->CheckFieldPermissions($User, $FieldOrFieldName, "Edit");
2302 }
2303
2310 public function UserCanAuthorField($User, $FieldOrFieldName)
2311 {
2312 return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2313 }
2314
2322 public function UserCanModifyField($User, $FieldOrFieldName)
2323 {
2324 $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2325
2326 return $this->$CheckFn($User, $FieldOrFieldName);
2327 }
2328
2329 # --- Utility Methods ----------------------------------------------------
2330
2334 public function QueueSearchAndRecommenderUpdate()
2335 {
2336 if (!$this->IsTempResource())
2337 {
2338 $SearchEngine = new SPTSearchEngine();
2339 $SearchEngine->QueueUpdateForItem($this);
2340
2341 $Recommender = new SPTRecommender();
2342 $Recommender->QueueUpdateForItem($this);
2343 }
2344 }
2345
2351 public static function GetSchemaForResource($ResourceId)
2352 {
2353 # if schema IDs are not loaded
2354 if (!isset(self::$SchemaIdCache))
2355 {
2356 # load schema IDs
2357 $DB = new Database();
2358 $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2359 self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2360 }
2361
2362 # if multiple resources specified
2363 if (is_array($ResourceId))
2364 {
2365 # find schema IDs for specified resources
2366 $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2367 array_flip($ResourceId));
2368
2369 # check that specified resource IDs were all valid
2370 if (count($SchemaIds) < count($ResourceId))
2371 {
2372 $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2373 throw new InvalidArgumentException("Unknown resource IDs ("
2374 .implode(", ", $BadIds).").");
2375 }
2376
2377 # return schema IDs to caller
2378 return $SchemaIds;
2379 }
2380 else
2381 {
2382 # check that specified resource was valid
2383 if (!isset(self::$SchemaIdCache[$ResourceId]))
2384 {
2385 throw new InvalidArgumentException("Unknown resource ID ("
2386 .$ResourceId.").");
2387 }
2388
2389 # return schema IDs for specified resource
2390 return self::$SchemaIdCache[$ResourceId];
2391 }
2392 }
2393
2394
2395 # ---- PRIVATE INTERFACE -------------------------------------------------
2396
2397 private $ClassificationCache;
2398 private $Comments;
2399 private $ControlledNameCache;
2400 private $ControlledNameVariantCache;
2401 private $CumulativeRating;
2402 private $NumberOfComments;
2403 private $NumberOfRatings;
2404 private $PermissionCache;
2405 private $SchemaId;
2406
2407 static private $Schemas;
2408 static private $SchemaIdCache;
2409
2420 private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2421 {
2422 # construct a key to use for our permissions cache
2423 $CacheKey = "UserCan".$CheckType.$User->Id();
2424
2425 # if we don't have a cached value for this perm, compute one
2426 if (!isset($this->PermissionCache[$CacheKey]))
2427 {
2428 # get privileges for schema
2429 $PermsFn = $CheckType."ingPrivileges";
2430 $SchemaPrivs = $this->Schema()->$PermsFn();
2431
2432 # check passes if user privileges are greater than resource set
2433 $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2434
2435 # save the result of this check in our cache
2436 $this->PermissionCache[$CacheKey] = $CheckResult;
2437 }
2438
2439 $Value = $this->PermissionCache[$CacheKey];
2440
2441 if ($AllowHooksToModify)
2442 {
2443 $SignalResult = $GLOBALS["AF"]->SignalEvent(
2444 "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2445 array(
2446 "Resource" => $this,
2447 "User" => $User,
2448 "Can".$CheckType => $Value,
2449 "Schema" => $this->Schema(), ));
2450
2451 $Value = $SignalResult["Can".$CheckType];
2452 }
2453
2454 return $Value;
2455 }
2456
2465 private function CheckFieldPermissions($User, $Field, $CheckType)
2466 {
2467 # get field object (if not supplied)
2468 if (!($Field instanceof MetadataField))
2469 {
2470 try
2471 {
2472 $Field = $this->Schema()->GetField($Field);
2473 }
2474 catch (InvalidArgumentException $Exception)
2475 {
2476 # (user cannot view/author/edit if field was invalid)
2477 return FALSE;
2478 }
2479 }
2480
2481 # construct a key to use for our permissions cache
2482 $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2483
2484 # if we don't have a cahced value, compute one
2485 if (!isset($this->PermissionCache[$CacheKey]))
2486 {
2487 # if field is enabled and editable, do permission check
2488 if ($Field->Enabled() &&
2489 ($CheckType == "View" || $Field->Editable()))
2490 {
2491 # be sure schema privs allow View/Edit/Author for this resource
2492 $SchemaCheckFn = "UserCan".$CheckType;
2493 if ($this->$SchemaCheckFn($User))
2494 {
2495 # get appropriate privilege set for field
2496 $PermsFn = $CheckType."ingPrivileges";
2497 $FieldPrivs = $Field->$PermsFn();
2498
2499 # user can View/Edit/Author if privileges are greater than field set
2500 $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2501 }
2502 else
2503 {
2504 $CheckResult = FALSE;
2505 }
2506 }
2507 else
2508 {
2509 $CheckResult = FALSE;
2510 }
2511
2512 # allow plugins to modify result of permission check
2513 $SignalResult = $GLOBALS["AF"]->SignalEvent(
2514 "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2515 "Field" => $Field,
2516 "Resource" => $this,
2517 "User" => $User,
2518 "Can".$CheckType => $CheckResult));
2519 $CheckResult = $SignalResult["Can".$CheckType];
2520
2521 # save the result of this check in our cache
2522 $this->PermissionCache[$CacheKey] = $CheckResult;
2523 }
2524
2525 # return cached permission value
2526 return $this->PermissionCache[$CacheKey];
2527 }
2528
2532 private function FetchAndPossiblyUpdateCumulativeRating()
2533 {
2534 # grab totals from DB
2535 $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2536 ."SUM(Rating) AS Total FROM ResourceRatings "
2537 ."WHERE ResourceId = ".$this->Id);
2538 $Record = $this->DB->FetchRow();
2539
2540 $this->NumberOfRatings = $Record["Count"];
2541 $NewCumulativeRating = round($Record["Total"] / max(1, $Record["Count"]));
2542
2543 # if saved cumulative rating is no longer accurate
2544 if ($this->CumulativeRating != $NewCumulativeRating)
2545 {
2546 # update local value and save new cumulative rating in DB
2547 $this->CumulativeRating = $NewCumulativeRating;
2548 $this->DB->Query("UPDATE Resources "
2549 ."SET CumulativeRating = ".$this->CumulativeRating." "
2550 ."WHERE ResourceId = ".$this->Id);
2551 $this->ValueCache["CumulativeRating"] = $this->CumulativeRating;
2552 }
2553 }
2554
2566 private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2567 {
2568 # We should ignore duplicate key errors when doing inserts:
2569 $this->DB->SetQueryErrorsToIgnore( array(
2570 "/INSERT INTO ".$TableName."/" =>
2571 "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2572
2573 # start out assuming no association will be added
2574 $AssociationAdded = FALSE;
2575
2576 # convert new value to array if necessary
2577 $Values = is_array($Value) ? $Value : array($Value);
2578
2579 # for each new value
2580 foreach ($Values as $Value)
2581 {
2582 # retrieve ID from value if necessary
2583 if (is_object($Value)) { $Value = $Value->Id(); }
2584
2585 # Try to insert a new entry for this association.
2586 $this->DB->Query("INSERT INTO ".$TableName." SET"
2587 ." ResourceId = ".intval($this->Id)
2588 .", ".$FieldName." = ".intval($Value)
2589 .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2590
2591 # If the insert ran without a duplicate key error,
2592 # then we added an assocation:
2593 if ($this->DB->IgnoredError() === FALSE)
2594 {
2595 $AssociationAdded = TRUE;
2596 }
2597 }
2598
2599 # Clear ignored errors:
2600 $this->DB->SetQueryErrorsToIgnore( NULL );
2601
2602 # report to caller whether association was added
2603 return $AssociationAdded;
2604 }
2605
2617 private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2618 {
2619 # start out assuming no association will be removed
2620 $AssociationRemoved = FALSE;
2621
2622 # convert value to array if necessary
2623 $Values = is_array($Value) ? $Value : array($Value);
2624
2625 # for each value
2626 foreach ($Values as $Value)
2627 {
2628 # retrieve ID from value if necessary
2629 if (is_object($Value)) { $Value = $Value->Id(); }
2630
2631 # remove any intersections with target ID from DB
2632 $this->DB->Query("DELETE FROM ".$TableName
2633 ." WHERE ResourceId = ".intval($this->Id)
2634 .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2635 ." AND ".$FieldName." = ".intval($Value));
2636 if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2637 }
2638
2639 # report to caller whether association was added
2640 return $AssociationRemoved;
2641 }
2642
2649 static protected function SetDatabaseAccessValues($ClassName)
2650 {
2651 if (!isset(self::$ItemIdColumnNames[$ClassName]))
2652 {
2653 self::$ItemIdColumnNames[$ClassName] = "ResourceId";
2654 self::$ItemNameColumnNames[$ClassName] = NULL;
2655 self::$ItemTableNames[$ClassName] = "Resources";
2656 }
2657 }
2658 }
MetadataSchema\MDFTYPE_IMAGE
const MDFTYPE_IMAGE
Definition: MetadataSchema.php:31
Resource\GetByField
GetByField($FieldNameOrObject, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Old method for retrieving values, deprecated in favor of Get().
Definition: Resource.php:790
Resource\UserCanView
UserCanView(User $User, $AllowHooksToModify=TRUE)
Determine if the given user can view the resource, e.g., on the full record page. ...
Definition: Resource.php:2230
FileFactory\GetFilesForResource
GetFilesForResource($ResourceOrResourceId, $ReturnObjects=TRUE)
Retrieve all files (names or objects) for specified resource.
Definition: FileFactory.php:39
Resource\GetImageUrls
GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
Get URLs for images, returning CleanURLs when possible and direct paths to image files otherwise...
Definition: Resource.php:1118
Resource\SetQualifier
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1767
Resource\UserCanViewMappedField
UserCanViewMappedField($User, $MappedName)
Check whether user can view specified standard (mapped) metadata field.
Definition: Resource.php:2286
MetadataSchema\MDFTYPE_TIMESTAMP
const MDFTYPE_TIMESTAMP
Definition: MetadataSchema.php:25
SPTSearchEngine
Definition: SPTSearchEngine.php:10
MetadataSchema\MDFTYPE_FILE
const MDFTYPE_FILE
Definition: MetadataSchema.php:32
MetadataSchema
Metadata schema (in effect a Factory class for MetadataField).
Definition: MetadataSchema.php:13
Message
Abstraction for forum messages and resource comments.
Definition: Message.php:14
Database
SQL database abstraction object with smart query caching.
Definition: Database.php:22
Resource\UserCanModifyField
UserCanModifyField($User, $FieldOrFieldName)
Check whether user is allowed to modify (Edit for perm resources, Author for temp) specified metadata...
Definition: Resource.php:2322
MetadataSchema\MDFTYPE_REFERENCE
const MDFTYPE_REFERENCE
Definition: MetadataSchema.php:35
Resource\QueueSearchAndRecommenderUpdate
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2334
Resource\GetAsArray
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:828
Resource\Id
Id()
Retrieve numerical resource ID.
Definition: Resource.php:294
Item\$DB
$DB
Definition: Item.php:210
Resource\UserCanEditField
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2299
Resource\SetQualifierByField
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1789
MetadataSchema\MDFTYPE_NUMBER
const MDFTYPE_NUMBER
Definition: MetadataSchema.php:23
Resource\GetViewPageUrl
GetViewPageUrl()
Retrieve view page URL for this resource.
Definition: Resource.php:396
Resource\Rating
Rating($NewRating=NULL, $UserId=NULL)
Get/set rating by a specific user for resource.
Definition: Resource.php:2085
User
Definition: User.php:48
Resource\NumberOfComments
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2200
Resource\NumberOfRatings
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2066
Resource\GetQualifier
GetQualifier($FieldName, $ReturnObject=TRUE)
Retrieve qualifier by field name.
Definition: Resource.php:891
FolderFactory
Factory object for Folder class, used to retrieve and manage Folders and groups of Folders...
Definition: FolderFactory.php:14
Qualifier
Definition: Qualifier.php:10
FileFactory\Copy
Copy($FileToCopy)
Create copy of File and return to caller.
Definition: FileFactory.php:85
MetadataSchema\MDFTYPE_TREE
const MDFTYPE_TREE
Definition: MetadataSchema.php:27
SPTRecommender
Definition: SPTRecommender.php:10
Resource\Schema
Schema()
Get MetadataSchema for resource.
Definition: Resource.php:312
Date
Definition: Date.php:18
MetadataSchema\MDFTYPE_OPTION
const MDFTYPE_OPTION
Definition: MetadataSchema.php:29
ControlledName
Metadata type representing non-hierarchical controlled vocabulary values.
Definition: ControlledName.php:14
MetadataSchema\MDFTYPE_FLAG
const MDFTYPE_FLAG
Definition: MetadataSchema.php:26
Resource\UserCanEdit
UserCanEdit($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2241
MetadataSchema\MDFTYPE_CONTROLLEDNAME
const MDFTYPE_CONTROLLEDNAME
Definition: MetadataSchema.php:28
Resource\GetForDisplay
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:754
Resource\Comments
Comments()
Get comments for resource.
Definition: Resource.php:2177
Resource\UpdateAutoupdateFields
UpdateAutoupdateFields($UpdateType, $User=NULL)
Update the auto-updated fields as necessary.
Definition: Resource.php:262
Resource\Get
Get($Field, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field name or field object.
Definition: Resource.php:420
PHP
PHP
Definition: RSSClient--Test.php:12
Resource\GetSchemaForResource
static GetSchemaForResource($ResourceId)
Get schema ID for specified resource(s).
Definition: Resource.php:2351
MetadataSchema\SCHEMAID_DEFAULT
const SCHEMAID_DEFAULT
Definition: MetadataSchema.php:53
FileFactory
Factory for manipulating File objects.
Definition: FileFactory.php:13
Item
Common base class for persistent items store in database.
Definition: Item.php:13
Resource\GetQualifierByFieldId
GetQualifierByFieldId($FieldId, $ReturnObject=TRUE)
Retrieve qualifier by field ID.
Definition: Resource.php:905
SPTImage
Encapsulates a full-size, preview, and thumbnail image.
Definition: SPTImage.php:13
Resource\UserCanAuthorField
UserCanAuthorField($User, $FieldOrFieldName)
Check whether user is allowed to author specified metadata field.
Definition: Resource.php:2310
Resource\Clear
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1835
Resource\UserCanModify
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2263
Resource\UserCanAuthor
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2252
Resource\GetByFieldId
GetByFieldId($FieldId, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field ID.
Definition: Resource.php:810
Resource\IsTempResource
IsTempResource($NewSetting=NULL)
Get/set whether resource is a temporary record.
Definition: Resource.php:323
Resource\SetByField
SetByField($Field, $NewValue)
Method replaced by Resource::Set(), preserved for backward compatibility.
Definition: Resource.php:1745
MetadataField
Object representing a locally-defined type of metadata field.
Definition: MetadataField.php:13
Resource\__construct
__construct($ResourceId)
Object constructor for loading an existing resource.
Definition: Resource.php:25
Resource\GetMapped
GetMapped($MappedName, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using standard (mapped) field name.
Definition: Resource.php:874
MetadataSchema\MDFTYPE_PARAGRAPH
const MDFTYPE_PARAGRAPH
Definition: MetadataSchema.php:22
Item\$Id
$Id
Definition: Item.php:211
Resource\SetDatabaseAccessValues
static SetDatabaseAccessValues($ClassName)
Set the database access values (table name, ID column name, name column name) for specified class...
Definition: Resource.php:2649
MetadataSchema\MDFTYPE_DATE
const MDFTYPE_DATE
Definition: MetadataSchema.php:24
Resource
Represents a "resource" in CWIS.
Definition: Resource.php:13
MetadataSchema\MDFTYPE_URL
const MDFTYPE_URL
Definition: MetadataSchema.php:33
Resource\GetQualifierByField
GetQualifierByField($Field, $ReturnObject=TRUE)
Retrieve qualifier by Field object.
Definition: Resource.php:919
MetadataSchema\MDFTYPE_TEXT
const MDFTYPE_TEXT
Definition: MetadataSchema.php:21
Resource\ClearByFieldId
ClearByFieldId($FieldId, $ValueToClear=NULL)
Clear field value specified by field ID.
Definition: Resource.php:1823
Resource\SetQualifierByFieldId
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1778
SPTImage\SIZE_FULL
const SIZE_FULL
Definition: SPTImage.php:21
MetadataSchema\MDFTYPE_USER
const MDFTYPE_USER
Definition: MetadataSchema.php:30
SPTImage\ClearImageSymlinksForResource
static ClearImageSymlinksForResource($ResourceId, $FieldId)
Remove symlinks used for to cache image mappings.
Definition: SPTImage.php:576
Resource\SchemaId
SchemaId()
Retrieve ID of schema for resource.
Definition: Resource.php:303
Resource\ScaledCumulativeRating
ScaledCumulativeRating()
Return cumulative rating scaled to 1/10th.
Definition: Resource.php:2050
Resource\Set
Set($Field, $NewValue, $Reset=FALSE)
Set value using field name or field object.
Definition: Resource.php:1153
MetadataField\UPDATEMETHOD_ONRECORDCREATE
const UPDATEMETHOD_ONRECORDCREATE
Definition: MetadataField.php:19
Resource\Create
static Create($SchemaId)
Create a new resource.
Definition: Resource.php:48
Resource\UserCanViewField
UserCanViewField($User, $FieldOrFieldName)
Check whether user is allowed to view specified metadata field.
Definition: Resource.php:2275
Classification
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
Definition: Classification.php:13
Resource\SetByFieldId
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1757
Resource\Classifications
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:2008
Resource\ClearByField
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1996
MetadataSchema\MDFTYPE_POINT
const MDFTYPE_POINT
Definition: MetadataSchema.php:34
File
Class representing a stored (usually uploaded) file.
Definition: File.php:13
Item\ItemExists
static ItemExists($Id)
Check whether an item exists with the specified ID.
Definition: Item.php:162
ResourceFactory
Factory for Resource objects.
Definition: ResourceFactory.php:13
CWUser
CWIS-specific user class.
Definition: CWUser.php:13
Resource\CumulativeRating
CumulativeRating()
Get cumulative rating (range is usually 0-100)
Definition: Resource.php:2041
Resource\FieldIsSet
FieldIsSet($FieldNameOrObject, $IgnorePadding=FALSE)
Determine if the value for a field is set.
Definition: Resource.php:1053
Resource\Delete
Delete()
Remove resource (and accompanying associations) from database and delete any associated files...
Definition: Resource.php:142
$Items
$Items
Definition: RSSClient--Test.php:26