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