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