CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
15 class Classification {
16
17 # ---- PUBLIC INTERFACE --------------------------------------------------
18
19 # error status codes
20 const CLASSSTAT_OK = 0;
21 const CLASSSTAT_INVALIDID = 1;
22 const CLASSSTAT_INVALIDPARENTID = 2;
23 const CLASSSTAT_DUPLICATENAME = 3;
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
356 function RecalcDepthAndFullName()
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 ?>