CWIS Developer Documentation
Classification.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Classification.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2002-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
13 class Classification extends Item
14 {
15  # ---- PUBLIC INTERFACE --------------------------------------------------
16 
18  const NOPARENT = -1;
19 
31  public static function Create($Name, $FieldId, $ParentId = NULL)
32  {
33  static $IdCache;
34 
35  # initialize state for creation
36  self::$SegmentsCreated = 0;
37 
38  # if parent class supplied
39  $DB = new Database();
40  if ($ParentId !== NULL)
41  {
42  # error out if parent ID is invalid
43  if ($ParentId != self::NOPARENT)
44  {
45  if ($DB->Query("SELECT COUNT(*) AS NumberFound"
46  ." FROM Classifications"
47  ." WHERE ClassificationId = ".intval($ParentId),
48  "NumberFound") < 1)
49  {
50  throw new InvalidArgumentException("Invalid parent ID"
51  ." specified (".$ParentId.").");
52  }
53  }
54 
55  # error out if name already exists
56  $Name = trim($Name);
57  $Count = $DB->Query("SELECT COUNT(*) AS NumberFound"
58  ." FROM Classifications"
59  ." WHERE ParentId = ".intval($ParentId)
60  ." AND FieldId = ".intval($FieldId)
61  ." AND LOWER(SegmentName) = '"
62  .addslashes(strtolower($Name))."'",
63  "NumberFound");
64  if ($Count > 0)
65  {
66  throw new Exception("Duplicate name specified for"
67  ." new classification (".$Name.").");
68  }
69 
70  # determine full name and depth for new classification
71  if ($ParentId == self::NOPARENT)
72  {
73  $NewName = $Name;
74  $NewDepth = 0;
75  }
76  else
77  {
78  $DB->Query("SELECT ClassificationName, Depth"
79  ." FROM Classifications"
80  ." WHERE ClassificationId = ".intval($ParentId));
81  $ParentInfo = $DB->FetchRow();
82  $NewName = $ParentInfo["ClassificationName"]." -- ".$Name;
83  $NewDepth = $ParentInfo["Depth"] + 1;
84  }
85 
86  # add classification to database
87  $InitialValues = array(
88  "FieldId" => $FieldId,
89  "ParentId" => $ParentId,
90  "SegmentName" => $Name,
91  "ResourceCount" => 0,
92  "Depth" => $NewDepth,
93  "ClassificationName" => $NewName);
94  $NewItem = parent::CreateWithValues($InitialValues);
95  }
96  else
97  {
98  # parse classification name into separate segments
99  $Segments = preg_split("/--/", $Name);
100 
101  # start out with top as parent
102  $ParentId = self::NOPARENT;
103 
104  # for each segment
105  $CurrentDepth = -1;
106  $CurrentFullName = "";
107  foreach ($Segments as $Segment)
108  {
109  # track segment depth and full classification name for use
110  # in adding new entries
111  $Segment = trim($Segment);
112  $CurrentDepth++;
113  $CurrentFullName .= (($CurrentFullName == "") ? "" : " -- ").$Segment;
114 
115  # if we have added classifications
116  $Segment = addslashes($Segment);
117  if (self::$SegmentsCreated)
118  {
119  # we know that current segment will not be found
120  $ClassId = NULL;
121  }
122  else
123  {
124  # look up classification with current parent and segment name
125  if (!isset($IdCache[$FieldId][$ParentId][$Segment]))
126  {
127  if ($ParentId == self::NOPARENT)
128  {
129  $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
130  "SELECT ClassificationId FROM Classifications"
131  ." WHERE ParentId = ".self::NOPARENT
132  ." AND SegmentName = '".addslashes($Segment)."'"
133  ." AND FieldId = ".intval($FieldId),
134  "ClassificationId");
135  }
136  else
137  {
138  $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
139  "SELECT ClassificationId FROM Classifications "
140  ."WHERE ParentId = ".intval($ParentId)
141  ." AND SegmentName = '".addslashes($Segment)."'",
142  "ClassificationId");
143  }
144  }
145  $ClassId = $IdCache[$FieldId][$ParentId][$Segment];
146  }
147 
148  # if classification not found
149  if ($ClassId === NULL)
150  {
151  # add new classification
152  $InitialValues = array(
153  "FieldId" => $FieldId,
154  "ParentId" => $ParentId,
155  "SegmentName" => $Segment,
156  "ResourceCount" => 0,
157  "Depth" => $CurrentDepth,
158  "ClassificationName" => $CurrentFullName);
159  $NewItem = parent::CreateWithValues($InitialValues);
160  $ClassId = $NewItem->Id();
161  $IdCache[$FieldId][$ParentId][$Segment] = $ClassId;
162 
163  # track total number of new classification segments created
164  self::$SegmentsCreated++;
165  }
166 
167  # set parent to created or found class
168  $ParentId = $ClassId;
169  }
170  }
171 
172  # return new classification to caller
173  return new self($NewItem->Id());
174  }
175 
180  public function Id()
181  {
182  return $this->Id;
183  }
184 
189  public function FullName()
190  {
191  return $this->ValueCache["ClassificationName"];
192  }
193 
198  public function Name()
199  {
200  return $this->FullName();
201  }
202 
207  public function VariantName()
208  {
209  return NULL;
210  }
211 
216  public function Depth()
217  {
218  return $this->ValueCache["Depth"];
219  }
220 
226  public function ResourceCount()
227  {
228  return $this->ValueCache["ResourceCount"];
229  }
230 
237  public function FullResourceCount()
238  {
239  return $this->ValueCache["FullResourceCount"];
240  }
241 
246  public static function SegmentsCreated()
247  {
248  return self::$SegmentsCreated;
249  }
250 
255  public function ParentId()
256  {
257  return $this->ValueCache["ParentId"];
258  }
259 
265  public function SegmentName($NewValue = DB_NOVALUE)
266  {
267  return $this->UpdateValue("SegmentName", $NewValue);
268  }
269 
277  public function LinkString($NewValue = DB_NOVALUE)
278  {
279  return $this->UpdateValue("LinkString", $NewValue);
280  }
281 
288  public function QualifierId($NewValue = DB_NOVALUE)
289  {
290  return $this->UpdateValue("QualifierId", $NewValue);
291  }
292 
298  public function FieldId($NewValue = DB_NOVALUE)
299  {
300  return $this->UpdateValue("FieldId", $NewValue);
301  }
302 
309  public function Qualifier($NewValue = DB_NOVALUE)
310  {
311  # if new qualifier supplied
312  if ($NewValue !== DB_NOVALUE)
313  {
314  # set new qualifier ID
315  $this->QualifierId($NewValue->Id());
316 
317  # use new qualifier for return value
318  $Qualifier = $NewValue;
319  }
320  else
321  {
322  # if qualifier is available
323  if ($this->QualifierId() !== NULL)
324  {
325  # create qualifier object using stored ID
326  $Qualifier = new Qualifier($this->QualifierId());
327  }
328  else
329  {
330  # return NULL to indicate no qualifier
331  $Qualifier = NULL;
332  }
333  }
334 
335  # return qualifier to caller
336  return $Qualifier;
337  }
338 
344  public function RecalcDepthAndFullName()
345  {
346  # start with full classification name set to our segment name
347  $FullClassName = $this->ValueCache["SegmentName"];
348 
349  # assume to begin with that we're at the top of the hierarchy
350  $Depth = 0;
351 
352  # while parent available
353  $ParentId = $this->ValueCache["ParentId"];
354  while ($ParentId != self::NOPARENT)
355  {
356  # retrieve classification information
357  $this->DB->Query("SELECT SegmentName, ParentId "
358  ."FROM Classifications "
359  ."WHERE ClassificationId=".$ParentId);
360  $Record = $this->DB->FetchRow();
361 
362  # prepend segment name to full classification name
363  $FullClassName = $Record["SegmentName"]." -- ".$FullClassName;
364 
365  # increment depth value
366  $Depth++;
367 
368  # move to parent of current classification
369  $ParentId = $Record["ParentId"];
370  }
371 
372  # for each child
373  $this->DB->Query("SELECT ClassificationId FROM Classifications"
374  ." WHERE ParentId = ".intval($this->Id));
375  while ($Record = $this->DB->FetchRow())
376  {
377  # perform depth and name recalc
378  $Child = new Classification($Record["ClassificationId"]);
379  $Child->RecalcDepthAndFullName();
380  }
381 
382  # save new depth and full classification name
383  $this->UpdateValue("Depth", $Depth);
384  $this->UpdateValue("ClassificationName", $FullClassName);
385  }
386 
390  public function UpdateLastAssigned()
391  {
392  $this->DB->Query("UPDATE Classifications SET LastAssigned=NOW() "
393  ."WHERE ClassificationId=".intval($this->Id));
394  }
395 
403  public function RecalcResourceCount($IdsToSkip = NULL)
404  {
405  $IdsUpdated = array();
406 
407  # if we don't have a skip list or we aren't in the skip list
408  if (!$IdsToSkip || !in_array($this->Id, $IdsToSkip))
409  {
410  # retrieve new count of resources directly associated with class
411  $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
412  ." FROM ResourceClassInts, Resources"
413  ." WHERE ClassificationId=".intval($this->Id)
414  ." AND ResourceClassInts.ResourceId = Resources.ResourceId"
415  ." AND Resources.ResourceId > 0"
416  ." AND ReleaseFlag = 1");
417  $Record = $this->DB->FetchRow();
418  $ResourceCount = $Record["ResourceCount"];
419 
420  # add on resources associated with all children
421  $ResourceCount += $this->DB->Query(
422  "SELECT SUM(ResourceCount) AS ResourceCountTotal "
423  ."FROM Classifications "
424  ."WHERE ParentId = ".intval($this->Id),
425  "ResourceCountTotal");
426 
427  # save new count
428  $this->UpdateValue("ResourceCount", $ResourceCount);
429 
430  # add our ID to list of IDs that have been recalculated
431  $IdsUpdated[] = $this->Id;
432  }
433 
434  # update resource count for our parent (if any)
435  if (($this->ValueCache["ParentId"] != self::NOPARENT)
436  && (!$IdsToSkip || !in_array($this->ValueCache["ParentId"], $IdsToSkip)) )
437  {
438  $Class = new Classification($this->ValueCache["ParentId"]);
439  $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
440  }
441 
442  # retrieve new count of all resources directly associated with class
443  $FullCount = $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
444  ." FROM ResourceClassInts I, Resources R"
445  ." WHERE I.ClassificationId = ".intval($this->Id)
446  ." AND R.ResourceId > 0"
447  ." AND I.ResourceId = R.ResourceId",
448  "ResourceCount");
449 
450  # add on resources associated with all children
451  $FullCount += $this->DB->Query(
452  "SELECT SUM(ResourceCount) AS ResourceCountTotal"
453  ." FROM Classifications"
454  ." WHERE ParentId = ".intval($this->Id),
455  "ResourceCountTotal");
456 
457  # save new full count
458  $this->UpdateValue("FullResourceCount", $ResourceCount);
459 
460  # return list of IDs of updated classifications to caller
461  return $IdsUpdated;
462  }
463 
468  public function ChildCount()
469  {
470  # return count of classifications that have this one as parent
471  return $this->DB->Query("SELECT COUNT(*) AS ClassCount "
472  ."FROM Classifications "
473  ."WHERE ParentId=".intval($this->Id),
474  "ClassCount");
475  }
476 
482  public function ChildList()
483  {
484  $ChildList = array();
485 
486  $this->DB->Query("SELECT ClassificationId "
487  ."FROM Classifications "
488  ."WHERE ParentId=".intval($this->Id));
489 
490  while ($Entry = $this->DB->FetchRow())
491  {
492  $ChildList[] = $Entry["ClassificationId"];
493  $Child = new Classification($Entry["ClassificationId"]);
494  if($Child->ChildCount() > 0)
495  {
496  $GrandChildList = $Child->ChildList();
497  $ChildList = array_merge($GrandChildList, $ChildList);
498  }
499  }
500  return array_unique($ChildList);
501  }
502 
516  public function Delete($DeleteParents = FALSE,
517  $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
518  {
519  # if no resources or okay to delete with resources
520  # and no children or okay to delete with children
521  $DeleteCount = 0;
522  if (($DeleteIfHasResources || ($this->ResourceCount() == 0))
523  && ($DeleteIfHasChildren || ($this->ChildCount() == 0)))
524  {
525  if ($this->ResourceCount() != 0)
526  {
527  $this->DB->Query("DELETE FROM ResourceClassInts"
528  ." WHERE ClassificationId = ".intval($this->Id));
529  $this->RecalcResourceCount();
530  }
531 
532  # delete this classification
533  parent::Delete();
534  $DeleteCount++;
535 
536  # delete parent classification (if requested)
537  $ParentId = $this->ValueCache["ParentId"];
538  if (($DeleteParents) && ($ParentId != self::NOPARENT))
539  {
540  $Parent = new Classification($ParentId);
541  $DeleteCount += $Parent->Delete(
542  TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
543  }
544  }
545 
546  # return total number of classifications deleted to caller
547  return $DeleteCount;
548  }
549 
550 
551  # ---- PRIVATE INTERFACE -------------------------------------------------
552 
553  static private $SegmentsCreated;
554 }
LinkString($NewValue=DB_NOVALUE)
Get or set the stored link string for the Classification.
static SegmentsCreated()
Get number of new segments (Classifications) generated when creating a new Classification with a full...
FullName()
Get full classification name (all segments).
FullResourceCount()
Get number of all resources (minus temporary ones) having this classification assigned to them...
UpdateValue($ColumnName, $NewValue=DB_NOVALUE)
Convenience function to supply parameters to Database->UpdateValue().
Definition: Item.php:189
SQL database abstraction object with smart query caching.
Definition: Database.php:22
static Create($Name, $FieldId, $ParentId=NULL)
Add new classification to the hierarchy.
FieldId($NewValue=DB_NOVALUE)
Get or set the ID of the MetadataField for the Classification.
VariantName()
Get variant name of classification, if any.
$DB
Definition: Item.php:115
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.
RecalcResourceCount($IdsToSkip=NULL)
Recalculate number of resources assigned to class and any parent classes.
const NOPARENT
Parent value for classifications with no parent.
Name()
Get name of classification segment.
ParentId()
Get ID of parent Classification.
RecalcDepthAndFullName()
Rebuild classification full name and recalculate depth in hierarchy.
Common base class for persistent items store in database.
Definition: Item.php:13
const DB_NOVALUE
Definition: Database.php:1541
Depth()
Get depth of classification in hierarchy.
ResourceCount()
Get number of released resources having this classification assigned to them.
$Id
Definition: Item.php:116
Delete($DeleteParents=FALSE, $DeleteIfHasResources=FALSE, $DeleteIfHasChildren=FALSE)
Remove Classification (and accompanying associations) from database.
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.