CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

Resource.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Resource.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9
13 class Resource extends Item
14 {
15
16 # ---- PUBLIC INTERFACE --------------------------------------------------
17
25 public function __construct($ResourceId)
26 {
27 # call parent contstructor to load info from DB
28 parent::__construct($ResourceId);
29
30 # load local attributes from database value cache
31 $this->CumulativeRating = $this->ValueCache["CumulativeRating"];
32
33 # load our local metadata schema
34 $this->SchemaId = $this->ValueCache["SchemaId"];
35 if (!isset(self::$Schemas[$this->SchemaId]))
36 {
37 self::$Schemas[$this->SchemaId] =
38 new MetadataSchema($this->SchemaId);
39 }
40 }
41
48 public static function Create($SchemaId)
49 {
50 # clean out any temp resource records more than three days old
51 $RFactory = new ResourceFactory();
52 $RFactory->CleanOutStaleTempItems(60 * 24 * 3);
53
54 # lock DB tables to prevent next ID from being grabbed
55 $DB = new Database;
56 $DB->Query("LOCK TABLES Resources WRITE");
57
58 # find next temp resource ID
59 $Id = $RFactory->GetNextTempItemId();
60
61 # write out new resource record with temp resource ID
62 # Set DateLastModified = NOW() to avoid being pruned as a
63 # stale temp resource.
64 $DB->Query(
65 "INSERT INTO Resources
66 SET `ResourceId` = '".intval($Id)."',
67 `SchemaId` = '".intval($SchemaId)."',
68 `DateLastModified` = NOW() " );
69
70 # release DB tables
71 $DB->Query("UNLOCK TABLES");
72
73 # create new Resource object
74 $Resource = new Resource($Id);
75
76 # set some additional fields for default resources
77 if ($SchemaId == MetadataSchema::SCHEMAID_DEFAULT)
78 {
79 $Resource->Set("Date Of Record Creation", date("Y-m-d H:i:s"));
80 $Resource->Set("Date Last Modified", date("Y-m-d H:i:s"));
81 if ($GLOBALS["G_User"]->IsLoggedIn())
82 {
83 $Resource->Set("Added By Id", $GLOBALS["G_User"]->Id());
84 $Resource->Set("Last Modified By Id", $GLOBALS["G_User"]->Id());
85 }
86 }
87
88 # for each field that can have a default value
89 $Schema = new MetadataSchema($SchemaId);
90 $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_OPTION
91 |MetadataSchema::MDFTYPE_TEXT
92 |MetadataSchema::MDFTYPE_FLAG
93 |MetadataSchema::MDFTYPE_NUMBER
94 |MetadataSchema::MDFTYPE_POINT);
95 foreach ($Fields as $Field)
96 {
97 # if there is a default value available
98 $DefaultValue = $Field->DefaultValue();
99 if ($DefaultValue !== NULL)
100 {
101 # if the default value is an array
102 if (is_array($DefaultValue))
103 {
104 # if there are values in the array
105 if (!empty($DefaultValue))
106 {
107 # flip values for Set() if necessary
108 if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
109 {
110 $DefaultValue = array_flip($DefaultValue);
111 }
112
113 # set default value
114 $Resource->Set($Field, $DefaultValue);
115 }
116 }
117 else
118 {
119 # set default value
120 $Resource->Set($Field, $DefaultValue);
121 }
122 }
123 }
124
125 $Resource->UpdateAutoupdateFields(
126 MetadataField::UPDATEMETHOD_ONRECORDCREATE,
127 $GLOBALS["G_User"]);
128
129 # signal resource creation
130 $GLOBALS["AF"]->SignalEvent("EVENT_RESOURCE_CREATE", array(
131 "Resource" => $Resource,
132 ));
133
134 # return new Resource object to caller
135 return $Resource;
136 }
137
142 public function Delete()
143 {
144 global $G_SysConfig;
145
146 # signal that resource deletion is about to occur
147 global $AF;
148 $AF->SignalEvent("EVENT_RESOURCE_DELETE", array(
149 "Resource" => $this,
150 ));
151
152 # grab list of classifications
153 $Classifications = $this->Classifications();
154
155 # delete resource/classification intersections
156 $DB = $this->DB;
157 $DB->Query("DELETE FROM ResourceClassInts WHERE ResourceId = ".$this->Id());
158
159 # for each classification type
160 foreach ($Classifications as $ClassType => $ClassesOfType)
161 {
162 # for each classification of that type
163 foreach ($ClassesOfType as $ClassId => $ClassName)
164 {
165 # recalculate resource count for classification
166 $Class = new Classification($ClassId);
167 $Class->RecalcResourceCount();
168 }
169 }
170
171 # delete resource references
172 $DB->Query("
173 DELETE FROM ReferenceInts
174 WHERE SrcResourceId = '".addslashes($this->Id())."'
175 OR DstResourceId = '".addslashes($this->Id())."'");
176
177 # delete resource/name intersections
178 $DB->Query("DELETE FROM ResourceNameInts WHERE ResourceId = ".$this->Id());
179
180 # delete resource/user intersections
181 $DB->Query("DELETE FROM ResourceUserInts WHERE ResourceId = ".$this->Id());
182
183 # get the list of all images associated with this resource
184 $DB->Query("SELECT ImageId FROM ResourceImageInts"
185 ." WHERE ResourceId = ".intval($this->Id()));
186 $ImageIds = $DB->FetchColumn("ImageId");
187
188 # disassociate this resource from all images
189 $DB->Query("DELETE FROM ResourceImageInts"
190 ." WHERE ResourceId = ".intval($this->Id()));
191
192 # delete any images that no longer belong to any resources
193 foreach ($ImageIds as $ImageId)
194 {
195 $DB->Query("SELECT ResourceId FROM ResourceImageInts"
196 ." WHERE ImageId = ".intval($ImageId) );
197 if ($DB->NumRowsSelected() == 0)
198 {
199 $Image = new SPTImage($ImageId);
200 $Image->Delete();
201 }
202 }
203
204 # delete any associated files
205 $Factory = new FileFactory(NULL);
206 $Files = $Factory->GetFilesForResource($this->Id());
207 foreach ($Files as $File)
208 {
209 $File->Delete();
210 }
211
212 # delete resource 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 ($G_SysConfig->SearchDBEnabled())
217 {
218 $SearchEngine = new SPTSearchEngine();
219 $SearchEngine->DropItem($this->Id());
220 }
221 if ($G_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 throw new Exception("Attempt to retrieve "
712 ."unknown field type (".$Field->Type().")");
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 !is_null($Value)
1058 && strlen($Value)
1059 && (!$IgnorePadding || ($IgnorePadding && strlen(trim($Value))));
1060
1061 case MetadataSchema::MDFTYPE_FLAG:
1062 return !is_null($Value)
1063 && strlen($Value);
1064
1065 case MetadataSchema::MDFTYPE_POINT:
1066 return !is_null($Value["X"])
1067 && !is_null($Value["Y"])
1068 && strlen(trim($Value["X"]))
1069 && strlen(trim($Value["Y"]));
1070
1071 case MetadataSchema::MDFTYPE_DATE:
1072 return !is_null($Value)
1073 && strlen(trim($Value))
1074 && $Value != "0000-00-00";
1075
1076 case MetadataSchema::MDFTYPE_TIMESTAMP:
1077 return !is_null($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 !is_null($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 (is_null($NewValue))
1328 {
1329 if (!is_null($this->ValueCache[$DBFieldName."Begin"]) ||
1330 !is_null($this->ValueCache[$DBFieldName."End"]) ||
1331 !is_null($this->ValueCache[$DBFieldName."Precision"]))
1332 {
1333 # clear date object values in DB
1334 $DB->Query("UPDATE Resources SET "
1335 .$DBFieldName."Begin = '', "
1336 .$DBFieldName."End = '', "
1337 .$DBFieldName."Precision = '' "
1338 ."WHERE ResourceId = ".$ResourceId);
1339
1340 # clear value locally
1341 $this->ValueCache[$DBFieldName."Begin"] = NULL;
1342 $this->ValueCache[$DBFieldName."End"] = NULL;
1343 $this->ValueCache[$DBFieldName."Precision"] = NULL;
1344 $UpdateModTime=TRUE;
1345 }
1346 }
1347 else
1348 {
1349
1350 # if we were given a date object
1351 if (is_object($NewValue))
1352 {
1353 # use supplied date object
1354 $Date = $NewValue;
1355 }
1356 else
1357 {
1358 # create date object
1359 $Date = new Date($NewValue);
1360 }
1361
1362 $OldDate = new Date(
1363 $this->ValueCache[$DBFieldName."Begin"],
1364 $this->ValueCache[$DBFieldName."End"],
1365 $this->ValueCache[$DBFieldName."Precision"]);
1366
1367 if ($OldDate->BeginDate() != $Date->BeginDate() ||
1368 $OldDate->EndDate() != $Date->EndDate() ||
1369 $OldDate->Precision() != $Date->Precision() )
1370 {
1371 # extract values from date object and store in DB
1372 $BeginDate = !is_null($Date->BeginDate()) ?
1373 "'".$Date->BeginDate()."'" : "NULL" ;
1374 $EndDate = !is_null($Date->EndDate()) ?
1375 "'".$Date->EndDate()."'" : "NULL" ;
1376
1377 $DB->Query("UPDATE Resources SET "
1378 .$DBFieldName."Begin = ".$BeginDate.", "
1379 .$DBFieldName."End = ".$EndDate.", "
1380 .$DBFieldName."Precision = '".$Date->Precision()."' "
1381 ."WHERE ResourceId = ".$ResourceId);
1382
1383 # save values locally
1384 $this->ValueCache[$DBFieldName."Begin"] = $Date->BeginDate();
1385 $this->ValueCache[$DBFieldName."End"] = $Date->EndDate();
1386 $this->ValueCache[$DBFieldName."Precision"] = $Date->Precision();
1387 $UpdateModTime=TRUE;
1388 }
1389 }
1390 break;
1391
1392 case MetadataSchema::MDFTYPE_TIMESTAMP:
1393 if (is_null($NewValue) || !strlen(trim($NewValue)))
1394 {
1395 $DateValue = $NewValue;
1396
1397 if (!is_null($this->ValueCache[$DBFieldName]))
1398 {
1399 # save value directly to DB
1400 $DB->Query("UPDATE Resources SET "
1401 ."`".$DBFieldName."` = NULL "
1402 ."WHERE ResourceId = ".$ResourceId);
1403 $UpdateModTime = TRUE;
1404 }
1405 }
1406 else
1407 {
1408 # assume value is date and use directly
1409 $TimestampValue = strtotime($NewValue);
1410
1411 # use the new value if the date is valid
1412 if ($TimestampValue !== FALSE && $TimestampValue >= 0)
1413 {
1414 $DateValue = date("Y-m-d H:i:s", $TimestampValue);
1415
1416 if ($this->ValueCache[$DBFieldName] != $DateValue)
1417 {
1418 # save value directly to DB
1419 $DB->Query("UPDATE Resources SET "
1420 ."`".$DBFieldName."` = '".addslashes($DateValue)."' "
1421 ."WHERE ResourceId = ".$ResourceId);
1422 $UpdateModTime=TRUE;
1423 }
1424 }
1425
1426 # continue using the old value if invalid
1427 else
1428 {
1429 $DateValue = $this->Get($Field);
1430 }
1431 }
1432
1433 # save value locally
1434 $this->ValueCache[$DBFieldName] = $DateValue;
1435 break;
1436
1437 case MetadataSchema::MDFTYPE_TREE:
1438 $OldValue = $this->Get($Field);
1439
1440 # if incoming value is array
1441 if (is_array($NewValue))
1442 {
1443 if ($OldValue != $NewValue)
1444 {
1445 if ($Reset)
1446 {
1447 # remove values that were in the old value
1448 # but not the new one
1449 $ToRemove = array_diff(array_keys($OldValue),
1450 array_keys($NewValue));
1451 foreach ($ToRemove as $ClassificationId)
1452 {
1453 $this->RemoveAssociation("ResourceClassInts",
1454 "ClassificationId",
1455 $ClassificationId);
1456 $Class = new Classification($ClassificationId);
1457 $Class->RecalcResourceCount();
1458 }
1459 }
1460
1461 # for each element of array
1462 foreach ($NewValue as
1463 $ClassificationId => $ClassificationName)
1464 {
1465 $Class = new Classification($ClassificationId);
1466 if ($Class->FieldId() == $Field->Id())
1467 {
1468 # associate with resource if not already associated
1469 if ($this->AddAssociation("ResourceClassInts",
1470 "ClassificationId", $ClassificationId))
1471 {
1472 $Class->UpdateLastAssigned();
1473 $Class->RecalcResourceCount();
1474 }
1475 }
1476 else
1477 {
1478 throw new Exception(
1479 "Attempting to store classification from "
1480 ."Field ".$Class->FieldId()." into Field "
1481 .$Field->Id() );
1482 }
1483
1484 }
1485
1486 $UpdateModTime=TRUE;
1487 }
1488 }
1489 else
1490 {
1491 # associate with resource if not already associated
1492 if (is_object($NewValue))
1493 {
1494 $Class = $NewValue;
1495 $NewValue = $Class->Id();
1496 }
1497 else
1498 {
1499 $Class = new Classification($NewValue);
1500 }
1501
1502 if (!array_key_exists($Class->Id(), $OldValue))
1503 {
1504
1505 $this->AddAssociation("ResourceClassInts",
1506 "ClassificationId",
1507 $NewValue);
1508 $Class->UpdateLastAssigned();
1509 $Class->RecalcResourceCount();
1510 $UpdateModTime=TRUE;
1511 }
1512 }
1513
1514 # clear our classification cache
1515 if ($UpdateModTime)
1516 {
1517 unset($this->ClassificationCache);
1518 }
1519 break;
1520
1521 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
1522 case MetadataSchema::MDFTYPE_OPTION:
1523 $OldValue = $this->Get($Field);
1524
1525 # input to Set() for these fields is one of
1526 # 1. an int specifying a ControlledNameId
1527 # 2. a ControlledName object
1528 # 3. an array with keys giving Ids and values giving ControlledNames
1529 #
1530 # normalize 1 and 2 into 3 for simplicity of processing
1531 if (is_object($NewValue) || !is_array($NewValue) )
1532 {
1533 if (!is_object($NewValue))
1534 {
1535 $NewValue = new ControlledName($NewValue);
1536 }
1537
1538 $TmpValue = array();
1539 $TmpValue[$NewValue->Id()] = $NewValue->Name();
1540
1541 $NewValue = $TmpValue;
1542 }
1543
1544 # if this is a unique field, only accept the first of the options given
1545 # NB: all ControlledNames implicitly AllowMultiple
1546 if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION &&
1547 $Field->AllowMultiple() == FALSE && count($NewValue) > 1)
1548 {
1549 $NewValue = array_slice($NewValue, 0, 1, TRUE);
1550 }
1551
1552 # if the value has changed
1553 if ($OldValue != $NewValue)
1554 {
1555 if ($Reset || ($Field->Type() == MetadataSchema::MDFTYPE_OPTION
1556 && $Field->AllowMultiple() == FALSE ) )
1557 {
1558 $ToRemove = array_diff(array_keys($OldValue),
1559 array_keys($NewValue));
1560 foreach ($ToRemove as $CNId)
1561 {
1562 $this->RemoveAssociation("ResourceNameInts",
1563 "ControlledNameId",
1564 $CNId);
1565 }
1566 }
1567
1568 # for each element of array
1569 foreach ($NewValue as $ControlledNameId => $ControlledName)
1570 {
1571 # associate with resource if not already associated
1572 if ($this->AddAssociation("ResourceNameInts",
1573 "ControlledNameId",
1574 $ControlledNameId))
1575 {
1576
1577 if (ControlledName::ItemExists($ControlledNameId))
1578 {
1579 $CN = new ControlledName($ControlledNameId);
1580 $CN->UpdateLastAssigned();
1581 }
1582 else
1583 {
1584 $this->RemoveAssociation("ResourceNameInts",
1585 "ControlledNameId", $ControlledNameId);
1586 throw new InvalidArgumentException(
1587 "Attempt to set controlled name with"
1588 ." invalid ID (".$ControlledNameId.").");
1589 }
1590 }
1591 }
1592 $UpdateModTime = TRUE;
1593 }
1594
1595 if ($UpdateModTime)
1596 {
1597 # clear our controlled name cache
1598 unset($this->ControlledNameCache);
1599 unset($this->ControlledNameVariantCache);
1600
1601 # clear visible count cache for any affected CNames
1602 $RFactory = new ResourceFactory($this->SchemaId);
1603 $RFactory->ClearVisibleResourceCountForValues(
1604 array_keys($OldValue + $NewValue) );
1605 }
1606
1607 break;
1608
1609 case MetadataSchema::MDFTYPE_IMAGE:
1610 # associate value(s) with resource
1611 $this->AddAssociation(
1612 "ResourceImageInts", "ImageId", $NewValue, $Field);
1613 # clear cached image mappings
1614 SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1615 break;
1616
1617 case MetadataSchema::MDFTYPE_FILE:
1618 # convert incoming value to array if necessary
1619 if (!is_array($NewValue)) { $NewValue = array($NewValue); }
1620
1621 # for each incoming file
1622 $Factory = new FileFactory($Field->Id());
1623 foreach ($NewValue as $File)
1624 {
1625 # make copy of file
1626 $NewFile = $Factory->Copy($File);
1627
1628 # associate copy with this resource and field
1629 $NewFile->ResourceId($this->Id);
1630 $NewFile->FieldId($Field->Id());
1631 }
1632 # Since we make a fresh copy of the File whenever Set is called,
1633 # we'll always update the modification time for this field.
1634 $UpdateModTime = TRUE;
1635 break;
1636
1637 case MetadataSchema::MDFTYPE_REFERENCE:
1638 # convert incoming value to array to simplify the workflow
1639 if (!is_array($NewValue))
1640 {
1641 $NewValue = [$NewValue];
1642 }
1643
1644 # delete existing resource references
1645 $this->DB->Query(
1646 "DELETE FROM ReferenceInts "
1647 ."WHERE FieldId = '".addslashes($Field->Id())."' "
1648 ."AND SrcResourceId = '".addslashes($this->Id())."'");
1649
1650 # add each reference
1651 foreach ($NewValue as $ReferenceId)
1652 {
1653 if ($ReferenceId instanceof Resource)
1654 {
1655 $ReferenceId = $ReferenceId->Id();
1656 }
1657
1658 # skip blank reference IDs
1659 if (strlen(trim($ReferenceId)) < 1)
1660 {
1661 continue;
1662 }
1663
1664 # skip reference IDs that don't look right
1665 if (!is_numeric($ReferenceId))
1666 {
1667 continue;
1668 }
1669
1670 # skip references to the current resource
1671 if ($ReferenceId == $this->Id())
1672 {
1673 continue;
1674 }
1675
1676 # add the reference to the references table
1677 $DB->Query(
1678 "INSERT INTO ReferenceInts ("
1679 ."FieldId, "
1680 ."SrcResourceId, "
1681 ."DstResourceId"
1682 .") VALUES ("
1683 .addslashes($Field->Id()).","
1684 .addslashes($this->Id()).","
1685 .addslashes($ReferenceId).")");
1686 }
1687 break;
1688
1689 default:
1690 # ERROR OUT
1691 exit("<br>SPT - ERROR: attempt to set unknown resource field type<br>\n");
1692 break;
1693 }
1694
1695 if ($UpdateModTime && !$this->IsTempResource())
1696 {
1697 # update modification timestamps
1698 global $G_User;
1699 $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1700 $DB->Query("DELETE FROM ResourceFieldTimestamps "
1701 ."WHERE ResourceId=".$this->Id." AND "
1702 ."FieldId=".$Field->Id() );
1703 $DB->Query("INSERT INTO ResourceFieldTimestamps "
1704 ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1705 .$this->Id.",".$Field->Id().","
1706 .$UserId.",NOW())");
1707
1708 # on resource modification, clear the UserPermsCache entry
1709 # so that stale permissions checks are not cached
1710 $DB->Query("DELETE FROM UserPermsCache WHERE ResourceId=".$this->Id);
1711
1712 # if this field is not an option or a cname, but it is
1713 # checked for visibility, then we need to clear resource
1714 # visibility cache (for example, if this is AddedById and
1715 # our schema allows users to view resources where they are
1716 # the AddedById)
1717 if (!in_array($Field->Type(),
1718 [MetadataSchema::MDFTYPE_OPTION,
1719 MetadataSchema::MDFTYPE_CONTROLLEDNAME]) &&
1720 $this->Schema()->ViewingPrivileges()->ChecksField($Field->Id()))
1721 {
1722 $RFactory = new ResourceFactory($this->SchemaId);
1723 $RFactory->ClearVisibleResourceCount($this);
1724 }
1725 }
1726 }
1727
1735 public function SetByField($Field, $NewValue)
1736 {
1737 $this->Set($Field, $NewValue);
1738 }
1739
1747 public function SetByFieldId($FieldId, $NewValue)
1748 {
1749 $this->Set($FieldId, $NewValue);
1750 }
1751
1757 public function SetQualifier($FieldName, $NewValue)
1758 {
1759 $Field = $this->Schema()->GetFieldByName($FieldName);
1760 $this->SetQualifierByField($Field, $NewValue);
1761 }
1762
1768 public function SetQualifierByFieldId($FieldId, $NewValue)
1769 {
1770 $Field = $this->Schema()->GetField($FieldId);
1771 $this->SetQualifierByField($Field, $NewValue);
1772 }
1773
1779 public function SetQualifierByField($Field, $NewValue)
1780 {
1781 # if field uses qualifiers and uses item-level qualifiers
1782 if ($Field->UsesQualifiers() && $Field->HasItemLevelQualifiers())
1783 {
1784 # if qualifier object passed in
1785 if (is_object($NewValue))
1786 {
1787 # grab qualifier ID from object
1788 $QualifierId = $NewValue->Id();
1789 }
1790 else
1791 {
1792 # assume value passed in is qualifier ID
1793 $QualifierId = $NewValue;
1794 }
1795
1796 # update qualifier value in database
1797 $DBFieldName = $Field->DBFieldName();
1798 $this->DB->Query("UPDATE Resources SET "
1799 .$DBFieldName."Qualifier = '".$QualifierId."' "
1800 ."WHERE ResourceId = ".$this->Id);
1801
1802 # update local qualifier value
1803 $this->ValueCache[$DBFieldName."Qualifier"] = $QualifierId;
1804 }
1805 }
1806
1813 public function ClearByFieldId($FieldId, $ValueToClear = NULL)
1814 {
1815 $Field = $this->Schema()->GetField($FieldId);
1816 $this->Clear($Field, $ValueToClear);
1817 }
1818
1825 public function Clear($Field, $ValueToClear = NULL)
1826 {
1827 # convert field name to object if necessary
1828 if (!is_object($Field))
1829 {
1830 $Field = $this->Schema()->GetFieldByName($Field);
1831 }
1832
1833 $UpdateModTime = FALSE;
1834
1835 # store value in DB based on field type
1836 switch ($Field->Type())
1837 {
1838 case MetadataSchema::MDFTYPE_TEXT:
1839 case MetadataSchema::MDFTYPE_PARAGRAPH:
1840 case MetadataSchema::MDFTYPE_NUMBER:
1841 case MetadataSchema::MDFTYPE_FLAG:
1842 case MetadataSchema::MDFTYPE_TIMESTAMP:
1843 case MetadataSchema::MDFTYPE_URL:
1844 case MetadataSchema::MDFTYPE_POINT:
1845 case MetadataSchema::MDFTYPE_DATE:
1846 $this->Set($Field, NULL);
1847 break;
1848
1849 case MetadataSchema::MDFTYPE_TREE:
1850 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
1851 case MetadataSchema::MDFTYPE_OPTION:
1852 case MetadataSchema::MDFTYPE_USER:
1853 # if value to clear supplied
1854 if ($ValueToClear !== NULL)
1855 {
1856 $Value = $this->Get($Field);
1857
1858 if (!is_array($ValueToClear))
1859 {
1860 $ValueToClear = [$ValueToClear => "Dummy"];
1861 }
1862
1863 # for each element of array
1864 foreach ($ValueToClear as $Id => $Dummy)
1865 {
1866 if (array_key_exists($Id, $Value))
1867 {
1868 unset($Value[$Id]);
1869 }
1870 }
1871
1872 $this->Set($Field, $Value, TRUE);
1873 }
1874 else
1875 {
1876 $this->Set($Field, [], TRUE);
1877 }
1878
1879 break;
1880
1881 case MetadataSchema::MDFTYPE_FILE:
1882 # if value to clear supplied
1883 if ($ValueToClear !== NULL)
1884 {
1885 # convert value to array if necessary
1886 $Files = $ValueToClear;
1887 if (!is_array($Files)) { $Files = array($Files); }
1888
1889 # convert values to objects if necessary
1890 foreach ($Files as $Index => $File)
1891 {
1892 if (!is_object($File))
1893 {
1894 $Files[$Index] = new File($File);
1895 }
1896 }
1897 }
1898 else
1899 {
1900 # use all files associated with resource
1901 $Files = $this->Get($Field, TRUE);
1902 }
1903
1904 # delete files
1905 foreach ($Files as $File) { $File->Delete(); }
1906 break;
1907
1908 case MetadataSchema::MDFTYPE_IMAGE:
1909 # if value to clear supplied
1910 if ($ValueToClear !== NULL)
1911 {
1912 # convert value to array if necessary
1913 $Images = $ValueToClear;
1914 if (!is_array($Images)) { $Images = array($Images); }
1915
1916 # convert values to objects if necessary
1917 foreach ($Images as $Index => $Image)
1918 {
1919 if (!is_object($Image))
1920 {
1921 $Images[$Index] = new SPTImage($Image);
1922 }
1923 }
1924 }
1925 else
1926 {
1927 # use all images associated with resource
1928 $Images = $this->Get($Field, TRUE);
1929 }
1930
1931 # delete images if we are the last resource referencing
1932 # a particular image.
1933 foreach ($Images as $Image)
1934 {
1935 $Cnt = $this->DB->Query(
1936 "SELECT COUNT(*) AS Cnt FROM ResourceImageInts WHERE ".
1937 "ImageId=".$Image->Id(), "Cnt");
1938 if ($Cnt==1)
1939 {
1940 $Image->Delete();
1941 }
1942 }
1943
1944 # clear cached image mappings
1945 SPTImage::ClearImageSymlinksForResource($this->Id(), $Field->Id());
1946
1947 # remove connections to images
1948 $UpdateModTime = $this->RemoveAssociation(
1949 "ResourceImageInts", "ImageId", $Images, $Field);
1950 break;
1951
1952 case MetadataSchema::MDFTYPE_REFERENCE:
1953 $this->Set($Field, []);
1954 break;
1955
1956 default:
1957 # ERROR OUT
1958 exit("<br>SPT - ERROR: attempt to clear "
1959 ."unknown resource field type<br>\n");
1960 break;
1961 }
1962
1963 if ($UpdateModTime && !$this->IsTempResource())
1964 {
1965 # update modification timestamps
1966 global $G_User;
1967 $UserId = $G_User->IsLoggedIn() ? $G_User->Get("UserId") : -1;
1968 $this->DB->Query("DELETE FROM ResourceFieldTimestamps "
1969 ."WHERE ResourceId=".$this->Id." AND "
1970 ."FieldId=".$Field->Id() );
1971 $this->DB->Query("INSERT INTO ResourceFieldTimestamps "
1972 ."(ResourceId,FieldId,ModifiedBy,Timestamp) VALUES ("
1973 .$this->Id.",".$Field->Id().","
1974 .$UserId.",NOW())");
1975 }
1976 }
1977
1986 public function ClearByField($Field, $ValueToClear = NULL)
1987 {
1988 $this->Clear($Field, $ValueToClear);
1989 }
1990
1991 # --- Field-Specific or Type-Specific Attribute Retrieval Methods -------
1992
1998 public function Classifications()
1999 {
2000 $DB = $this->DB;
2001
2002 # start with empty array
2003 $Names = array();
2004
2005 # for each controlled name
2006 $DB->Query("SELECT ClassificationName, MetadataFields.FieldName, "
2007 ."ResourceClassInts.ClassificationId FROM ResourceClassInts, "
2008 ."Classifications, MetadataFields "
2009 ."WHERE ResourceClassInts.ResourceId = ".$this->Id." "
2010 ."AND ResourceClassInts.ClassificationId = "
2011 ."Classifications.ClassificationId "
2012 ."AND Classifications.FieldId = MetadataFields.FieldId ");
2013 while ($Record = $DB->FetchRow())
2014 {
2015 # add name to array
2016 $Names[$Record["FieldName"]][$Record["ClassificationId"]] =
2017 $Record["ClassificationName"];
2018 }
2019
2020 # return array to caller
2021 return $Names;
2022 }
2023
2024
2025 # --- Ratings Methods ---------------------------------------------------
2026
2031 public function CumulativeRating()
2032 {
2033 return $this->CumulativeRating;
2034 }
2035
2040 public function ScaledCumulativeRating()
2041 {
2042 if ($this->CumulativeRating == NULL)
2043 {
2044 return NULL;
2045 }
2046 else
2047 {
2048 return intval(($this->CumulativeRating + 5) / 10);
2049 }
2050 }
2051
2056 public function NumberOfRatings()
2057 {
2058 # if number of ratings not already set
2059 if (!isset($this->NumberOfRatings))
2060 {
2061 # obtain number of ratings
2062 $this->NumberOfRatings =
2063 $this->DB->Query("SELECT Count(*) AS NumberOfRatings "
2064 ."FROM ResourceRatings "
2065 ."WHERE ResourceId = ".$this->Id,
2066 "NumberOfRatings"
2067 );
2068
2069 # recalculate cumulative rating if it looks erroneous
2070 if (($this->NumberOfRatings > 0) && !$this->CumulativeRating())
2071 {
2072 $this->UpdateCumulativeRating();
2073 }
2074 }
2075
2076 # return number of ratings to caller
2077 return $this->NumberOfRatings;
2078 }
2079
2087 public function Rating($NewRating = NULL, $UserId = NULL)
2088 {
2089 $DB = $this->DB;
2090
2091 # if user ID not supplied
2092 if ($UserId == NULL)
2093 {
2094 # if user is logged in
2095 global $G_User;
2096 if ($G_User->IsLoggedIn())
2097 {
2098 # use ID of current user
2099 $UserId = $G_User->Get("UserId");
2100 }
2101 else
2102 {
2103 # return NULL to caller
2104 return NULL;
2105 }
2106 }
2107
2108 # sanitize $NewRating
2109 if (!is_null($NewRating))
2110 {
2111 $NewRating = intval($NewRating);
2112 }
2113
2114 # if there is a rating for resource and user
2115 $DB->Query("SELECT Rating FROM ResourceRatings "
2116 ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2117 if ($Record = $DB->FetchRow())
2118 {
2119 # if new rating was supplied
2120 if ($NewRating != NULL)
2121 {
2122 # update existing rating
2123 $DB->Query("UPDATE ResourceRatings "
2124 ."SET Rating = ${NewRating}, DateRated = NOW() "
2125 ."WHERE UserId = ${UserId} AND ResourceId = ".$this->Id);
2126
2127 # update cumulative rating value
2128 $this->UpdateCumulativeRating();
2129
2130 # return value is new rating
2131 $Rating = $NewRating;
2132 }
2133 else
2134 {
2135 # get rating value to return to caller
2136 $Rating = $Record["Rating"];
2137 }
2138 }
2139 else
2140 {
2141 # if new rating was supplied
2142 if ($NewRating != NULL)
2143 {
2144 # add new rating
2145 $DB->Query("INSERT INTO ResourceRatings "
2146 ."(ResourceId, UserId, DateRated, Rating) "
2147 ."VALUES ("
2148 .$this->Id.", "
2149 ."${UserId}, "
2150 ."NOW(), "
2151 ."${NewRating})");
2152
2153 # update cumulative rating value
2154 $this->UpdateCumulativeRating();
2155
2156 # return value is new rating
2157 $Rating = $NewRating;
2158 }
2159 else
2160 {
2161 # return value is NULL
2162 $Rating = NULL;
2163 }
2164 }
2165
2166 # return rating value to caller
2167 return $Rating;
2168 }
2169
2170
2171 # --- Resource Comment Methods ------------------------------------------
2172
2177 public function Comments()
2178 {
2179 # read in comments if not already loaded
2180 if (!isset($this->Comments))
2181 {
2182 $this->DB->Query("SELECT MessageId FROM Messages "
2183 ."WHERE ParentId = ".$this->Id
2184 ." AND ParentType = 2 "
2185 ."ORDER BY DatePosted DESC");
2186 while ($MessageId = $this->DB->FetchField("MessageId"))
2187 {
2188 $this->Comments[] = new Message($MessageId);
2189 }
2190 }
2191
2192 # return array of comments to caller
2193 return $this->Comments;
2194 }
2195
2200 public function NumberOfComments()
2201 {
2202 # obtain number of comments if not already set
2203 if (!isset($this->NumberOfComments))
2204 {
2205 $this->NumberOfComments =
2206 $this->DB->Query("SELECT Count(*) AS NumberOfComments "
2207 ."FROM Messages "
2208 ."WHERE ParentId = ".$this->Id
2209 ." AND ParentType = 2",
2210 "NumberOfComments"
2211 );
2212 }
2213
2214 # return number of comments to caller
2215 return $this->NumberOfComments;
2216 }
2217
2218
2219 # --- Permission Methods -------------------------------------------------
2220
2230 public function UserCanView(User $User, $AllowHooksToModify=TRUE)
2231 {
2232 return $this->CheckSchemaPermissions($User, "View", $AllowHooksToModify);
2233 }
2234
2241 public function UserCanEdit($User)
2242 {
2243 return $this->CheckSchemaPermissions($User, "Edit");
2244 }
2245
2252 public function UserCanAuthor($User)
2253 {
2254 return $this->CheckSchemaPermissions($User, "Author");
2255 }
2256
2263 public function UserCanModify($User)
2264 {
2265 $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit");
2266 return $this->$CheckFn($User);
2267 }
2268
2275 public function UserCanViewField($User, $FieldOrFieldName)
2276 {
2277 return $this->CheckFieldPermissions($User, $FieldOrFieldName, "View");
2278 }
2279
2286 public function UserCanViewMappedField($User, $MappedName)
2287 {
2288 $FieldId = $this->Schema()->StdNameToFieldMapping($MappedName);
2289 return ($FieldId === NULL) ? FALSE
2290 : $this->CheckFieldPermissions($User, $FieldId, "View");
2291 }
2292
2299 public function UserCanEditField($User, $FieldOrFieldName)
2300 {
2301 return $this->CheckFieldPermissions($User, $FieldOrFieldName, "Edit");
2302 }
2303
2310 public function UserCanAuthorField($User, $FieldOrFieldName)
2311 {
2312 return $this->CheckFieldPermissions( $User, $FieldOrFieldName, "Author" );
2313 }
2314
2322 public function UserCanModifyField($User, $FieldOrFieldName)
2323 {
2324 $CheckFn = "UserCan".(($this->Id()<0) ? "Author" : "Edit")."Field";
2325
2326 return $this->$CheckFn($User, $FieldOrFieldName);
2327 }
2328
2329 # --- Utility Methods ----------------------------------------------------
2330
2334 public function QueueSearchAndRecommenderUpdate()
2335 {
2336 if (!$this->IsTempResource())
2337 {
2338 $SearchEngine = new SPTSearchEngine();
2339 $SearchEngine->QueueUpdateForItem($this);
2340
2341 $Recommender = new SPTRecommender();
2342 $Recommender->QueueUpdateForItem($this);
2343 }
2344 }
2345
2351 public static function GetSchemaForResource($ResourceId)
2352 {
2353 # if schema IDs are not loaded
2354 if (!isset(self::$SchemaIdCache))
2355 {
2356 # load schema IDs
2357 $DB = new Database();
2358 $DB->Query("SELECT ResourceId, SchemaId FROM Resources");
2359 self::$SchemaIdCache = $DB->FetchColumn("SchemaId", "ResourceId");
2360 }
2361
2362 # if multiple resources specified
2363 if (is_array($ResourceId))
2364 {
2365 # find schema IDs for specified resources
2366 $SchemaIds = array_intersect_key(self::$SchemaIdCache,
2367 array_flip($ResourceId));
2368
2369 # check that specified resource IDs were all valid
2370 if (count($SchemaIds) < count($ResourceId))
2371 {
2372 $BadIds = array_diff($ResourceId, array_keys($SchemaIds));
2373 throw new InvalidArgumentException("Unknown resource IDs ("
2374 .implode(", ", $BadIds).").");
2375 }
2376
2377 # return schema IDs to caller
2378 return $SchemaIds;
2379 }
2380 else
2381 {
2382 # check that specified resource was valid
2383 if (!isset(self::$SchemaIdCache[$ResourceId]))
2384 {
2385 throw new InvalidArgumentException("Unknown resource ID ("
2386 .$ResourceId.").");
2387 }
2388
2389 # return schema IDs for specified resource
2390 return self::$SchemaIdCache[$ResourceId];
2391 }
2392 }
2393
2394
2395 # ---- PRIVATE INTERFACE -------------------------------------------------
2396
2397 private $ClassificationCache;
2398 private $Comments;
2399 private $ControlledNameCache;
2400 private $ControlledNameVariantCache;
2401 private $CumulativeRating;
2402 private $NumberOfComments;
2403 private $NumberOfRatings;
2404 private $PermissionCache;
2405 private $SchemaId;
2406
2407 static private $Schemas;
2408 static private $SchemaIdCache;
2409
2420 private function CheckSchemaPermissions($User, $CheckType, $AllowHooksToModify=TRUE)
2421 {
2422 # construct a key to use for our permissions cache
2423 $CacheKey = "UserCan".$CheckType.$User->Id();
2424
2425 # if we don't have a cached value for this perm, compute one
2426 if (!isset($this->PermissionCache[$CacheKey]))
2427 {
2428 # get privileges for schema
2429 $PermsFn = $CheckType."ingPrivileges";
2430 $SchemaPrivs = $this->Schema()->$PermsFn();
2431
2432 # check passes if user privileges are greater than resource set
2433 $CheckResult = $SchemaPrivs->MeetsRequirements($User, $this);
2434
2435 # save the result of this check in our cache
2436 $this->PermissionCache[$CacheKey] = $CheckResult;
2437 }
2438
2439 $Value = $this->PermissionCache[$CacheKey];
2440
2441 if ($AllowHooksToModify)
2442 {
2443 $SignalResult = $GLOBALS["AF"]->SignalEvent(
2444 "EVENT_RESOURCE_".strtoupper($CheckType)."_PERMISSION_CHECK",
2445 array(
2446 "Resource" => $this,
2447 "User" => $User,
2448 "Can".$CheckType => $Value,
2449 "Schema" => $this->Schema(), ));
2450
2451 $Value = $SignalResult["Can".$CheckType];
2452 }
2453
2454 return $Value;
2455 }
2456
2465 private function CheckFieldPermissions($User, $Field, $CheckType)
2466 {
2467 # get field object (if not supplied)
2468 if (!($Field instanceof MetadataField))
2469 {
2470 try
2471 {
2472 $Field = $this->Schema()->GetField($Field);
2473 }
2474 catch (InvalidArgumentException $Exception)
2475 {
2476 # (user cannot view/author/edit if field was invalid)
2477 return FALSE;
2478 }
2479 }
2480
2481 # construct a key to use for our permissions cache
2482 $CacheKey = "UserCan".$CheckType."Field".$Field->Id()."-".$User->Id();
2483
2484 # if we don't have a cahced value, compute one
2485 if (!isset($this->PermissionCache[$CacheKey]))
2486 {
2487 # if field is enabled and editable, do permission check
2488 if ($Field->Enabled() &&
2489 ($CheckType == "View" || $Field->Editable()))
2490 {
2491 # be sure schema privs allow View/Edit/Author for this resource
2492 $SchemaCheckFn = "UserCan".$CheckType;
2493 if ($this->$SchemaCheckFn($User))
2494 {
2495 # get appropriate privilege set for field
2496 $PermsFn = $CheckType."ingPrivileges";
2497 $FieldPrivs = $Field->$PermsFn();
2498
2499 # user can View/Edit/Author if privileges are greater than field set
2500 $CheckResult = $FieldPrivs->MeetsRequirements($User, $this);
2501 }
2502 else
2503 {
2504 $CheckResult = FALSE;
2505 }
2506 }
2507 else
2508 {
2509 $CheckResult = FALSE;
2510 }
2511
2512 # allow plugins to modify result of permission check
2513 $SignalResult = $GLOBALS["AF"]->SignalEvent(
2514 "EVENT_FIELD_".strtoupper($CheckType)."_PERMISSION_CHECK", array(
2515 "Field" => $Field,
2516 "Resource" => $this,
2517 "User" => $User,
2518 "Can".$CheckType => $CheckResult));
2519 $CheckResult = $SignalResult["Can".$CheckType];
2520
2521 # save the result of this check in our cache
2522 $this->PermissionCache[$CacheKey] = $CheckResult;
2523 }
2524
2525 # return cached permission value
2526 return $this->PermissionCache[$CacheKey];
2527 }
2528
2532 private function UpdateCumulativeRating()
2533 {
2534 # grab totals from DB
2535 $this->DB->Query("SELECT COUNT(Rating) AS Count, "
2536 ."SUM(Rating) AS Total FROM ResourceRatings "
2537 ."WHERE ResourceId = ".$this->Id);
2538 $Record = $this->DB->FetchRow();
2539
2540 # calculate new cumulative rating
2541 $this->CumulativeRating = round($Record["Total"] / $Record["Count"]);
2542
2543 # save new cumulative rating in DB
2544 $this->DB->Query("UPDATE Resources "
2545 ."SET CumulativeRating = ".$this->CumulativeRating." "
2546 ."WHERE ResourceId = ".$this->Id);
2547 }
2548
2560 private function AddAssociation($TableName, $FieldName, $Value, $Field = NULL)
2561 {
2562 # We should ignore duplicate key errors when doing inserts:
2563 $this->DB->SetQueryErrorsToIgnore( array(
2564 "/INSERT INTO ".$TableName."/" =>
2565 "/Duplicate entry '-?[0-9]+-[0-9]+(-[0-9]+)?' for key/"));
2566
2567 # start out assuming no association will be added
2568 $AssociationAdded = FALSE;
2569
2570 # convert new value to array if necessary
2571 $Values = is_array($Value) ? $Value : array($Value);
2572
2573 # for each new value
2574 foreach ($Values as $Value)
2575 {
2576 # retrieve ID from value if necessary
2577 if (is_object($Value)) { $Value = $Value->Id(); }
2578
2579 # Try to insert a new entry for this association.
2580 $this->DB->Query("INSERT INTO ".$TableName." SET"
2581 ." ResourceId = ".intval($this->Id)
2582 .", ".$FieldName." = ".intval($Value)
2583 .($Field ? ", FieldId = ".intval($Field->Id()) : ""));
2584
2585 # If the insert ran without a duplicate key error,
2586 # then we added an assocation:
2587 if ($this->DB->IgnoredError() === FALSE)
2588 {
2589 $AssociationAdded = TRUE;
2590 }
2591 }
2592
2593 # Clear ignored errors:
2594 $this->DB->SetQueryErrorsToIgnore( NULL );
2595
2596 # report to caller whether association was added
2597 return $AssociationAdded;
2598 }
2599
2611 private function RemoveAssociation($TableName, $FieldName, $Value, $Field = NULL)
2612 {
2613 # start out assuming no association will be removed
2614 $AssociationRemoved = FALSE;
2615
2616 # convert value to array if necessary
2617 $Values = is_array($Value) ? $Value : array($Value);
2618
2619 # for each value
2620 foreach ($Values as $Value)
2621 {
2622 # retrieve ID from value if necessary
2623 if (is_object($Value)) { $Value = $Value->Id(); }
2624
2625 # remove any intersections with target ID from DB
2626 $this->DB->Query("DELETE FROM ".$TableName
2627 ." WHERE ResourceId = ".intval($this->Id)
2628 .($Field ? " AND FieldId = ".intval($Field->Id()) : "")
2629 ." AND ".$FieldName." = ".intval($Value));
2630 if ($this->DB->NumRowsAffected()) { $AssociationRemoved = TRUE; }
2631 }
2632
2633 # report to caller whether association was added
2634 return $AssociationRemoved;
2635 }
2636
2643 private function RemoveAllAssociations($TableName, $TargetFieldName, $Field)
2644 {
2645 # retrieve list of entries for this field and resource
2646 $Entries = $this->Get($Field);
2647
2648 # divide them into chunks of not more than 100
2649 foreach (array_chunk($Entries, 100, TRUE) as $Chunk)
2650 {
2651 # remove assocations from this chunk
2652 $this->DB->Query("DELETE FROM ".$TableName
2653 ." WHERE ResourceId = ".intval($this->Id)
2654 ." AND ".$TargetFieldName." IN "
2655 ."(".implode(",", array_keys($Chunk)).")");
2656 }
2657 }
2658
2665 static protected function SetDatabaseAccessValues($ClassName)
2666 {
2667 if (!isset(self::$ItemIdColumnNames[$ClassName]))
2668 {
2669 self::$ItemIdColumnNames[$ClassName] = "ResourceId";
2670 self::$ItemNameColumnNames[$ClassName] = NULL;
2671 self::$ItemTableNames[$ClassName] = "Resources";
2672 }
2673 }
2674 }
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:2230
FileFactory\GetFilesForResource
GetFilesForResource($ResourceOrResourceId, $ReturnObjects=TRUE)
Retrieve all files (names or objects) for specified resource.
Definition: FileFactory.php:39
Resource\GetImageUrls
GetImageUrls($FieldNameOrObject, $ImageSize=SPTImage::SIZE_FULL)
Get URLs for images, returning CleanURLs when possible and direct paths to image files otherwise...
Definition: Resource.php:1108
Resource\SetQualifier
SetQualifier($FieldName, $NewValue)
Set qualifier using field name.
Definition: Resource.php:1757
Resource\UserCanViewMappedField
UserCanViewMappedField($User, $MappedName)
Check whether user can view specified standard (mapped) metadata field.
Definition: Resource.php:2286
MetadataSchema\MDFTYPE_TIMESTAMP
const MDFTYPE_TIMESTAMP
Definition: MetadataSchema.php:25
SPTSearchEngine
Definition: SPTSearchEngine.php:10
MetadataSchema\MDFTYPE_FILE
const MDFTYPE_FILE
Definition: MetadataSchema.php:32
MetadataSchema
Metadata schema (in effect a Factory class for MetadataField).
Definition: MetadataSchema.php:13
Message
Abstraction for forum messages and resource comments.
Definition: Message.php:14
Database
SQL database abstraction object with smart query caching.
Definition: Database.php:22
Resource\UserCanModifyField
UserCanModifyField($User, $FieldOrFieldName)
Check whether user is allowed to modify (Edit for perm resources, Author for temp) specified metadata...
Definition: Resource.php:2322
MetadataSchema\MDFTYPE_REFERENCE
const MDFTYPE_REFERENCE
Definition: MetadataSchema.php:35
Resource\QueueSearchAndRecommenderUpdate
QueueSearchAndRecommenderUpdate()
Update search and recommender system DBs.
Definition: Resource.php:2334
Resource\GetAsArray
GetAsArray($IncludeDisabledFields=FALSE, $ReturnObjects=TRUE)
Retrieve all resource values as an array.
Definition: Resource.php:813
Resource\Id
Id()
Retrieve numerical resource ID.
Definition: Resource.php:291
Item\$DB
$DB
Definition: Item.php:210
Resource\UserCanEditField
UserCanEditField($User, $FieldOrFieldName)
Check whether user is allowed to edit specified metadata field.
Definition: Resource.php:2299
Resource\SetQualifierByField
SetQualifierByField($Field, $NewValue)
Set qualifier using field object.
Definition: Resource.php:1779
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:2087
User
Definition: User.php:48
Resource\NumberOfComments
NumberOfComments()
Get current number of comments for resource.
Definition: Resource.php:2200
Resource\NumberOfRatings
NumberOfRatings()
Get current number of ratings for resource.
Definition: Resource.php:2056
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:2241
MetadataSchema\MDFTYPE_CONTROLLEDNAME
const MDFTYPE_CONTROLLEDNAME
Definition: MetadataSchema.php:28
Resource\GetForDisplay
GetForDisplay($FieldNameOrObject, $ReturnObject=TRUE, $IncludeVariants=FALSE)
Retrieve value using field name or field object, signaling EVENT_FIELD_DISPLAY_FILTER to allow other ...
Definition: Resource.php:739
Resource\Comments
Comments()
Get comments for resource.
Definition: Resource.php:2177
Resource\UpdateAutoupdateFields
UpdateAutoupdateFields($UpdateType, $User=NULL)
Update the auto-updated fields as necessary.
Definition: Resource.php: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:2351
MetadataSchema\SCHEMAID_DEFAULT
const SCHEMAID_DEFAULT
Definition: MetadataSchema.php:53
FileFactory
Factory for manipulating File objects.
Definition: FileFactory.php:13
Item
Common base class for persistent items store in database.
Definition: Item.php:13
Resource\GetQualifierByFieldId
GetQualifierByFieldId($FieldId, $ReturnObject=TRUE)
Retrieve qualifier by field ID.
Definition: Resource.php: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:2310
Resource\Clear
Clear($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1825
Resource\UserCanModify
UserCanModify($User)
Check if the user is allowed to modify (Edit for perm resources, Author for temp) a specified resourc...
Definition: Resource.php:2263
Resource\UserCanAuthor
UserCanAuthor($User)
Determine if the given user can edit the resource.
Definition: Resource.php:2252
Resource\GetByFieldId
GetByFieldId($FieldId, $ReturnObject=FALSE, $IncludeVariants=FALSE)
Retrieve value using field ID.
Definition: Resource.php: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:1735
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:211
Resource\SetDatabaseAccessValues
static SetDatabaseAccessValues($ClassName)
Set the database access values (table name, ID column name, name column name) for specified class...
Definition: Resource.php:2665
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:1813
Resource\SetQualifierByFieldId
SetQualifierByFieldId($FieldId, $NewValue)
Set qualifier using field ID.
Definition: Resource.php:1768
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:2040
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:2275
Classification
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
Definition: Classification.php:13
Resource\SetByFieldId
SetByFieldId($FieldId, $NewValue)
Set field value using field ID.
Definition: Resource.php:1747
Resource\Classifications
Classifications()
Get 2D array of classifications associated with resource.
Definition: Resource.php:1998
Resource\ClearByField
ClearByField($Field, $ValueToClear=NULL)
Clear field value.
Definition: Resource.php:1986
MetadataSchema\MDFTYPE_POINT
const MDFTYPE_POINT
Definition: MetadataSchema.php:34
File
Class representing a stored (usually uploaded) file.
Definition: File.php:13
Item\ItemExists
static ItemExists($Id)
Check whether an item exists with the specified ID.
Definition: Item.php:162
ResourceFactory
Factory for Resource objects.
Definition: ResourceFactory.php:13
CWUser
CWIS-specific user class.
Definition: CWUser.php:13
Resource\CumulativeRating
CumulativeRating()
Get cumulative rating (range is usually 0-100)
Definition: Resource.php:2031
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