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 # check that resource to be duplicated exists 45 throw new InvalidArgumentException(
46 "No resource found with specified ID (".$ResourceId.
").");
49 # create new target resource 52 # load up resource to duplicate 53 $SrcResource =
new Resource($ResourceId);
55 # for each metadata field 57 $Fields = $Schema->GetFields();
58 foreach ($Fields as $Field)
60 if ($Field->CopyOnResourceDuplication())
62 $NewValue = $SrcResource->GetByField($Field, TRUE);
64 # clear default value from destination resource that is 65 # set when creating a new resource 66 $DstResource->ClearByField($Field);
68 # copy value from source resource to destination resource 69 $DstResource->SetByField($Field, $NewValue);
73 # return new resource to caller 85 # sanitize qualifier ID or retrieve from object 86 $QualifierId = is_object($ObjectOrId)
87 ? $ObjectOrId->Id() : intval($ObjectOrId);
89 # if new qualifier passed in 90 if ($NewObjectOrId !== NULL)
92 # sanitize qualifier ID to change to or retrieve it from object 93 $NewQualifierIdVal = is_object($NewObjectOrId)
94 ? $NewObjectOrId->Id() : intval($NewObjectOrId);
98 # qualifier should be cleared 99 $NewQualifierIdVal =
"NULL";
102 # for each metadata field 104 $Fields = $Schema->GetFields();
105 foreach ($Fields as $Field)
107 # if field uses qualifiers and uses item-level qualifiers 108 $QualColName = $Field->DBFieldName().
"Qualifier";
109 if ($Field->UsesQualifiers()
110 && $Field->HasItemLevelQualifiers()
111 && $this->DB->FieldExists(
"Resources", $QualColName))
113 # set all occurrences to new qualifier value 114 $this->DB->Query(
"UPDATE Resources" 115 .
" SET ".$QualColName.
" = ".$NewQualifierIdVal.
"" 116 .
" WHERE ".$QualColName.
" = '".$QualifierId.
"'" 117 .
" AND SchemaId = ".intval($this->SchemaId));
121 # clear or change qualifier association with controlled names 122 # (NOTE: this should probably be done in a controlled name factory object) 123 $this->DB->Query(
"UPDATE ControlledNames" 124 .
" SET QualifierId = ".$NewQualifierIdVal
125 .
" WHERE QualifierId = '".$QualifierId.
"'");
127 # clear or change qualifier association with classifications 128 # (NOTE: this should probably be done in a classification factory object) 129 $this->DB->Query(
"UPDATE Classifications" 130 .
" SET QualifierId = ".$NewQualifierIdVal
131 .
" WHERE QualifierId = '".$QualifierId.
"'");
140 return $this->DB->Query(
141 "SELECT COUNT(DISTINCT ResourceId) AS ResourceCount" 142 .
" FROM ResourceRatings",
152 return $this->DB->Query(
153 "SELECT COUNT(DISTINCT UserId) AS UserCount" 154 .
" FROM ResourceRatings",
168 $Count = 10, $Offset = 0, $MaxDaysToGoBack = 90)
170 # assume that no resources will be found 171 $Resources = array();
173 # calculate cutoff date for resources 174 $CutoffDate = date(
"Y-m-d H:i:s", strtotime($MaxDaysToGoBack.
" days ago"));
176 # query for resource IDs 177 $this->DB->Query(
"SELECT ResourceId FROM Resources WHERE" 178 .
" DateOfRecordRelease > '".$CutoffDate.
"'" 179 .
" AND ReleaseFlag = 1" 180 .
" AND ResourceId >= 0" 181 .
" AND SchemaId = ".intval($this->SchemaId)
182 .
" ORDER BY DateOfRecordRelease DESC, DateOfRecordCreation DESC" 183 .
" LIMIT ".intval($Offset).
", ".intval($Count));
184 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
186 # for each resource ID found 187 foreach ($ResourceIds as $ResourceId)
189 # load resource and add to list of found resources 190 $Resources[$ResourceId] =
new Resource($ResourceId);
193 # return found resources to caller 207 # assume no resources will be found 208 $ResourceIds = array();
212 $Field = $Schema->GetField($FieldId);
217 # construct query based on field type 218 switch ($Field->Type())
223 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 224 .
" FROM Resources WHERE " 225 .$Field->DBFieldName().
" IS NOT NULL" 226 .
" AND LENGTH(LTRIM(RTRIM(".$Field->DBFieldName().
"))) > 0" 227 .
" AND SchemaId = ".intval($this->SchemaId),
231 $Query =
"SELECT ResourceId FROM Resources" 232 .
" WHERE SchemaId = ".intval($this->SchemaId)
233 .
" ORDER BY ".$Field->DBFieldName()
234 .($Ascending ?
" ASC" :
" DESC");
240 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 241 .
" FROM Resources WHERE " 242 .$Field->DBFieldName().
" IS NOT NULL" 243 .
" AND SchemaId = ".intval($this->SchemaId),
247 $Query =
"SELECT ResourceId FROM Resources" 248 .
" WHERE SchemaId = ".intval($this->SchemaId)
249 .
" ORDER BY ".$Field->DBFieldName()
250 .($Ascending ?
" ASC" :
" DESC");
255 $Count = $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount" 256 .
" FROM Resources WHERE " 257 .$Field->DBFieldName().
"Begin IS NOT NULL" 258 .
" AND SchemaId = ".intval($this->SchemaId),
262 $Query =
"SELECT ResourceId FROM Resources" 263 .
" WHERE SchemaId = ".intval($this->SchemaId)
264 .
" ORDER BY ".$Field->DBFieldName().
"Begin" 265 .($Ascending ?
" ASC" :
" DESC");
270 # if appropriate query was found 273 # if limited number of results were requested 277 $Query .=
" LIMIT ".intval($Limit);
280 # perform query and retrieve resource IDs 281 $this->DB->Query($Query);
282 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
286 # return resource IDs to caller 301 # compute this user's class 302 $UserClass = $this->ComputeUserClass($User);
304 # generate an array where the keys are ResourceIds affected by 305 # user comparisons for the current user 306 $UserComparisonsRIDs = array_flip(
307 $this->ResourcesWhereUserComparisonsMatterForViewing($User));
309 # grab all the ResourceIds for this user class 310 $DB->Query(
"SELECT ResourceId, CanView FROM UserPermsCache WHERE" 311 .
" UserClass='".$UserClass.
"'");
313 # filter out those not requested 314 $Cache = array_intersect_key(
315 $DB->FetchColumn(
"CanView",
"ResourceId"),
316 array_flip($ResourceIds) );
318 # figure out which resources we didn't have cached values for 319 # and iterate over those 320 $MissingIds = array_diff( $ResourceIds, array_keys($Cache) );
321 foreach ($MissingIds as $Id)
323 # evaluate perms for this resource 325 $CanView = $Resource->UserCanView($User, FALSE);
327 # if this is a result we can cache, do so 328 if ( !isset($UserComparisonRIDs[$Id]) )
331 "INSERT INTO UserPermsCache (ResourceId, UserClass, CanView) " 332 .
"VALUES (".$Id.
",'".$UserClass.
"',".($CanView?
"1":
"0").
")");
335 $Cache[$Id] = $CanView;
338 # apply schema permissions hooks to all our values 339 foreach (array_keys($Cache) as $Id)
341 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
342 "EVENT_RESOURCE_VIEW_PERMISSION_CHECK",
346 "CanView" => $Cache[$Id],
347 "Schema" => $Schema, ));
348 $Cache[$Id] = $SignalResult[
"CanView"];
351 # filter out the non-viewable resources, preserving the order 354 foreach ($ResourceIds as $ResourceId)
356 if ($Cache[$ResourceId])
358 $Result[]= $ResourceId;
362 # return the viewable ResourceIds 372 $DB->Query(
"DELETE FROM UserPermsCache");
383 $LastChangeDate = $this->DB->Query(
384 "SELECT MAX(DateLastModified) AS LastChangeDate" 386 .
" WHERE SchemaId = ".intval($this->SchemaId)
387 .($OnlyReleasedResources ?
" AND ReleaseFlag = 1" :
""),
389 return ($LastChangeDate ? strtotime($LastChangeDate) : NULL);
399 # retrieve field names from schema 400 $FieldNames = array();
402 $Fields = $Schema->GetFields();
403 foreach ($Fields as $Field)
405 $FieldNames[$Field->Id()] = $Field->Name();
408 # return field names to caller 425 $ValuesToMatch, $AllRequired=TRUE, $ReturnObjects=TRUE)
427 # start out assuming we won't find any resources 428 $Resources = array();
435 $Fields = $Schema->GetFields();
437 foreach ($ValuesToMatch as $FieldId => $Value)
439 # retrieve metadata field ID if not supplied 440 if (!is_numeric($FieldId))
442 $FieldId = $Schema->GetFieldIdByName($FieldId);
445 # if we're attempting to search a field that isn't in our schema, 447 if (!isset($Fields[$FieldId]))
450 "Attempt to match values against a field " 451 .
"that doesn't exist in this schema");
454 switch ($Fields[$FieldId]->Type())
463 $DBFname = $Fields[$FieldId]->DBFieldName();
464 # add comparison to condition 465 if ($Value ==
"NULL")
467 $Condition .= $LinkingTerm.
"(" 468 .$DBFname.
" IS NULL OR ".$DBFname.
" = '')";
472 $Condition .= $LinkingTerm.$DBFname.
473 " = '".addslashes($Value).
"'";
478 $DBFname = $Fields[$FieldId]->DBFieldName();
480 if ($Value ==
"NULL")
482 $Condition .= $LinkingTerm.
"(" 483 .$DBFname.
"X IS NULL AND " 484 .$DBFname.
"Y IS NULL)";
488 $Vx = addslashes($Value[
"X"]);
489 $Vy = addslashes($value[
"Y"]);
491 $Condition .= $LinkingTerm.
"(" 492 .$DBFname.
"X = '".$Vx.
"' AND " 493 .$DBFname.
"Y = '".$Vy.
"')";
498 $TgtValues = array();
499 if (is_object($Value))
501 $TgtValues[]= $Value->Id();
503 elseif (is_numeric($Value))
505 $TgtValues[]= $Value;
507 elseif (is_array($Value))
509 foreach ($Value as $UserId => $UserNameOrObject)
511 $TgtValues[]= $UserId;
515 # if no users were specified 516 if (!count($TgtValues))
518 # return no results (nothing matches nothing) 523 # add conditional to match specified users 524 $Condition .= $LinkingTerm.
"(" 525 .
"ResourceId IN (SELECT ResourceId FROM " 526 .
"ResourceUserInts WHERE FieldId=".intval($FieldId)
528 .implode(
",", $TgtValues).
")) )";
533 throw new Exception(
"Unsupported field type");
536 $LinkingTerm = $AllRequired ?
" AND " :
" OR ";
539 # if there were valid conditions 540 if (strlen($Condition))
542 # build query statment 543 $Query =
"SELECT ResourceId FROM Resources WHERE (".$Condition
544 .
") AND SchemaId = ".intval($this->SchemaId);
546 # execute query to retrieve matching resource IDs 547 $this->DB->Query($Query);
548 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
552 # retrieve resource objects 553 foreach ($ResourceIds as $Id)
555 $Resources[$Id] =
new Resource($Id);
560 $Resources = $ResourceIds;
564 # return any resources found to caller 578 # if the specified user is matched by any UserIs or UserIsNot 579 # privset conditions for any resources, then put them in a class 581 $UserClass = count($this->ResourcesWhereUserComparisonsMatterForViewing($User))
582 ?
"UID_".$User->Id() :
583 $this->ComputeUserClass($User);
585 # if we haven't loaded any cached values, do so now 586 if (!isset($this->CountCache[$UserClass]))
589 "SELECT ResourceCount, ValueId FROM " 590 .
"VisibleResourceCounts WHERE " 591 .
"SchemaId=".intval($this->SchemaId)
592 .
" AND UserClass='".addslashes($UserClass).
"'");
594 $this->CountCache[$UserClass] = $this->DB->FetchColumn(
595 "ResourceCount",
"ValueId");
598 # if we don't have a cached value for this class, 599 # queue a background update and return -1 600 if (!isset($this->CountCache[$UserClass][$ValueId]))
602 $GLOBALS[
"AF"]->QueueUniqueTask(
603 array($this,
"UpdateAssociatedVisibleResourceCount"),
604 array($ValueId, $User->Id() ) );
609 # owtherwise, return the cached data 610 return $this->CountCache[$UserClass][$ValueId];
622 $User =
new CWUser($UserId);
624 # if the specified user is matched by any UserIs or UserIsNot 625 # privset conditions for any resources, then put them in a class 627 $UserClass = count($this->ResourcesWhereUserComparisonsMatterForViewing($User))
628 ?
"UID_".$User->Id() :
629 $this->ComputeUserClass($User);
632 "SELECT ResourceId FROM ResourceNameInts " 633 .
"WHERE ControlledNameId=".intval($ValueId) );
634 $ResourceIds = $this->DB->FetchColumn(
"ResourceId");
637 $ResourceIds, $User);
639 $ResourceCount = count($ResourceIds);
642 "INSERT INTO VisibleResourceCounts " 643 .
"(SchemaId, UserClass, ValueId, ResourceCount) " 645 .intval($this->SchemaId).
"," 646 .
"'".addslashes($UserClass).
"'," 647 .intval($ValueId).
"," 648 .$ResourceCount.
")");
657 return $this->DB->Query(
" 658 SELECT COUNT(*) AS ResourceTotal 662 AND SchemaId = ".intval($this->SchemaId),
673 return $this->DB->Query(
" 674 SELECT COUNT(*) AS ResourceTotal 677 AND SchemaId = ".intval($this->SchemaId),
681 # ---- PRIVATE INTERFACE ------------------------------------------------- 693 private function ComputeUserClass( $User )
697 # if we don't already have a class cache, initialize one 698 if (!isset($ClassCache))
700 $ClassCache = array();
703 # put the anonymous user into their own user class, otherwise 704 # use the UserId for a key into the ClassCache 705 $UserId = is_null($User->Id()) ?
"XX-ANON-XX" : $User->Id();
707 # check if we have a cached UserClass for this User 708 if (!isset($ClassCache[$UserId]))
710 # assemble a list of the privilege flags (PRIV_SYSADMIN, 711 # etc) that are checked when evaluating the UserCanView for 712 # all fields in this schema 713 $RelevantPerms = array();
716 foreach ($Schema->GetFields() as $Field)
718 $RelevantPerms = array_merge(
720 $Field->ViewingPrivileges()->PrivilegeFlagsChecked() );
722 $RelevantPerms = array_unique($RelevantPerms);
724 # whittle the list of all privs checked down to just the 725 # list of privs that users in this class have 726 $PermsInvolved = array();
727 foreach ($RelevantPerms as $Perm)
729 if ($User->HasPriv($Perm))
731 $PermsInvolved[]= $Perm;
735 # generate a string by concatenating all the involved 736 # permissions then hashing the result (hashing gives 737 # a fixed-size string for storing in the database) 738 $ClassCache[$UserId] = md5( implode(
"-", $PermsInvolved ) );
741 return $ClassCache[$UserId];
753 private function ResourcesWhereUserComparisonsMatterForViewing($User)
755 $ResourceIds = array();
757 # if we're checking the anonymous user, presume that 759 if (is_null($User->Id()))
766 # for each comparison type 767 foreach (array(
"==",
"!=") as $ComparisonType)
769 # iterate through all the fields in the schema, 770 # constructing a list of the User fields implicated 771 # in comparisons of the desired type 772 $UserComparisonFields = array();
773 foreach ($Schema->GetFields() as $Field)
775 $UserComparisonFields = array_merge(
776 $UserComparisonFields,
777 $Field->ViewingPrivileges()->FieldsWithUserComparisons(
780 $UserComparisonFields = array_unique($UserComparisonFields);
782 # if we have any fields to check 783 if (count($UserComparisonFields) > 0 )
785 # query the database for resources where one or more of the 786 # user comparisons will be satisfied 787 $SqlOp = ($ComparisonType ==
"==") ?
"= " :
"!= ";
789 $DB->Query(
"SELECT R.ResourceId as ResourceId FROM ".
790 "Resources R, ResourceUserInts RU WHERE ".
791 "R.SchemaId = ".$this->SchemaId.
" AND ".
792 "R.ResourceId = RU.ResourceId AND ".
793 "RU.UserId ".$SqlOp.$User->Id().
" AND ".
794 "RU.FieldId IN (".implode(
",", $UserComparisonFields).
")");
795 $Result =
$DB->FetchColumn(
"ResourceId");
797 # merge those resources into our results 798 $ResourceIds = array_merge(
804 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.
static ItemExists($Id)
Check whether an item exists with the specified ID.
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.