3 # FILE: Classification.php
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2002-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
15 # ---- PUBLIC INTERFACE --------------------------------------------------
42 function Classification($ClassId, $Name = NULL, $FieldId = NULL, $ParentId = NULL)
46 # assume everything will turn out okay
47 $this->ErrorStatus = self::CLASSSTAT_OK;
49 # create DB handle for our use
53 # if class ID not given (indicating class must be created)
54 if ($ClassId === NULL)
56 # if parent class supplied
57 if ($ParentId !== NULL)
59 # if parent ID was invalid
61 && ($DB->Query(
"SELECT COUNT(*) AS NumberFound"
62 .
" FROM Classifications"
63 .
" WHERE ClassificationId = ".intval($ParentId),
66 # set error code for bad parent ID
67 $this->ErrorStatus = self::CLASSSTAT_INVALIDPARENTID;
71 # if name already exists
73 if ($FieldId === NULL)
75 # If we know what field we're trying to add a classifcation for,
76 # Check just within that field
77 $Count = $DB->Query(
"SELECT COUNT(*) AS NumberFound FROM Classifications"
78 .
" WHERE ParentId = ".intval($ParentId)
79 .
" AND LOWER(SegmentName) = '"
80 .addslashes(strtolower($Name)).
"'",
85 # Otherwise, check all classifications for all fields
86 $Count = $DB->Query(
"SELECT COUNT(*) AS NumberFound FROM Classifications"
87 .
" WHERE ParentId = ".intval($ParentId)
88 .
" AND FieldId = ".intval($FieldId)
89 .
" AND LOWER(SegmentName) = '"
90 .addslashes(strtolower($Name)).
"'",
96 # set error code for duplicate class name
97 $this->ErrorStatus = self::CLASSSTAT_DUPLICATENAME;
101 # add class to database
102 $ParentId = intval($ParentId);
110 $DB->Query(
"SELECT ClassificationName, Depth"
111 .
" FROM Classifications"
112 .
" WHERE ClassificationId = ".$ParentId);
113 $ParentInfo = $DB->FetchRow();
114 $NewName = $ParentInfo[
"ClassificationName"].
" -- ".$Name;
115 $NewDepth = $ParentInfo[
"Depth"] + 1;
117 $DB->Query(
"INSERT INTO Classifications"
118 .
" (FieldId, ParentId, SegmentName, ResourceCount,"
119 .
" Depth, ClassificationName) VALUES"
120 .
" (".intval($FieldId).
", ".$ParentId.
","
121 .
" '".addslashes($Name).
"', 0, "
122 .$NewDepth.
", '".addslashes($NewName).
"')");
124 # retrieve ID of new class
125 $this->
Id = $DB->LastInsertId();
131 # parse classification name into separate segments
132 $Segments = preg_split(
"/--/", $Name);
134 # start out with top as parent
139 $CurrentFullName =
"";
140 foreach ($Segments as $Segment)
142 # track segment depth and full classification name for use in adding new entries
143 $Segment = trim($Segment);
145 $CurrentFullName .= (($CurrentFullName ==
"") ?
"" :
" -- ").$Segment;
147 # if we have added classifications
148 $Segment = addslashes($Segment);
151 # we know that current segment will not be found
156 # look up classification with current parent and segment name
157 if (!isset($IdCache[$FieldId][$ParentId][$Segment]))
161 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
162 "SELECT ClassificationId FROM Classifications"
163 .
" WHERE ParentId = -1"
164 .
" AND SegmentName = '".addslashes($Segment).
"'"
165 .
" AND FieldId = ".intval($FieldId),
170 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
171 "SELECT ClassificationId FROM Classifications "
172 .
"WHERE ParentId = ".intval($ParentId)
173 .
" AND SegmentName = '".addslashes($Segment).
"'",
177 $ClassId = $IdCache[$FieldId][$ParentId][$Segment];
180 # if classification not found
181 if ($ClassId === NULL)
183 # add new classification
184 $DB->Query(
"INSERT INTO Classifications "
185 .
"(FieldId, ParentId, SegmentName,"
186 .
" ClassificationName, Depth, ResourceCount) "
187 .
"VALUES (".intval($FieldId).
", "
188 .intval($ParentId).
", "
189 .
"'".addslashes($Segment).
"', "
190 .
"'".addslashes($CurrentFullName).
"', "
191 .intval($CurrentDepth).
", 0)");
192 $ClassId = $DB->LastInsertId();
193 $IdCache[$FieldId][$ParentId][$Segment] = $ClassId;
195 # track total number of new classification segments created
199 # set parent to created or found class
200 $PreviousParentId = $ParentId;
201 $ParentId = $ClassId;
204 # our class ID is the one that was last found
205 $this->
Id = $ClassId;
210 # our class ID is the one that was supplied by caller
211 $this->
Id = intval($ClassId);
214 # if no error encountered
215 if ($this->ErrorStatus == self::CLASSSTAT_OK)
217 # load in attributes from database
218 $DB->Query(
"SELECT * FROM Classifications"
219 .
" WHERE ClassificationId = ".intval($this->
Id));
220 $this->DBFields = $DB->NumRowsSelected()>0 ? $DB->FetchRow() : NULL ;
222 # set error status if class info not loaded
223 if ($this->DBFields === NULL ||
224 $this->DBFields[
"ClassificationId"] != $this->
Id)
226 $this->ErrorStatus = self::CLASSSTAT_INVALIDID;
235 function Status() {
return $this->ErrorStatus; }
241 function Id() {
return $this->Id; }
249 return $this->DBFields[
"ClassificationName"];
268 function Depth() {
return $this->DBFields[
"Depth"]; }
295 function ParentId() {
return $this->DBFields[
"ParentId"]; }
303 return $this->UpdateValue(
"SegmentName", $NewValue); }
313 return $this->UpdateValue(
"LinkString", $NewValue); }
322 return $this->UpdateValue(
"QualifierId", $NewValue); }
330 return $this->UpdateValue(
"FieldId", $NewValue); }
340 # if new qualifier supplied
343 # set new qualifier ID
346 # use new qualifier for return value
347 $Qualifier = $NewValue;
351 # if qualifier is available
354 # create qualifier object using stored ID
359 # return NULL to indicate no qualifier
364 # return qualifier to caller
377 # start with full classification name set to our segment name
378 $FullClassName = $this->DBFields[
"SegmentName"];
380 # assume to begin with that we're at the top of the hierarchy
383 # while parent available
384 $ParentId = $this->DBFields[
"ParentId"];
385 while ($ParentId != -1)
387 # retrieve classification information
388 $DB->Query(
"SELECT SegmentName, ParentId "
389 .
"FROM Classifications "
390 .
"WHERE ClassificationId=".$ParentId);
391 $Record = $DB->FetchRow();
393 # prepend segment name to full classification name
394 $FullClassName = $Record[
"SegmentName"].
" -- ".$FullClassName;
396 # increment depth value
399 # move to parent of current classification
400 $ParentId = $Record[
"ParentId"];
404 $DB->Query(
"SELECT ClassificationId "
405 .
"FROM Classifications "
406 .
"WHERE ParentId=".intval($this->
Id));
407 while ($Record = $DB->FetchRow())
409 # perform depth and name recalc
411 $Child->RecalcDepthAndFullName();
414 # save new depth and full classification name
415 $DB->Query(
"UPDATE Classifications SET "
416 .
"Depth=".intval($Depth).
", "
417 .
"ClassificationName='".addslashes($FullClassName).
"' "
418 .
"WHERE ClassificationId=".intval($this->
Id));
419 $this->DBFields[
"ClassificationName"] = $FullClassName;
420 $this->DBFields[
"Depth"] = $Depth;
428 $this->DB->Query(
"UPDATE Classifications SET LastAssigned=NOW() "
429 .
"WHERE ClassificationId=".intval($this->
Id));
441 $IdsUpdated = array();
443 # if we don't have a skip list or we aren't in the skip list
444 if (!$IdsToSkip || !in_array($this->
Id, $IdsToSkip))
446 # retrieve new count of resources directly associated with class
447 $this->DB->Query(
"SELECT COUNT(*) AS ResourceCount"
448 .
" FROM ResourceClassInts, Resources"
449 .
" WHERE ClassificationId=".intval($this->
Id)
450 .
" AND ResourceClassInts.ResourceId = Resources.ResourceId"
451 .
" AND Resources.ResourceId > 0"
452 .
" AND ReleaseFlag = 1");
453 $Record = $this->DB->FetchRow();
454 $ResourceCount = $Record[
"ResourceCount"];
456 # add on resources associated with all children
457 $ResourceCount += $this->DB->Query(
458 "SELECT SUM(ResourceCount) AS ResourceCountTotal "
459 .
"FROM Classifications "
460 .
"WHERE ParentId = ".intval($this->
Id),
461 "ResourceCountTotal");
463 # save new count to database
464 $this->DB->Query(
"UPDATE Classifications SET "
465 .
"ResourceCount=".$ResourceCount.
" "
466 .
"WHERE ClassificationId=".intval($this->
Id));
468 # save new count to our local cache
469 $this->DBFields[
"ResourceCount"] = $ResourceCount;
471 # add our ID to list of IDs that have been recalculated
472 $IdsUpdated[] = $this->Id;
475 # update resource count for our parent (if any)
476 if (($this->DBFields[
"ParentId"] != -1)
477 && (!$IdsToSkip || !in_array($this->DBFields[
"ParentId"], $IdsToSkip)) )
480 if ($Class->Status() == self::CLASSSTAT_OK)
482 $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
486 # retrieve new count of all resources directly associated with class
487 $FullCount = $this->DB->Query(
"
488 SELECT COUNT(*) AS ResourceCount
489 FROM ResourceClassInts I, Resources R
490 WHERE I.ClassificationId = '".intval($this->
Id).
"'
492 AND I.ResourceId = R.ResourceId",
495 # add on resources associated with all children
496 $FullCount += $this->DB->Query(
"
497 SELECT SUM(ResourceCount) AS ResourceCountTotal
499 WHERE ParentId = '".intval($this->
Id).
"'",
500 "ResourceCountTotal");
502 # save new count to database
504 UPDATE Classifications
505 SET FullResourceCount = '".intval($FullCount).
"'
506 WHERE ClassificationId = '".intval($this->
Id).
"'");
508 # save new count to our local cache
509 $this->DBFields[
"FullResourceCount"] = $FullCount;
511 # return list of IDs of updated classifications to caller
521 # return count of classifications that have this one as parent
522 return $this->DB->Query(
"SELECT COUNT(*) AS ClassCount "
523 .
"FROM Classifications "
524 .
"WHERE ParentId=".intval($this->
Id),
535 $ChildList = array();
537 $this->DB->Query(
"SELECT ClassificationId "
538 .
"FROM Classifications "
539 .
"WHERE ParentId=".intval($this->
Id));
541 while ($Entry = $this->DB->FetchRow())
543 $ChildList[] = $Entry[
"ClassificationId"];
545 if($Child->ChildCount() > 0)
547 $GrandChildList = $Child->ChildList();
548 $ChildList = array_merge($GrandChildList, $ChildList);
567 $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
571 # if no resources or okay to delete with resources
572 # and no children or okay to delete with children
574 && ($DeleteIfHasChildren || ($this->
ChildCount() == 0)))
576 $ParentId = $this->DBFields[
"ParentId"];
578 if ($DeleteIfHasResources)
580 $DB->Query(
"DELETE FROM ResourceClassInts "
581 .
"WHERE ClassificationId=".intval($this->
Id));
584 # delete this classification
585 $DB->Query(
"DELETE FROM Classifications "
586 .
"WHERE ClassificationId=".intval($this->
Id));
588 # delete parent classification (if requested)
589 if (($DeleteParents) && ($this->DBFields[
"ParentId"] != -1))
593 TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
599 # ---- PRIVATE INTERFACE -------------------------------------------------
604 private $ErrorStatus;
605 private $SegmentsCreated;
614 private function UpdateValue($FieldName, $NewValue)
616 return $this->DB->UpdateValue(
"Classifications", $FieldName, $NewValue,
617 "ClassificationId = ".intval($this->
Id),
618 $this->DBFields, TRUE);
LinkString($NewValue=DB_NOVALUE)
Get or set the stored link string for the Classification.
const CLASSSTAT_INVALIDPARENTID
Status code indicating an invalid parent classification ID was specified.
FullName()
Get full classification name (all segments).
FullResourceCount()
Get number of all resources (minus temporary ones) having this classification assigned to them...
SQL database abstraction object with smart query caching.
const CLASSSTAT_INVALIDID
Status code indicating an invalid classification ID was specified.
FieldId($NewValue=DB_NOVALUE)
Get or set the ID of the MetadataField for the Classification.
VariantName()
Get variant name of classification, if any.
Qualifier($NewValue=DB_NOVALUE)
Get or set the Qualifier associated with the Classification.
ChildCount()
Get number of classifications that have this Classification as their direct parent.
Classification($ClassId, $Name=NULL, $FieldId=NULL, $ParentId=NULL)
Class constructor.
RecalcResourceCount($IdsToSkip=NULL)
Recalculate number of resources assigned to class and any parent classes.
Name()
Get name of classification segment.
ParentId()
Get ID of parent Classification.
SegmentsCreated()
Get number of new segments (Classifications) generated when creating a new Classification with a full...
RecalcDepthAndFullName()
Rebuild classification full name and recalculate depth in hierarchy.
Status()
Returns success/failure code for last call (where applicable).
Depth()
Get depth of classification in hierarchy.
const CLASSSTAT_DUPLICATENAME
Status code indicating a duplicate classification name was specified.
ResourceCount()
Get number of released resources having this classification assigned to them.
Delete($DeleteParents=FALSE, $DeleteIfHasResources=FALSE, $DeleteIfHasChildren=FALSE)
Remove Classification (and accompanying associations) from database.
const CLASSSTAT_OK
Status code indicating operation completed successfully.
UpdateLastAssigned()
Update the LastAssigned timestamp for this classification.
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
QualifierId($NewValue=DB_NOVALUE)
Get or set the Qualifier associated with the Classification by ID.
ChildList()
Get list of IDs of Classifications that have this class as an "ancestor" (parent, grandparent...
SegmentName($NewValue=DB_NOVALUE)
Get or set the segment name.
Id()
Get Classification ID.