CWIS Developer Documentation
Classification.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # FILE: Classification.php
5 # AUTHOR: Edward Almasy
6 #
7 # Part of the Scout Portal Toolkit
8 # Copyright 2002-2003 Internet Scout Project
9 # http://scout.wisc.edu
10 #
11 
16 
17  # ---- PUBLIC INTERFACE --------------------------------------------------
18 
19  # error status codes
20  const CLASSSTAT_OK = 0;
24 
36  function Classification($ClassId, $Name = NULL, $FieldId = NULL, $ParentId = NULL)
37  {
38  static $IdCache;
39 
40  # assume everything will turn out okay
41  $this->ErrorStatus = Classification::CLASSSTAT_OK;
42 
43  # create DB handle for our use
44  $this->DB = new Database();
45  $DB = $this->DB;
46 
47  # if class ID not given (indicating class must be created)
48  if ($ClassId === NULL)
49  {
50  # if parent class supplied
51  if ($ParentId !== NULL)
52  {
53  # if parent ID was invalid
54  if (($ParentId != -1)
55  && ($DB->Query("SELECT COUNT(*) AS NumberFound"
56  ." FROM Classifications"
57  ." WHERE ClassificationId = ".intval($ParentId),
58  "NumberFound") < 1))
59  {
60  # set error code for bad parent ID
61  $this->ErrorStatus = Classification::CLASSSTAT_INVALIDPARENTID;
62  }
63  else
64  {
65  # if name already exists
66  $Name = trim($Name);
67  if ($FieldId === NULL)
68  {
69  # If we know what field we're trying to add a classifcation for,
70  # Check just within that field
71  $Count = $DB->Query("SELECT COUNT(*) AS NumberFound FROM Classifications"
72  ." WHERE ParentId = ".intval($ParentId)
73  ." AND LOWER(SegmentName) = '"
74  .addslashes(strtolower($Name))."'",
75  "NumberFound");
76  }
77  else
78  {
79  # Otherwise, check all classifications for all fields
80  $Count = $DB->Query("SELECT COUNT(*) AS NumberFound FROM Classifications"
81  ." WHERE ParentId = ".intval($ParentId)
82  ." AND FieldId = ".intval($FieldId)
83  ." AND LOWER(SegmentName) = '"
84  .addslashes(strtolower($Name))."'",
85  "NumberFound");
86  }
87 
88  if ($Count > 0)
89  {
90  # set error code for duplicate class name
91  $this->ErrorStatus = Classification::CLASSSTAT_DUPLICATENAME;
92  }
93  else
94  {
95  # add class to database
96  $ParentId = intval($ParentId);
97  if ($ParentId == -1)
98  {
99  $NewName = $Name;
100  $NewDepth = 0;
101  }
102  else
103  {
104  $DB->Query("SELECT ClassificationName, Depth"
105  ." FROM Classifications"
106  ." WHERE ClassificationId = ".$ParentId);
107  $ParentInfo = $DB->FetchRow();
108  $NewName = $ParentInfo["ClassificationName"]." -- ".$Name;
109  $NewDepth = $ParentInfo["Depth"] + 1;
110  }
111  $DB->Query("INSERT INTO Classifications"
112  ." (FieldId, ParentId, SegmentName, ResourceCount,"
113  ." Depth, ClassificationName) VALUES"
114  ." (".intval($FieldId).", ".$ParentId.","
115  ." '".addslashes($Name)."', 0, "
116  .$NewDepth.", '".addslashes($NewName)."')");
117 
118  # retrieve ID of new class
119  $this->Id = $DB->LastInsertId("Classifications");
120  }
121  }
122  }
123  else
124  {
125  # parse classification name into separate segments
126  $Segments = preg_split("/--/", $Name);
127 
128  # start out with top as parent
129  $ParentId = -1;
130 
131  # for each segment
132  $CurrentDepth = -1;
133  $CurrentFullName = "";
134  foreach ($Segments as $Segment)
135  {
136  # track segment depth and full classification name for use in adding new entries
137  $Segment = trim($Segment);
138  $CurrentDepth++;
139  $CurrentFullName .= (($CurrentFullName == "") ? "" : " -- ").$Segment;
140 
141  # if we have added classifications
142  $Segment = addslashes($Segment);
143  if ($this->SegmentsCreated)
144  {
145  # we know that current segment will not be found
146  $ClassId = NULL;
147  }
148  else
149  {
150  # look up classification with current parent and segment name
151  if (!isset($IdCache[$FieldId][$ParentId][$Segment]))
152  {
153  if ($ParentId == -1)
154  {
155  $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
156  "SELECT ClassificationId FROM Classifications"
157  ." WHERE ParentId = -1"
158  ." AND SegmentName = '".addslashes($Segment)."'"
159  ." AND FieldId = ".intval($FieldId),
160  "ClassificationId");
161  }
162  else
163  {
164  $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
165  "SELECT ClassificationId FROM Classifications "
166  ."WHERE ParentId = ".intval($ParentId)
167  ." AND SegmentName = '".addslashes($Segment)."'",
168  "ClassificationId");
169  }
170  }
171  $ClassId = $IdCache[$FieldId][$ParentId][$Segment];
172  }
173 
174  # if classification not found
175  if ($ClassId === NULL)
176  {
177  # add new classification
178  $DB->Query("INSERT INTO Classifications "
179  ."(FieldId, ParentId, SegmentName,"
180  ." ClassificationName, Depth, ResourceCount) "
181  ."VALUES (".intval($FieldId).", "
182  .intval($ParentId).", "
183  ."'".addslashes($Segment)."', "
184  ."'".addslashes($CurrentFullName)."', "
185  .intval($CurrentDepth).", 0)");
186  $ClassId = $DB->LastInsertId("Classifications");
187  $IdCache[$FieldId][$ParentId][$Segment] = $ClassId;
188 
189  # track total number of new classification segments created
190  $this->SegmentsCreated++;
191  }
192 
193  # set parent to created or found class
194  $PreviousParentId = $ParentId;
195  $ParentId = $ClassId;
196  }
197 
198  # our class ID is the one that was last found
199  $this->Id = $ClassId;
200  }
201  }
202  else
203  {
204  # our class ID is the one that was supplied by caller
205  $this->Id = intval($ClassId);
206  }
207 
208  # if no error encountered
209  if ($this->ErrorStatus == Classification::CLASSSTAT_OK)
210  {
211  # load in attributes from database
212  $DB->Query("SELECT * FROM Classifications"
213  ." WHERE ClassificationId = ".intval($this->Id));
214  $this->DBFields = $DB->NumRowsSelected()>0 ? $DB->FetchRow() : NULL ;
215 
216  # set error status if class info not loaded
217  if ($this->DBFields === NULL ||
218  $this->DBFields["ClassificationId"] != $this->Id)
219  {
220  $this->ErrorStatus = Classification::CLASSSTAT_INVALIDID;
221  }
222  }
223  }
224 
229  function Status() { return $this->ErrorStatus; }
230 
235  function Id() { return $this->Id; }
236 
241  function FullName() { return stripslashes($this->DBFields["ClassificationName"]); }
242 
247  function Name() { return $this->FullName(); }
248 
253  function VariantName() { return NULL; }
254 
259  function Depth() { return $this->DBFields["Depth"]; }
260 
266  function ResourceCount() { return $this->DBFields["ResourceCount"]; }
267 
272  function SegmentsCreated() { return $this->SegmentsCreated; }
273 
278  function ParentId() { return $this->DBFields["ParentId"]; }
279 
285  function SegmentName($NewValue = DB_NOVALUE) {
286  return stripslashes($this->UpdateValue("SegmentName", $NewValue)); }
287 
295  function LinkString($NewValue = DB_NOVALUE) {
296  return stripslashes($this->UpdateValue("LinkString", $NewValue)); }
297 
304  function QualifierId($NewValue = DB_NOVALUE) {
305  return $this->UpdateValue("QualifierId", $NewValue); }
306 
312  function FieldId($NewValue = DB_NOVALUE) {
313  return $this->UpdateValue("FieldId", $NewValue); }
314 
321  function Qualifier($NewValue = DB_NOVALUE)
322  {
323  # if new qualifier supplied
324  if ($NewValue !== DB_NOVALUE)
325  {
326  # set new qualifier ID
327  $this->QualifierId($NewValue->Id());
328 
329  # use new qualifier for return value
330  $Qualifier = $NewValue;
331  }
332  else
333  {
334  # if qualifier is available
335  if ($this->QualifierId() !== NULL)
336  {
337  # create qualifier object using stored ID
338  $Qualifier = new Qualifier($this->QualifierId());
339  }
340  else
341  {
342  # return NULL to indicate no qualifier
343  $Qualifier = NULL;
344  }
345  }
346 
347  # return qualifier to caller
348  return $Qualifier;
349  }
350 
357  {
358  $DB = $this->DB;
359 
360  # start with full classification name set to our segment name
361  $FullClassName = $this->DBFields["SegmentName"];
362 
363  # assume to begin with that we're at the top of the hierarchy
364  $Depth = 0;
365 
366  # while parent available
367  $ParentId = $this->DBFields["ParentId"];
368  while ($ParentId != -1)
369  {
370  # retrieve classification information
371  $DB->Query("SELECT SegmentName, ParentId "
372  ."FROM Classifications "
373  ."WHERE ClassificationId=".$ParentId);
374  $Record = $DB->FetchRow();
375 
376  # prepend segment name to full classification name
377  $FullClassName = stripslashes($Record["SegmentName"])
378  ." -- ".$FullClassName;
379 
380  # increment depth value
381  $Depth++;
382 
383  # move to parent of current classification
384  $ParentId = $Record["ParentId"];
385  }
386 
387  # for each child
388  $DB->Query("SELECT ClassificationId "
389  ."FROM Classifications "
390  ."WHERE ParentId=".intval($this->Id));
391  while ($Record = $DB->FetchRow())
392  {
393  # perform depth and name recalc
394  $Child = new Classification($Record["ClassificationId"]);
395  $Child->RecalcDepthAndFullName();
396  }
397 
398  # save new depth and full classification name
399  $DB->Query("UPDATE Classifications SET "
400  ."Depth=".intval($Depth).", "
401  ."ClassificationName='".addslashes($FullClassName)."' "
402  ."WHERE ClassificationId=".intval($this->Id));
403  $this->DBFields["ClassificationName"] = $FullClassName;
404  $this->DBFields["Depth"] = $Depth;
405  }
406 
414  function RecalcResourceCount($IdsToSkip = NULL)
415  {
416  $IdsUpdated = array();
417 
418  # if we don't have a skip list or we aren't in the skip list
419  if (!$IdsToSkip || !in_array($this->Id, $IdsToSkip))
420  {
421  # retrieve new count of resources directly associated with class
422  $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
423  ." FROM ResourceClassInts, Resources"
424  ." WHERE ClassificationId=".intval($this->Id)
425  ." AND ResourceClassInts.ResourceId = Resources.ResourceId"
426  ." AND ReleaseFlag = 1");
427  $Record = $this->DB->FetchRow();
428  $ResourceCount = $Record["ResourceCount"];
429 
430  # add on resources associated with all children
431  $ResourceCount += $this->DB->Query(
432  "SELECT SUM(ResourceCount) AS ResourceCountTotal "
433  ."FROM Classifications "
434  ."WHERE ParentId = ".intval($this->Id),
435  "ResourceCountTotal");
436 
437  # save new count to database
438  $this->DB->Query("UPDATE Classifications SET "
439  ."ResourceCount=".$ResourceCount." "
440  ."WHERE ClassificationId=".intval($this->Id));
441 
442  # save new count to our local cache
443  $this->DBFields["ResourceCount"] = $ResourceCount;
444 
445  # add our ID to list of IDs that have been recalculated
446  $IdsUpdated[] = $this->Id;
447  }
448 
449  # update resource count for our parent (if any)
450  if (($this->DBFields["ParentId"] != -1)
451  && (!$IdsToSkip || !in_array($this->DBFields["ParentId"], $IdsToSkip)) )
452  {
453  $Class = new Classification($this->DBFields["ParentId"]);
454  if ($Class->Status() == Classification::CLASSSTAT_OK)
455  {
456  $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
457  }
458  }
459 
460  # return list of IDs of updated classifications to caller
461  return $IdsUpdated;
462  }
463 
468  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  # this also returns grandchildren, great grandchildren, etc.
483  function ChildList()
484  {
485  $ChildList = array();
486 
487  $this->DB->Query("SELECT ClassificationId "
488  ."FROM Classifications "
489  ."WHERE ParentId=".intval($this->Id));
490 
491  while ($Entry = $this->DB->FetchRow())
492  {
493  $ChildList[] = $Entry["ClassificationId"];
494  $Child = new Classification($Entry["ClassificationId"]);
495  if($Child->ChildCount() > 0)
496  {
497  $GrandChildList = $Child->ChildList();
498  $ChildList = array_merge($GrandChildList, $ChildList);
499  }
500  }
501  return $ChildList;
502  }
503 
510  function Delete($DeleteParents = FALSE,
511  $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
512  {
513  $DB = $this->DB;
514 
515  # if no resources or okay to delete with resources
516  # and no children or okay to delete with children
517  if (($DeleteIfHasResources || ($this->ResourceCount() == 0))
518  && ($DeleteIfHasChildren || ($this->ChildCount() == 0)))
519  {
520  $ParentId = $this->DBFields["ParentId"];
521 
522  if ($DeleteIfHasResources)
523  {
524  $DB->Query("DELETE FROM ResourceClassInts "
525  ."WHERE ClassificationId=".intval($this->Id));
526  $this->RecalcResourceCount();
527  }
528  # delete this classification
529  $DB->Query("DELETE FROM Classifications "
530  ."WHERE ClassificationId=".intval($this->Id));
531 
532  # delete parent classification (if requested)
533  if (($DeleteParents) && ($this->DBFields["ParentId"] != -1))
534  {
535  $Parent = new Classification($this->DBFields["ParentId"]);
536  $Parent->Delete(
537  TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
538  }
539  }
540  }
541 
542 
543  # ---- PRIVATE INTERFACE -------------------------------------------------
544 
545  private $DB;
546  private $DBFields;
547  private $Id;
548  private $ErrorStatus;
549  private $SegmentsCreated;
550 
551  # convenience function to supply parameters to Database->UpdateValue()
552  private function UpdateValue($FieldName, $NewValue)
553  {
554  return $this->DB->UpdateValue("Classifications", $FieldName, $NewValue,
555  "ClassificationId = ".intval($this->Id),
556  $this->DBFields, TRUE);
557  }
558 }
559 
560 
561 ?>