Search:

# CWIS Developers Documentation

- Main Page
- Classes
- Files

- File List
- File Members

# Classification.php

Go to the documentation of this file.

    00001 <?PHP
    00002
    00003 #
    00004 #   FILE:  Classification.php
    00005 #   AUTHOR:  Edward Almasy
    00006 #
    00007 #   Part of the Scout Portal Toolkit
    00008 #   Copyright 2002-2003 Internet Scout Project
    00009 #   http://scout.wisc.edu
    00010 #
    00011
    00015 class Classification {
    00016
    00017     # ---- PUBLIC INTERFACE --------------------------------------------------
    00018
    00019     # error status codes
    00020     const CLASSSTAT_OK = 0;
    00021     const CLASSSTAT_INVALIDID = 1;
    00022     const CLASSSTAT_INVALIDPARENTID = 2;
    00023     const CLASSSTAT_DUPLICATENAME = 3;
    00024
    00036     function Classification($ClassId, $Name = NULL, $FieldId = NULL, $ParentId = NULL)
    00037     {
    00038         static $IdCache;
    00039
    00040         # assume everything will turn out okay
    00041         $this->ErrorStatus = Classification::CLASSSTAT_OK;
    00042
    00043         # create DB handle for our use
    00044         $this->DB = new SPTDatabase();
    00045         $DB = $this->DB;
    00046
    00047         # if class ID not given (indicating class must be created)
    00048         if ($ClassId === NULL)
    00049         {
    00050             # if parent class supplied
    00051             if ($ParentId !== NULL)
    00052             {
    00053                 # if parent ID was invalid
    00054                 if (($ParentId != -1)
    00055                     && ($DB->Query("SELECT COUNT(*) AS NumberFound"
    00056                                    ." FROM Classifications"
    00057                                    ." WHERE ClassificationId = ".intval($ParentId),
    00058                                    "NumberFound") < 1))
    00059                 {
    00060                     # set error code for bad parent ID
    00061                     $this->ErrorStatus = Classification::CLASSSTAT_INVALIDPARENTID;
    00062                 }
    00063                 else
    00064                 {
    00065                     # if name already exists
    00066                     $Name = trim($Name);
    00067                     if ($FieldId === NULL)
    00068                     {
    00069                         # If we know what field we're trying to add a classifcation for,
    00070                         # Check just within that field
    00071                         $Count = $DB->Query("SELECT COUNT(*) AS NumberFound FROM Classifications"
    00072                                 ." WHERE ParentId = ".intval($ParentId)
    00073                                 ." AND LOWER(SegmentName) = '"
    00074                                         .addslashes(strtolower($Name))."'",
    00075                                             "NumberFound");
    00076                     }
    00077                     else
    00078                     {
    00079                         # Otherwise, check all classifications for all fields
    00080                         $Count = $DB->Query("SELECT COUNT(*) AS NumberFound FROM Classifications"
    00081                                             ." WHERE ParentId = ".intval($ParentId)
    00082                                             ." AND FieldId = ".intval($FieldId)
    00083                                             ." AND LOWER(SegmentName) = '"
    00084                                             .addslashes(strtolower($Name))."'",
    00085                                             "NumberFound");
    00086                     }
    00087
    00088                     if ($Count > 0)
    00089                     {
    00090                         # set error code for duplicate class name
    00091                         $this->ErrorStatus = Classification::CLASSSTAT_DUPLICATENAME;
    00092                     }
    00093                     else
    00094                     {
    00095                         # add class to database
    00096                         $ParentId = intval($ParentId);
    00097                         if ($ParentId == -1)
    00098                         {
    00099                             $NewName = $Name;
    00100                             $NewDepth = 0;
    00101                         }
    00102                         else
    00103                         {
    00104                             $DB->Query("SELECT ClassificationName, Depth"
    00105                                     ." FROM Classifications"
    00106                                     ." WHERE ClassificationId = ".$ParentId);
    00107                             $ParentInfo = $DB->FetchRow();
    00108                             $NewName = $ParentInfo["ClassificationName"]." -- ".$Name;
    00109                             $NewDepth = $ParentInfo["Depth"] + 1;
    00110                         }
    00111                         $DB->Query("INSERT INTO Classifications"
    00112                                 ." (FieldId, ParentId, SegmentName, ResourceCount,"
    00113                                         ." Depth, ClassificationName) VALUES"
    00114                                 ." (".intval($FieldId).", ".$ParentId.","
    00115                                         ." '".addslashes($Name)."', 0, "
    00116                                         .$NewDepth.", '".addslashes($NewName)."')");
    00117
    00118                         # retrieve ID of new class
    00119                         $this->Id = $DB->LastInsertId("Classifications");
    00120                     }
    00121                 }
    00122             }
    00123             else
    00124             {
    00125                 # parse classification name into separate segments
    00126                 $Segments = preg_split("/--/", $Name);
    00127
    00128                 # start out with top as parent
    00129                 $ParentId = -1;
    00130
    00131                 # for each segment
    00132                 $CurrentDepth = -1;
    00133                 $CurrentFullName = "";
    00134                 foreach ($Segments as $Segment)
    00135                 {
    00136                     # track segment depth and full classification name for use in adding new entries
    00137                     $Segment = trim($Segment);
    00138                     $CurrentDepth++;
    00139                     $CurrentFullName .= (($CurrentFullName == "") ? "" : " -- ").$Segment;
    00140
    00141                     # if we have added classifications
    00142                     $Segment = addslashes($Segment);
    00143                     if ($this->SegmentsCreated)
    00144                     {
    00145                         # we know that current segment will not be found
    00146                         $ClassId = NULL;
    00147                     }
    00148                     else
    00149                     {
    00150                         # look up classification with current parent and segment name
    00151                         if (!isset($IdCache[$FieldId][$ParentId][$Segment]))
    00152                         {
    00153                             if ($ParentId == -1)
    00154                             {
    00155                                 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
    00156                                         "SELECT ClassificationId FROM Classifications"
    00157                                         ." WHERE ParentId = -1"
    00158                                         ." AND SegmentName = '".addslashes($Segment)."'"
    00159                                         ." AND FieldId = ".intval($FieldId),
    00160                                         "ClassificationId");
    00161                             }
    00162                             else
    00163                             {
    00164                                 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
    00165                                         "SELECT ClassificationId FROM Classifications "
    00166                                         ."WHERE ParentId = ".intval($ParentId)
    00167                                         ." AND SegmentName = '".addslashes($Segment)."'",
    00168                                         "ClassificationId");
    00169                             }
    00170                         }
    00171                         $ClassId = $IdCache[$FieldId][$ParentId][$Segment];
    00172                     }
    00173
    00174                     # if classification not found
    00175                     if ($ClassId === NULL)
    00176                     {
    00177                         # add new classification
    00178                         $DB->Query("INSERT INTO Classifications "
    00179                                  ."(FieldId, ParentId, SegmentName,"
    00180                                         ." ClassificationName, Depth, ResourceCount) "
    00181                                  ."VALUES (".intval($FieldId).", "
    00182                                     .intval($ParentId).", "
    00183                                     ."'".addslashes($Segment)."', "
    00184                                     ."'".addslashes($CurrentFullName)."', "
    00185                                     .intval($CurrentDepth).", 0)");
    00186                         $ClassId = $DB->LastInsertId("Classifications");
    00187                         $IdCache[$FieldId][$ParentId][$Segment] = $ClassId;
    00188
    00189                         # track total number of new classification segments created
    00190                         $this->SegmentsCreated++;
    00191                     }
    00192
    00193                     # set parent to created or found class
    00194                     $PreviousParentId = $ParentId;
    00195                     $ParentId = $ClassId;
    00196                 }
    00197
    00198                 # our class ID is the one that was last found
    00199                 $this->Id = $ClassId;
    00200             }
    00201         }
    00202         else
    00203         {
    00204             # our class ID is the one that was supplied by caller
    00205             $this->Id = intval($ClassId);
    00206         }
    00207
    00208         # if no error encountered
    00209         if ($this->ErrorStatus == Classification::CLASSSTAT_OK)
    00210         {
    00211             # load in attributes from database
    00212             $DB->Query("SELECT * FROM Classifications"
    00213                        ." WHERE ClassificationId = ".intval($this->Id));
    00214             $this->DBFields = $DB->NumRowsSelected()>0 ? $DB->FetchRow() : NULL ;
    00215
    00216             # set error status if class info not loaded
    00217             if ($this->DBFields === NULL ||
    00218                 $this->DBFields["ClassificationId"] != $this->Id)
    00219             {
    00220                 $this->ErrorStatus = Classification::CLASSSTAT_INVALIDID;
    00221             }
    00222         }
    00223     }
    00224
    00229     function Status() {  return $this->ErrorStatus;  }
    00230
    00235     function Id()            {  return $this->Id;  }
    00236
    00241     function FullName()      {  return stripslashes($this->DBFields["ClassificationName"]);  }
    00242
    00247     function Name()          {  return $this->FullName();  }
    00248
    00253     function VariantName()   {  return NULL;  }
    00254
    00259     function Depth()         {  return $this->DBFields["Depth"];  }
    00260
    00266     function ResourceCount() {  return $this->DBFields["ResourceCount"];  }
    00267
    00272     function SegmentsCreated() { return $this->SegmentsCreated; }
    00273
    00278     function ParentId()      {  return $this->DBFields["ParentId"];  }
    00279
    00285     function SegmentName($NewValue = DB_NOVALUE) {
    00286             return stripslashes($this->UpdateValue("SegmentName", $NewValue));  }
    00287
    00295     function LinkString($NewValue = DB_NOVALUE) {
    00296             return stripslashes($this->UpdateValue("LinkString", $NewValue));  }
    00297
    00304     function QualifierId($NewValue = DB_NOVALUE) {
    00305             return $this->UpdateValue("QualifierId", $NewValue);  }
    00306
    00312     function FieldId($NewValue = DB_NOVALUE) {
    00313             return $this->UpdateValue("FieldId", $NewValue);  }
    00314
    00321     function Qualifier($NewValue = DB_NOVALUE)
    00322     {
    00323         # if new qualifier supplied
    00324         if ($NewValue !== DB_NOVALUE)
    00325         {
    00326             # set new qualifier ID
    00327             $this->QualifierId($NewValue->Id());
    00328
    00329             # use new qualifier for return value
    00330             $Qualifier = $NewValue;
    00331         }
    00332         else
    00333         {
    00334             # if qualifier is available
    00335             if ($this->QualifierId() !== NULL)
    00336             {
    00337                 # create qualifier object using stored ID
    00338                 $Qualifier = new Qualifier($this->QualifierId());
    00339             }
    00340             else
    00341             {
    00342                 # return NULL to indicate no qualifier
    00343                 $Qualifier = NULL;
    00344             }
    00345         }
    00346
    00347         # return qualifier to caller
    00348         return $Qualifier;
    00349     }
    00350
    00356     function RecalcDepthAndFullName()
    00357     {
    00358         $DB = $this->DB;
    00359
    00360         # start with full classification name set to our segment name
    00361         $FullClassName = $this->DBFields["SegmentName"];
    00362
    00363         # assume to begin with that we're at the top of the hierarchy
    00364         $Depth = 0;
    00365
    00366         # while parent available
    00367         $ParentId = $this->DBFields["ParentId"];
    00368         while ($ParentId != -1)
    00369         {
    00370             # retrieve classification information
    00371             $DB->Query("SELECT SegmentName, ParentId "
    00372                     ."FROM Classifications "
    00373                     ."WHERE ClassificationId=".$ParentId);
    00374             $Record = $DB->FetchRow();
    00375
    00376             # prepend segment name to full classification name
    00377             $FullClassName = stripslashes($Record["SegmentName"])
    00378                     ." -- ".$FullClassName;
    00379
    00380             # increment depth value
    00381             $Depth++;
    00382
    00383             # move to parent of current classification
    00384             $ParentId = $Record["ParentId"];
    00385         }
    00386
    00387         # for each child
    00388         $DB->Query("SELECT ClassificationId "
    00389                 ."FROM Classifications "
    00390                 ."WHERE ParentId=".intval($this->Id));
    00391         while ($Record = $DB->FetchRow())
    00392         {
    00393             # perform depth and name recalc
    00394             $Child = new Classification($Record["ClassificationId"]);
    00395             $Child->RecalcDepthAndFullName();
    00396         }
    00397
    00398         # save new depth and full classification name
    00399         $DB->Query("UPDATE Classifications SET "
    00400                 ."Depth=".intval($Depth).", "
    00401                 ."ClassificationName='".addslashes($FullClassName)."' "
    00402                 ."WHERE ClassificationId=".intval($this->Id));
    00403         $this->DBFields["ClassificationName"] = $FullClassName;
    00404         $this->DBFields["Depth"] = $Depth;
    00405     }
    00406
    00414     function RecalcResourceCount($IdsToSkip = NULL)
    00415     {
    00416         $IdsUpdated = array();
    00417
    00418         # if we don't have a skip list or we aren't in the skip list
    00419         if (!$IdsToSkip || !in_array($this->Id, $IdsToSkip))
    00420         {
    00421             # retrieve new count of resources directly associated with class
    00422             $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
    00423                     ." FROM ResourceClassInts, Resources"
    00424                     ." WHERE ClassificationId=".intval($this->Id)
    00425                     ." AND ResourceClassInts.ResourceId = Resources.ResourceId"
    00426                     ." AND ReleaseFlag = 1");
    00427             $Record = $this->DB->FetchRow();
    00428             $ResourceCount = $Record["ResourceCount"];
    00429
    00430             # add on resources associated with all children
    00431             $ResourceCount += $this->DB->Query(
    00432                     "SELECT SUM(ResourceCount) AS ResourceCountTotal "
    00433                         ."FROM Classifications "
    00434                         ."WHERE ParentId = ".intval($this->Id),
    00435                     "ResourceCountTotal");
    00436
    00437             # save new count to database
    00438             $this->DB->Query("UPDATE Classifications SET "
    00439                     ."ResourceCount=".$ResourceCount." "
    00440                     ."WHERE ClassificationId=".intval($this->Id));
    00441
    00442             # save new count to our local cache
    00443             $this->DBFields["ResourceCount"] = $ResourceCount;
    00444
    00445             # add our ID to list of IDs that have been recalculated
    00446             $IdsUpdated[] = $this->Id;
    00447         }
    00448
    00449         # update resource count for our parent (if any)
    00450         if (($this->DBFields["ParentId"] != -1)
    00451             && (!$IdsToSkip || !in_array($this->DBFields["ParentId"], $IdsToSkip)) )
    00452         {
    00453             $Class = new Classification($this->DBFields["ParentId"]);
    00454             if ($Class->Status() == Classification::CLASSSTAT_OK)
    00455             {
    00456                 $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
    00457             }
    00458         }
    00459
    00460         # return list of IDs of updated classifications to caller
    00461         return $IdsUpdated;
    00462     }
    00463
    00468     function ChildCount()
    00469     {
    00470         # return count of classifications that have this one as parent
    00471         return $this->DB->Query("SELECT COUNT(*) AS ClassCount "
    00472                     ."FROM Classifications "
    00473                     ."WHERE ParentId=".intval($this->Id),
    00474                 "ClassCount");
    00475     }
    00476
    00482     # this also returns grandchildren, great grandchildren, etc.
    00483     function ChildList()
    00484     {
    00485         $ChildList = array();
    00486
    00487         $this->DB->Query("SELECT ClassificationId  "
    00488                     ."FROM Classifications "
    00489                     ."WHERE ParentId=".intval($this->Id));
    00490
    00491          while ($Entry = $this->DB->FetchRow())
    00492          {
    00493             $ChildList[] = $Entry["ClassificationId"];
    00494             $Child = new Classification($Entry["ClassificationId"]);
    00495             if($Child->ChildCount() > 0)
    00496             {
    00497                 $GrandChildList = $Child->ChildList();
    00498                 $ChildList = array_merge($GrandChildList, $ChildList);
    00499             }
    00500          }
    00501          return $ChildList;
    00502     }
    00503
    00510     function Delete($DeleteParents = FALSE,
    00511             $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
    00512     {
    00513         $DB = $this->DB;
    00514
    00515         # if no resources or okay to delete with resources
    00516         #         and no children or okay to delete with children
    00517         if (($DeleteIfHasResources || ($this->ResourceCount() == 0))
    00518                 && ($DeleteIfHasChildren || ($this->ChildCount() == 0)))
    00519         {
    00520             $ParentId = $this->DBFields["ParentId"];
    00521
    00522             if ($DeleteIfHasResources)
    00523             {
    00524                 $DB->Query("DELETE FROM ResourceClassInts "
    00525                         ."WHERE ClassificationId=".intval($this->Id));
    00526                 $this->RecalcResourceCount();
    00527             }
    00528             # delete this classification
    00529             $DB->Query("DELETE FROM Classifications "
    00530                     ."WHERE ClassificationId=".intval($this->Id));
    00531
    00532             # delete parent classification (if requested)
    00533             if (($DeleteParents) && ($this->DBFields["ParentId"] != -1))
    00534             {
    00535                 $Parent = new Classification($this->DBFields["ParentId"]);
    00536                 $Parent->Delete(
    00537                         TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
    00538             }
    00539         }
    00540     }
    00541
    00542
    00543     # ---- PRIVATE INTERFACE -------------------------------------------------
    00544
    00545     private $DB;
    00546     private $DBFields;
    00547     private $Id;
    00548     private $ErrorStatus;
    00549     private $SegmentsCreated;
    00550
    00551     # convenience function to supply parameters to Database->UpdateValue()
    00552     private function UpdateValue($FieldName, $NewValue)
    00553     {
    00554         return $this->DB->UpdateValue("Classifications", $FieldName, $NewValue,
    00555                                "ClassificationId = ".intval($this->Id),
    00556                                $this->DBFields, TRUE);
    00557     }
    00558 }
    00559
    00560
    00561 ?>