3 # FILE: ResourceFactory.php 5 # Part of the Collection Workflow Integration System (CWIS) 6 # Copyright 2011-2013 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu/cwis/ 15 # ---- PUBLIC INTERFACE -------------------------------------------------- 25 $this->SchemaId = $SchemaId;
27 # set up resource count cache 28 $this->CountCache = array();
30 # set up item factory base class 31 parent::__construct(
"Resource",
"Resources",
"ResourceId", NULL, FALSE,
32 "SchemaId = ".intval($this->SchemaId));
42 # create new target resource 45 # load up resource to duplicate 46 $SrcResource =
new Resource($ResourceId);
48 # if resource to duplicate was found 49 if ($SrcResource->Status() > 0)
51 # for each metadata field 53 $Fields = $Schema->GetFields();
54 foreach ($Fields as $Field)
56 if ($Field->CopyOnResourceDuplication())
58 $NewValue = $SrcResource->GetByField($Field, TRUE);
60 # clear default value from destination resource that is 61 # set when creating a new resource 62 $DstResource->ClearByField($Field);
64 # copy value from source resource to destination resource 65 $DstResource->SetByField($Field, $NewValue);
70 # return new resource to caller 82 # sanitize qualifier ID or retrieve from object 83 $QualifierId = is_object($ObjectOrId)
84 ? $ObjectOrId->Id() : intval($ObjectOrId);
86 # if new qualifier passed in 87 if ($NewObjectOrId !== NULL)
89 # sanitize qualifier ID to change to or retrieve it from object 90 $NewQualifierIdVal = is_object($NewObjectOrId)
91 ? $NewObjectOrId->Id() : intval($NewObjectOrId);
95 # qualifier should be cleared 96 $NewQualifierIdVal =
"NULL";
99 # for each metadata field 101 $Fields = $Schema->GetFields();
102 foreach ($Fields as $Field)
104 # if field uses qualifiers and uses item-level qualifiers 105 $QualColName = $Field->DBFieldName().
"Qualifier";
106 if ($Field->UsesQualifiers()
107 && $Field->HasItemLevelQualifiers()
108 && $this->DB->FieldExists(
"Resources", $QualColName))
110 # set all occurrences to new qualifier value 111 $this->DB->Query(
"UPDATE Resources" 112 .
" SET ".$QualColName.
" = ".$NewQualifierIdVal.
"" 113 .
" WHERE ".$QualColName.
" = '".$QualifierId.
"'" 114 .
" AND SchemaId = ".intval($this->SchemaId));
118 # clear or change qualifier association with controlled names 119 # (NOTE: this should probably be done in a controlled name factory object) 120 $this->DB->Query(
"UPDATE ControlledNames" 121 .
" SET QualifierId = ".$NewQualifierIdVal
122 .
" WHERE QualifierId = '".$QualifierId.
"'");
124 # clear or change qualifier association with classifications 125 # (NOTE: this should probably be done in a classification factory object) 126 $this->DB->Query(
"UPDATE Classifications" 127 .
" SET QualifierId = ".$NewQualifierIdVal
128 .
" WHERE QualifierId = '".$QualifierId.
"'");
137 return $this->DB->Query(
138 "SELECT COUNT(DISTINCT ResourceId) AS ResourceCount" 139 .
" FROM ResourceRatings",
149 return $this->DB->Query(
150 "SELECT COUNT(DISTINCT UserId) AS UserCount" 151 .
" FROM ResourceRatings",
165 $Count = 10, $Offset = 0, $MaxDaysToGoBack = 90)
167 # assume that no resources will be found 168 $Resources = array();
170 # calculate cutoff date for resources 171 $CutoffDate = date(
"Y-m-d H:i:s", strtotime($MaxDaysToGoBack.
" days ago"));
173 # query for resource IDs 174 $this->DB->Query(
"SELECT ResourceId FROM Resources WHERE" 175 .
" DateOfRecordRelease > '".$CutoffDate.
"'" 176 .
" AND ReleaseFlag = 1" 177 .
" AND ResourceId >= 0" 178 .
" AND SchemaId = ".intval($this->SchemaId)
179 .
" ORDER BY DateOfRecordRelease DESC, DateOfRecordCreation DESC" 180 .
" LIMIT ".intval($Offset).
", ".intval($Count));
181 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
183 # for each resource ID found 184 foreach ($ResourceIds as $ResourceId)
186 # load resource and add to list of found resources 187 $Resources[$ResourceId] =
new Resource($ResourceId);
190 # return found resources to caller 204 # assume no resources will be found 205 $ResourceIds = array();
209 $Field = $Schema->GetField($FieldId);
214 # construct query based on field type 215 switch ($Field->Type())
220 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 221 .
" FROM Resources WHERE " 222 .$Field->DBFieldName().
" IS NOT NULL" 223 .
" AND LENGTH(LTRIM(RTRIM(".$Field->DBFieldName().
"))) > 0" 224 .
" AND SchemaId = ".intval($this->SchemaId),
228 $Query =
"SELECT ResourceId FROM Resources" 229 .
" WHERE SchemaId = ".intval($this->SchemaId)
230 .
" ORDER BY ".$Field->DBFieldName()
231 .($Ascending ?
" ASC" :
" DESC");
237 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 238 .
" FROM Resources WHERE " 239 .$Field->DBFieldName().
" IS NOT NULL" 240 .
" AND SchemaId = ".intval($this->SchemaId),
244 $Query =
"SELECT ResourceId FROM Resources" 245 .
" WHERE SchemaId = ".intval($this->SchemaId)
246 .
" ORDER BY ".$Field->DBFieldName()
247 .($Ascending ?
" ASC" :
" DESC");
252 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 253 .
" FROM Resources WHERE " 254 .$Field->DBFieldName().
"Begin IS NOT NULL" 255 .
" AND SchemaId = ".intval($this->SchemaId),
259 $Query =
"SELECT ResourceId FROM Resources" 260 .
" WHERE SchemaId = ".intval($this->SchemaId)
261 .
" ORDER BY ".$Field->DBFieldName().
"Begin" 262 .($Ascending ?
" ASC" :
" DESC");
267 # if appropriate query was found 270 # if limited number of results were requested 274 $Query .=
" LIMIT ".intval($Limit);
277 # perform query and retrieve resource IDs 278 $this->DB->Query($Query);
279 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
283 # return resource IDs to caller 298 # compute this user's class 299 $UserClass = $this->ComputeUserClass($User);
301 # generate an array where the keys are ResourceIds affected by 302 # user comparisons for the current user 303 $UserComparisonsRIDs = array_flip(
304 $this->ResourcesWhereUserComparisonsMatterForViewing($User));
306 # grab all the ResourceIds for this user class 307 $DB->Query(
"SELECT ResourceId, CanView FROM UserPermsCache WHERE" 308 .
" UserClass='".$UserClass.
"'");
310 # filter out those not requested 311 $Cache = array_intersect_key(
312 $DB->FetchColumn(
"CanView",
"ResourceId"),
313 array_flip($ResourceIds) );
315 # figure out which resources we didn't have cached values for 316 # and iterate over those 317 $MissingIds = array_diff( $ResourceIds, array_keys($Cache) );
318 foreach ($MissingIds as $Id)
320 # evaluate perms for this resource 322 $CanView = $Resource->UserCanView($User, FALSE);
324 # if this is a result we can cache, do so 325 if ( !isset($UserComparisonRIDs[$Id]) )
328 "INSERT INTO UserPermsCache (ResourceId, UserClass, CanView) " 329 .
"VALUES (".$Id.
",'".$UserClass.
"',".($CanView?
"1":
"0").
")");
332 $Cache[$Id] = $CanView;
335 # apply schema permissions hooks to all our values 336 foreach (array_keys($Cache) as $Id)
338 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
339 "EVENT_RESOURCE_VIEW_PERMISSION_CHECK",
343 "CanView" => $Cache[$Id],
344 "Schema" => $Schema, ));
345 $Cache[$Id] = $SignalResult[
"CanView"];
348 # filter out the non-viewable resources, preserving the order 351 foreach ($ResourceIds as $ResourceId)
353 if ($Cache[$ResourceId])
355 $Result[]= $ResourceId;
359 # return the viewable ResourceIds 369 $DB->Query(
"DELETE FROM UserPermsCache");
380 $LastChangeDate = $this->DB->Query(
381 "SELECT MAX(DateLastModified) AS LastChangeDate" 383 .
" WHERE SchemaId = ".intval($this->SchemaId)
384 .($OnlyReleasedResources ?
" AND ReleaseFlag = 1" :
""),
386 return ($LastChangeDate ? strtotime($LastChangeDate) : NULL);
396 # retrieve field names from schema 397 $FieldNames = array();
399 $Fields = $Schema->GetFields();
400 foreach ($Fields as $Field)
402 $FieldNames[$Field->Id()] = $Field->Name();
405 # return field names to caller 422 $ValuesToMatch, $AllRequired=TRUE, $ReturnObjects=TRUE)
424 # start out assuming we won't find any resources 425 $Resources = array();
432 $Fields = $Schema->GetFields();
434 foreach ($ValuesToMatch as $FieldId => $Value)
436 # retrieve metadata field ID if not supplied 437 if (!is_numeric($FieldId))
442 # if we're attempting to search a field that isn't in our schema, 444 if (!isset($Fields[$FieldId]))
447 "Attempt to match values against a field " 448 .
"that doesn't exist in this schema");
451 switch ($Fields[$FieldId]->Type())
460 $DBFname = $Fields[$FieldId]->DBFieldName();
461 # add comparison to condition 462 if ($Value ==
"NULL")
464 $Condition .= $LinkingTerm.
"(" 465 .$DBFname.
" IS NULL OR ".$DBFname.
" = '')";
469 $Condition .= $LinkingTerm.$DBFname.
470 " = '".addslashes($Value).
"'";
475 $DBFname = $Fields[$FieldId]->DBFieldName();
477 if ($Value ==
"NULL")
479 $Condition .= $LinkingTerm.
"(" 480 .$DBFname.
"X IS NULL AND " 481 .$DBFname.
"Y IS NULL)";
485 $Vx = addslashes($Value[
"X"]);
486 $Vy = addslashes($value[
"Y"]);
488 $Condition .= $LinkingTerm.
"(" 489 .$DBFname.
"X = '".$Vx.
"' AND " 490 .$DBFname.
"Y = '".$Vy.
"')";
495 $TgtValues = array();
496 if (is_object($Value))
498 $TgtValues[]= $Value->Id();
500 elseif (is_numeric($Value))
502 $TgtValues[]= $Value;
504 elseif (is_array($Value))
506 foreach ($Value as $UserId => $UserNameOrObject)
508 $TgtValues[]= $UserId;
512 # if no users were specified 513 if (!count($TgtValues))
515 # return no results (nothing matches nothing) 520 # add conditional to match specified users 521 $Condition .= $LinkingTerm.
"(" 522 .
"ResourceId IN (SELECT ResourceId FROM " 523 .
"ResourceUserInts WHERE FieldId=".intval($FieldId)
525 .implode(
",", $TgtValues).
")) )";
530 throw new Exception(
"Unsupported field type");
533 $LinkingTerm = $AllRequired ?
" AND " :
" OR ";
536 # if there were valid conditions 537 if (strlen($Condition))
539 # build query statment 540 $Query =
"SELECT ResourceId FROM Resources WHERE (".$Condition
541 .
") AND SchemaId = ".intval($this->SchemaId);
543 # execute query to retrieve matching resource IDs 544 $this->DB->Query($Query);
545 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
549 # retrieve resource objects 550 foreach ($ResourceIds as $Id)
552 $Resources[$Id] =
new Resource($Id);
557 $Resources = $ResourceIds;
561 # return any resources found to caller 575 # if the specified user is matched by any UserIs or UserIsNot 576 # privset conditions for any resources, then put them in a class 578 $UserClass = count($this->ResourcesWhereUserComparisonsMatterForViewing($User))
579 ?
"UID_".$User->Id() :
580 $this->ComputeUserClass($User);
582 # if we haven't loaded any cached values, do so now 583 if (!isset($this->CountCache[$UserClass]))
586 "SELECT ResourceCount, ValueId FROM " 587 .
"VisibleResourceCounts WHERE " 588 .
"SchemaId=".intval($this->SchemaId)
589 .
" AND UserClass='".addslashes($UserClass).
"'");
591 $this->CountCache[$UserClass] = $this->DB->FetchColumn(
592 "ResourceCount",
"ValueId");
595 # if we don't have a cached value for this class, 596 # queue a background update and return -1 597 if (!isset($this->CountCache[$UserClass][$ValueId]))
599 $GLOBALS[
"AF"]->QueueUniqueTask(
600 array($this,
"UpdateAssociatedVisibleResourceCount"),
601 array($ValueId, $User->Id() ) );
606 # owtherwise, return the cached data 607 return $this->CountCache[$UserClass][$ValueId];
619 $User =
new CWUser($UserId);
621 # if the specified user is matched by any UserIs or UserIsNot 622 # privset conditions for any resources, then put them in a class 624 $UserClass = count($this->ResourcesWhereUserComparisonsMatterForViewing($User))
625 ?
"UID_".$User->Id() :
626 $this->ComputeUserClass($User);
629 "SELECT ResourceId FROM ResourceNameInts " 630 .
"WHERE ControlledNameId=".intval($ValueId) );
631 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
634 $ResourceIds, $User);
636 $ResourceCount = count($ResourceIds);
639 "INSERT INTO VisibleResourceCounts " 640 .
"(SchemaId, UserClass, ValueId, ResourceCount) " 642 .intval($this->SchemaId).
"," 643 .
"'".addslashes($UserClass).
"'," 644 .intval($ValueId).
"," 645 .$ResourceCount.
")");
654 return $this->DB->Query(
" 655 SELECT COUNT(*) AS ResourceTotal 659 AND SchemaId = ".intval($this->SchemaId),
670 return $this->DB->Query(
" 671 SELECT COUNT(*) AS ResourceTotal 674 AND SchemaId = ".intval($this->SchemaId),
678 # ---- PRIVATE INTERFACE ------------------------------------------------- 690 private function ComputeUserClass( $User )
694 # if we don't already have a class cache, initialize one 695 if (!isset($ClassCache))
697 $ClassCache = array();
700 # put the anonymous user into their own user class, otherwise 701 # use the UserId for a key into the ClassCache 702 $UserId = is_null($User->Id()) ?
"XX-ANON-XX" : $User->Id();
704 # check if we have a cached UserClass for this User 705 if (!isset($ClassCache[$UserId]))
707 # assemble a list of the privilege flags (PRIV_SYSADMIN, 708 # etc) that are checked when evaluating the UserCanView for 709 # all fields in this schema 710 $RelevantPerms = array();
713 foreach ($Schema->GetFields() as $Field)
715 $RelevantPerms = array_merge(
717 $Field->ViewingPrivileges()->PrivilegeFlagsChecked() );
719 $RelevantPerms = array_unique($RelevantPerms);
721 # whittle the list of all privs checked down to just the 722 # list of privs that users in this class have 723 $PermsInvolved = array();
724 foreach ($RelevantPerms as $Perm)
726 if ($User->HasPriv($Perm))
728 $PermsInvolved[]= $Perm;
732 # generate a string by concatenating all the involved 733 # permissions then hashing the result (hashing gives 734 # a fixed-size string for storing in the database) 735 $ClassCache[$UserId] = md5( implode(
"-", $PermsInvolved ) );
738 return $ClassCache[$UserId];
750 private function ResourcesWhereUserComparisonsMatterForViewing($User)
752 $ResourceIds = array();
754 # if we're checking the anonymous user, presume that 756 if (is_null($User->Id()))
763 # for each comparison type 764 foreach (array(
"==",
"!=") as $ComparisonType)
766 # iterate through all the fields in the schema, 767 # constructing a list of the User fields implicated 768 # in comparisons of the desired type 769 $UserComparisonFields = array();
770 foreach ($Schema->GetFields() as $Field)
772 $UserComparisonFields = array_merge(
773 $UserComparisonFields,
774 $Field->ViewingPrivileges()->FieldsWithUserComparisons(
777 $UserComparisonFields = array_unique($UserComparisonFields);
779 # if we have any fields to check 780 if (count($UserComparisonFields) > 0 )
782 # query the database for resources where one or more of the 783 # user comparisons will be satisfied 784 $SqlOp = ($ComparisonType ==
"==") ?
"= " :
"!= ";
786 $DB->Query(
"SELECT R.ResourceId as ResourceId FROM ".
787 "Resources R, ResourceUserInts RU WHERE ".
788 "R.SchemaId = ".$this->SchemaId.
" AND ".
789 "R.ResourceId = RU.ResourceId AND ".
790 "RU.UserId ".$SqlOp.$User->Id().
" AND ".
791 "RU.FieldId IN (".implode(
",", $UserComparisonFields).
")");
792 $Result =
$DB->FetchColumn(
"ResourceId");
794 # merge those resources into our results 795 $ResourceIds = array_merge(
801 return array_unique($ResourceIds);
GetRatedResourceUserCount()
Return number of users who have rated resources.
SQL database abstraction object with smart query caching.
GetTimestampOfLastResourceModification($OnlyReleasedResources=TRUE)
Get date/time of when last a resource was modified.
GetResourceIdsSortedBy($FieldId, $Ascending=TRUE, $Limit=NULL)
Get resource IDs sorted by specified field.
ClearViewingPermsCache()
Clear the cache of viewable resources.
UpdateAssociatedVisibleResourceCount($ValueId, $UserId)
Update the count of resources associated with a ControlledName that are visible to a specified user...
GetRecentlyReleasedResources($Count=10, $Offset=0, $MaxDaysToGoBack=90)
Get resources sorted by descending Date of Record Release, with Date of Record Creation as the second...
AssociatedVisibleResourceCount($ValueId, $User)
Return the number of resources visible to a specified user that have a given ControlledName value set...
FilterNonViewableResources($ResourceIds, $User)
Filter a list of resources leaving only those viewable by a specified user.
ClearQualifier($ObjectOrId, $NewObjectOrId=NULL)
Clear or change specific qualifier for all resources.
Represents a "resource" in CWIS.
GetPossibleFieldNames()
Get possible field names for resources.
GetReleasedResourceTotal()
Get the total number of released resources in the collection.
GetMatchingResources($ValuesToMatch, $AllRequired=TRUE, $ReturnObjects=TRUE)
Find resources with values that match those specified.
__construct($SchemaId=MetadataSchema::SCHEMAID_DEFAULT)
Class constructor.
static Create($SchemaId)
Create a new resource.
Common factory class for item manipulation.
GetRatedResourceCount()
Return number of resources that have ratings.
Factory for Resource objects.
CWIS-specific user class.
GetResourceTotal()
Get the total number of resources in the collection, even if they are not released.
DuplicateResource($ResourceId)
Duplicate the specified resource and return to caller.