00001 <?PHP
00002
00003 #
00004 # FILE: ItemFactory.php
00005 #
00006 # NOTES:
00007 # - for a derived class to use the temp methods the item record in the
00008 # database must include "DateLastModified" and "LastModifiedById"
00009 # fields, and the item object must include a "Delete()" method
00010 #
00011 # Copyright 2007-2010 Edward Almasy and Internet Scout
00012 # http://scout.wisc.edu
00013 #
00014
00015 class ItemFactory {
00016
00017 # ---- PUBLIC INTERFACE --------------------------------------------------
00018
00019 # object constructor
00020 function ItemFactory($ItemClassName, $ItemTableName, $ItemIdFieldName,
00021 $ItemNameFieldName = NULL, $FieldId = NULL, $OrderOpsAllowed = FALSE)
00022 {
00023 # save item access names
00024 $this->ItemClassName = $ItemClassName;
00025 $this->ItemTableName = $ItemTableName;
00026 $this->ItemIdFieldName = $ItemIdFieldName;
00027 $this->ItemNameFieldName = $ItemNameFieldName;
00028
00029 # save field ID (if specified)
00030 if ($FieldId !== NULL) { $this->FieldId = intval($FieldId); }
00031
00032 # save flag indicating whether item type allows ordering operations
00033 $this->OrderOpsAllowed = $OrderOpsAllowed;
00034 if ($OrderOpsAllowed)
00035 {
00036 $this->OrderList = new DoublyLinkedItemList(
00037 $ItemTableName, $ItemIdFieldName);
00038 $this->SetOrderOpsCondition(NULL);
00039 }
00040
00041 # grab our own database handle
00042 $this->DB = new Database();
00043
00044 # assume everything will be okay
00045 $this->ErrorStatus = 0;
00046 }
00047
00048 # return current error status
00049 function Status() { return $this->ErrorStatus; }
00050
00051 # get ID of currently edited item
00052 function GetCurrentEditedItemId()
00053 {
00054 # if ID available in session variable
00055 global $Session;
00056 if ($EditedIds = $Session->Get($this->ItemClassName."EditedIds"))
00057 {
00058 # look up value in session variable
00059 $ItemId = $EditedIds[0];
00060 }
00061 else
00062 {
00063 # attempt to look up last temp item ID
00064 $ItemId = $this->GetLastTempItemId();
00065
00066 # store it in session variable
00067 $EditedIds = array($ItemId);
00068 $Session->RegisterVariable($this->ItemClassName."EditedIds", $EditedIds);
00069 }
00070
00071 # return ID (if any) to caller
00072 return $ItemId;
00073 }
00074
00075 # set ID of currently edited item
00076 function SetCurrentEditedItemId($NewId)
00077 {
00078 # if edited ID array already stored for session
00079 global $Session;
00080 if ($EditedIds = $Session->Get($this->ItemClassName."EditedIds"))
00081 {
00082 # prepend new value to array
00083 array_unshift($EditedIds, $NewId);
00084 }
00085 else
00086 {
00087 # start with fresh array
00088 $EditedIds = array($NewId);
00089 }
00090
00091 # save in session variable
00092 $Session->RegisterVariable($this->ItemClassName."EditedIds", $EditedIds);
00093 }
00094
00095 # clear currently edited item ID
00096 function ClearCurrentEditedItemId()
00097 {
00098 # if edited item IDs available in a session variable
00099 global $Session;
00100 $SessionVarName = $this->ItemClassName."EditedIds";
00101 if ($EditedIds = $Session->Get($SessionVarName))
00102 {
00103 # remove current item from edited item ID array
00104 array_shift($EditedIds);
00105
00106 # if no further edited items
00107 if (count($EditedIds) < 1)
00108 {
00109 # destroy session variable
00110 $Session->UnregisterVariable($SessionVarName);
00111 }
00112 else
00113 {
00114 # save new shorter edited item ID array to session variable
00115 $Session->RegisterVariable($SessionVarName, $EditedIds);
00116 }
00117 }
00118 }
00119
00120 # clear currently edited item ID and item
00121 function ClearCurrentEditedItem()
00122 {
00123 # if current edited item is temp item
00124 $CurrentEditedItemId = $this->GetCurrentEditedItemId();
00125 if ($CurrentEditedItemId < 0)
00126 {
00127 # delete temp item from DB
00128 $this->DB->Query("DELETE FROM ".$this->ItemTableName
00129 ." WHERE ".$this->ItemIdFieldName." = ".$CurrentEditedItemId);
00130 }
00131
00132 # clear current edited item ID
00133 $this->ClearCurrentEditedItemId();
00134 }
00135
00143 function CleanOutStaleTempItems($MinutesUntilStale = 10080)
00144 {
00145 # load array of stale items
00146 $MinutesUntilStale = max($MinutesUntilStale, 1);
00147 $this->DB->Query("SELECT ".$this->ItemIdFieldName." FROM ".$this->ItemTableName
00148 ." WHERE ".$this->ItemIdFieldName." < 0"
00149 ." AND DateLastModified < DATE_SUB(NOW(), "
00150 ." INTERVAL ".intval($MinutesUntilStale)." MINUTE)");
00151 $ItemIds = $this->DB->FetchColumn($this->ItemIdFieldName);
00152
00153 # delete stale items
00154 foreach ($ItemIds as $ItemId)
00155 {
00156 $Item = new $this->ItemClassName($ItemId);
00157 $Item->Delete();
00158 }
00159
00160 # report number of items deleted to caller
00161 return count($ItemIds);
00162 }
00163
00164 # retrieve most recent temp item ID based on user ID
00165 # (returns NULL if no temp item found for that user ID)
00166 function GetLastTempItemId()
00167 {
00168 # retrieve ID of most recently modified temp item for this user
00169 global $User;
00170 $ItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName." FROM ".$this->ItemTableName
00171 ." WHERE LastModifiedById = '".$User->Get("UserId")."'"
00172 ." AND ".$this->ItemIdFieldName." < 0"
00173 ." ORDER BY ".$this->ItemIdFieldName." ASC"
00174 ." LIMIT 1",
00175 $this->ItemIdFieldName);
00176
00177 # return item to caller (or NULL if none found)
00178 return $ItemId;
00179 }
00180
00181 # return next item ID
00182 function GetNextItemId()
00183 {
00184 # if no highest item ID found
00185 $HighestItemId = $this->GetHighestItemId();
00186 if ($HighestItemId <= 0)
00187 {
00188 # start with item ID 1
00189 $ItemId = 1;
00190 }
00191 else
00192 {
00193 # else use next ID available after highest
00194 $ItemId = $HighestItemId + 1;
00195 }
00196
00197 # return next ID to caller
00198 return $ItemId;
00199 }
00200
00201 # return highest item ID ($Condition should not include "WHERE")
00202 function GetHighestItemId($Condition = NULL, $IncludeTempItems = FALSE)
00203 {
00204 # if temp items are supposed to be included
00205 if ($IncludeTempItems)
00206 {
00207 # condition is only as supplied
00208 $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
00209 }
00210 else
00211 {
00212 # condition is non-negative IDs plus supplied condition
00213 $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0"
00214 .(($Condition == NULL) ? "" : " AND ".$Condition);
00215 }
00216
00217 # return highest item ID to caller
00218 return $this->DB->Query("SELECT ".$this->ItemIdFieldName
00219 ." FROM ".$this->ItemTableName
00220 .$ConditionString
00221 ." ORDER BY ".$this->ItemIdFieldName
00222 ." DESC LIMIT 1",
00223 $this->ItemIdFieldName);
00224 }
00225
00226 # return next temp item ID
00227 function GetNextTempItemId()
00228 {
00229 $LowestItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName
00230 ." FROM ".$this->ItemTableName
00231 ." ORDER BY ".$this->ItemIdFieldName
00232 ." ASC LIMIT 1",
00233 $this->ItemIdFieldName);
00234 if ($LowestItemId > 0)
00235 {
00236 $ItemId = -1;
00237 }
00238 else
00239 {
00240 $ItemId = $LowestItemId - 1;
00241 }
00242 return $ItemId;
00243 }
00244
00245 # return count of items
00246 function GetItemCount($Condition = NULL, $IncludeTempItems = FALSE)
00247 {
00248 # if condition was supplied
00249 if ($Condition != NULL)
00250 {
00251 # use condition
00252 $ConditionString = " WHERE ".$Condition;
00253 }
00254 else
00255 {
00256 # if field ID is available
00257 if (isset($this->FieldId))
00258 {
00259 # use condition for matching field ID
00260 $ConditionString = " WHERE FieldId = ".intval($this->FieldId);
00261 }
00262 else
00263 {
00264 # use no condition
00265 $ConditionString = "";
00266 }
00267 }
00268
00269 # if temp items are to be excluded
00270 if (!$IncludeTempItems)
00271 {
00272 # if a condition was previously set
00273 if (strlen($ConditionString))
00274 {
00275 # add in condition to exclude temp items
00276 $ConditionString .= " AND (".$this->ItemIdFieldName." >= 0)";
00277 }
00278 else
00279 {
00280 # use condition to exclude temp items
00281 $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0";
00282 }
00283 }
00284
00285 # retrieve item count
00286 $Count = $this->DB->Query("SELECT COUNT(*) AS RecordCount"
00287 ." FROM ".$this->ItemTableName
00288 .$ConditionString,
00289 "RecordCount");
00290
00291 # return count to caller
00292 return $Count;
00293 }
00294
00295 # return array of item IDs ($Condition should not include "WHERE")
00296 function GetItemIds($Condition = NULL, $IncludeTempItems = FALSE)
00297 {
00298 # if temp items are supposed to be included
00299 if ($IncludeTempItems)
00300 {
00301 # condition is only as supplied
00302 $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
00303 }
00304 else
00305 {
00306 # condition is non-negative IDs plus supplied condition
00307 $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0"
00308 .(($Condition == NULL) ? "" : " AND ".$Condition);
00309 }
00310
00311 # get item IDs
00312 $this->DB->Query("SELECT ".$this->ItemIdFieldName
00313 ." FROM ".$this->ItemTableName
00314 .$ConditionString);
00315 $ItemIds = $this->DB->FetchColumn($this->ItemIdFieldName);
00316
00317 # return IDs to caller
00318 return $ItemIds;
00319 }
00320
00321 # return latest modification date ($Condition should not include "WHERE")
00322 function GetLatestModificationDate($Condition = NULL)
00323 {
00324 # return modification date for item most recently changed
00325 $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
00326 return $this->DB->Query("SELECT MAX(DateLastModified) AS LastChangeDate"
00327 ." FROM ".$this->ItemTableName.$ConditionString,
00328 "LastChangeDate");
00329 }
00330
00331 # retrieve item by item ID
00332 function GetItem($ItemId)
00333 {
00334 return new $this->ItemClassName($ItemId);
00335 }
00336
00341 function ItemExists($ItemId)
00342 {
00343 return $this->DB->Query("SELECT COUNT(*) AS ItemCount"
00344 ." FROM ".$this->ItemTableName
00345 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId), "ItemCount")
00346 > 0 ? TRUE : FALSE;
00347 }
00348
00349 # retrieve item by name
00350 function GetItemByName($Name, $IgnoreCase = FALSE)
00351 {
00352 # error out if this is an illegal operation for this item type
00353 if ($this->ItemNameFieldName == NULL)
00354 {
00355 exit("<br>ERROR: attempt to get item by name on item type"
00356 ."(".$this->ItemClassName.") that has no name field specified<br>\n");
00357 }
00358
00359 # query database for item ID
00360 $Comparison = $IgnoreCase
00361 ? "LOWER(".$this->ItemNameFieldName.") = '"
00362 .addslashes(strtolower($Name))."'"
00363 : $this->ItemNameFieldName." = '" .addslashes($Name)."'";
00364 $ItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName
00365 ." FROM ".$this->ItemTableName
00366 ." WHERE ".$Comparison
00367 .(isset($this->FieldId)
00368 ? " AND FieldId = ".$this->FieldId
00369 : ""),
00370 $this->ItemIdFieldName);
00371
00372 # if item ID was not found
00373 if ($ItemId === NULL)
00374 {
00375 # return NULL to caller
00376 $Item = NULL;
00377 }
00378 else
00379 {
00380 # generate new item object
00381 $Item = $this->GetItem($ItemId);
00382 }
00383
00384 # return new object to caller
00385 return $Item;
00386 }
00387
00393 function GetItemNames($SqlCondition = NULL)
00394 {
00395 # error out if this is an illegal operation for this item type
00396 if ($this->ItemNameFieldName == NULL)
00397 {
00398 exit("<br>ERROR: attempt to get array of item names on item type"
00399 ."(".$this->ItemClassName.") that has no name field specified<br>\n");
00400 }
00401
00402 # query database for item names
00403 $Condition = "";
00404 if ($this->FieldId || $SqlCondition)
00405 {
00406 $Condition = "WHERE ";
00407 if ($this->FieldId)
00408 $Condition .= "FieldId = ".intval($this->FieldId);
00409 if ($this->FieldId && $SqlCondition)
00410 $Condition .= " AND ";
00411 if ($SqlCondition)
00412 $Condition .= $SqlCondition;
00413 }
00414 $this->DB->Query("SELECT ".$this->ItemIdFieldName
00415 .", ".$this->ItemNameFieldName
00416 ." FROM ".$this->ItemTableName." "
00417 .$Condition
00418 ." ORDER BY ".$this->ItemNameFieldName);
00419 $Names = $this->DB->FetchColumn(
00420 $this->ItemNameFieldName, $this->ItemIdFieldName);
00421
00422 # return item names to caller
00423 return $Names;
00424 }
00425
00431 function GetItems($SqlCondition = NULL)
00432 {
00433 $Items = array();
00434 $Names = $this->GetItemNames($SqlCondition);
00435 foreach ($Names as $Id => $Name)
00436 {
00437 $Items[$Id] = $this->GetItem($Id);
00438 }
00439 return $Items;
00440 }
00441
00451 function GetItemsAsOptionList(
00452 $OptionListName, $SelectedItemId = NULL, $SqlCondition = NULL)
00453 {
00454 # retrieve requested fields
00455 $ItemNames = $this->GetItemNames($SqlCondition);
00456
00457 # begin HTML option list
00458 $Html = "<select name=\"".htmlspecialchars($OptionListName)."\">\n";
00459 $Html .= "<option value=\"-1\">--</option>\n";
00460
00461 # for each metadata field
00462 foreach ($ItemNames as $Id => $Name)
00463 {
00464 # add entry for field to option list
00465 $Html .= "<option value=\"".$Id."\"";
00466 if ($Id == $SelectedItemId) { $Html .= " selected"; }
00467 $Html .= ">".htmlspecialchars($Name)."</option>\n";
00468 }
00469
00470 # end HTML option list
00471 $Html .= "</select>\n";
00472
00473 # return constructed HTML to caller
00474 return $Html;
00475 }
00482 function NameIsInUse($Name, $IgnoreCase = FALSE)
00483 {
00484 $Condition = $IgnoreCase
00485 ? "LOWER(".$this->ItemNameFieldName.")"
00486 ." = '".addslashes(strtolower($Name))."'"
00487 : $this->ItemNameFieldName." = '".addslashes($Name)."'";
00488 $NameCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM "
00489 .$this->ItemTableName." WHERE ".$Condition, "RecordCount");
00490 return ($NameCount > 0) ? TRUE : FALSE;
00491 }
00492
00493 # retrieve names of items matching search string (array index is IDs)
00494 # (NOTE: IncludeVariants parameter is NOT YET SUPPORTED!)
00495 function SearchForItemNames($SearchString, $NumberOfResults = 100,
00496 $IncludeVariants = FALSE, $UseBooleanMode = TRUE, $Offset=0)
00497 {
00498 # error out if this is an illegal operation for this item type
00499 if ($this->ItemNameFieldName == NULL)
00500 {
00501 exit("<br>ERROR: attempt to search for item names on item type"
00502 ."(".$this->ItemClassName.") that has no name field specified<br>\n");
00503 }
00504
00505 # return no results if empty search string passed in
00506 if (!strlen(trim($SearchString))) { return array(); }
00507
00508 # construct SQL query
00509 $DB = new Database();
00510 $QueryString = "SELECT ".$this->ItemIdFieldName.",".$this->ItemNameFieldName
00511 ." FROM ".$this->ItemTableName." WHERE";
00512 if ($this->FieldId)
00513 {
00514 $QueryString .= " FieldId = ".$this->FieldId." AND";
00515 }
00516 if ($UseBooleanMode)
00517 {
00518 $SearchString = preg_replace("/[)\(><]+/", "", $SearchString);
00519 $Words = preg_split("/[\s]+/", trim($SearchString));
00520 $NewSearchString = "";
00521 $InQuotedString = FALSE;
00522 $SqlVarObj = new MysqlSystemVariables($DB);
00523 $StopWordList = $SqlVarObj->GetStopWords();
00524 $MinWordLen = $SqlVarObj->Get("ft_min_word_len");
00525 foreach ($Words as $Word)
00526 {
00527 # remove any query-specific terms, punctuation, etc.
00528 $JustTheWord = preg_replace("/[^a-zA-Z-]/", "", $Word);
00529
00530 # require (boolean AND) certain words
00531 if ($InQuotedString == FALSE
00532 && !in_array($JustTheWord, $StopWordList)
00533 && strlen($JustTheWord) >= $MinWordLen
00534 && $Word{0} != "+"
00535 && $Word{0} != "-")
00536 {
00537 $NewSearchString .= "+";
00538 }
00539
00540 if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
00541 if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
00542 $NewSearchString .= $Word." ";
00543 }
00544
00545 $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
00546 ." AGAINST ('".addslashes(trim($NewSearchString))."'"
00547 ." IN BOOLEAN MODE)";
00548 }
00549 else
00550 {
00551 $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
00552 ." AGAINST ('".addslashes(trim($SearchString))."')";
00553 }
00554 $QueryString .= " LIMIT ".intval($NumberOfResults)." OFFSET "
00555 .intval($Offset);
00556
00557 # perform query and retrieve names and IDs of items found by query
00558 $DB->Query($QueryString);
00559 $Names = $DB->FetchColumn($this->ItemNameFieldName, $this->ItemIdFieldName);
00560
00561 if ($UseBooleanMode)
00562 {
00563 foreach ($Words as $Word)
00564 {
00565 $TgtWord = preg_replace("/[^a-zA-Z]/", "", $Word);
00566 if ($Word{0} == "-" && strlen($TgtWord) < $MinWordLen)
00567 {
00568 $NewNames = array();
00569 foreach ($Names as $Id => $Name)
00570 {
00571 if (! preg_match('/\b'.$TgtWord.'/i', $Name))
00572 {
00573 $NewNames[$Id] = $Name;
00574 }
00575 }
00576 $Names = $NewNames;
00577 }
00578 }
00579 }
00580
00581 # return names to caller
00582 return $Names;
00583 }
00584
00585 # retrieve the count of names of items matching search string (array index
00586 # is IDs) (NOTE: IncludeVariants parameter is NOT YET SUPPORTED!)
00587 function GetCountForItemNames($SearchString, $IncludeVariants = FALSE,
00588 $UseBooleanMode = TRUE)
00589 {
00590 # return no results if empty search string passed in
00591 if (!strlen(trim($SearchString))) { return 0; }
00592
00593 # construct SQL query
00594 $DB = new Database();
00595 $QueryString = "SELECT COUNT(*) as ItemCount FROM "
00596 .$this->ItemTableName." WHERE";
00597 if ($this->FieldId)
00598 {
00599 $QueryString .= " FieldId = ".$this->FieldId." AND";
00600 }
00601 if ($UseBooleanMode)
00602 {
00603 $SearchString = preg_replace("/[)\(><]+/", "", $SearchString);
00604 $Words = preg_split("/[\s]+/", trim($SearchString));
00605 $NewSearchString = "";
00606 $InQuotedString = FALSE;
00607 $SqlVarObj = new MysqlSystemVariables($DB);
00608 $StopWordList = $SqlVarObj->GetStopWords();
00609 $MinWordLen = $SqlVarObj->Get("ft_min_word_len");
00610 foreach ($Words as $Word)
00611 {
00612 # remove any query-specific terms, punctuation, etc.
00613 $JustTheWord = preg_replace("/[^a-zA-Z-]/", "", $Word);
00614
00615 # require (boolean AND) certain words
00616 if ($InQuotedString == FALSE
00617 && !in_array($JustTheWord, $StopWordList)
00618 && strlen($JustTheWord) >= $MinWordLen
00619 && $Word{0} != "+"
00620 && $Word{0} != "-")
00621 {
00622 $NewSearchString .= "+";
00623 }
00624
00625 if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
00626 if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
00627 $NewSearchString .= $Word." ";
00628 }
00629
00630 $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
00631 ." AGAINST ('".addslashes(trim($NewSearchString))."'"
00632 ." IN BOOLEAN MODE)";
00633 }
00634 else
00635 {
00636 $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
00637 ." AGAINST ('".addslashes(trim($SearchString))."')";
00638 }
00639
00640 # perform query and retrieve names and IDs of items found by query
00641 $DB->Query($QueryString);
00642 return intval($DB->FetchField("ItemCount"));
00643 }
00644
00653 function AddItems($ItemNames, $Qualifier = NULL)
00654 {
00655 # for each supplied item name
00656 $ItemCount = 0;
00657 foreach ($ItemNames as $Name)
00658 {
00659 # if item does not exist with this name
00660 $Name = trim($Name);
00661 if ($this->GetItemByName($Name) === NULL)
00662 {
00663 # add item
00664 $NewItem = new $this->ItemClassName(NULL, $Name, $this->FieldId);
00665 $ItemCount++;
00666
00667 # assign qualifier to item if supplied
00668 if ($Qualifier !== NULL)
00669 {
00670 $NewItem->Qualifier($Qualifier);
00671 }
00672 }
00673 }
00674
00675 # return count of items added to caller
00676 return $ItemCount;
00677 }
00678
00679 # ---- order operations --------------------------------------------------
00680
00681 # set SQL condition (added to WHERE clause) used to select items for ordering ops
00682 # (use NULL to clear any previous condition)
00683 function SetOrderOpsCondition($Condition)
00684 {
00685 # condition is non-negative IDs (non-temp items) plus supplied condition
00686 $NewCondition = $this->ItemIdFieldName." >= 0"
00687 .(($Condition) ? " AND ".$Condition : "");
00688 $this->OrderList->SqlCondition($NewCondition);
00689 }
00690
00691 # insert/move item to before specified item
00692 function InsertBefore($SourceItemOrItemId, $TargetItemOrItemId)
00693 {
00694 # error out if ordering operations are not allowed for this item type
00695 if (!$this->OrderOpsAllowed)
00696 {
00697 exit("<br>ERROR: attempt to perform ordering operation"
00698 ." (InsertBefore()) on item type"
00699 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00700 }
00701
00702 # insert/move item
00703 $this->OrderList->InsertBefore($SourceItemOrItemId, $TargetItemOrItemId);
00704 }
00705
00706 # insert/move item to after specified item
00707 function InsertAfter($SourceItemOrItemId, $TargetItemOrItemId)
00708 {
00709 # error out if ordering operations are not allowed for this item type
00710 if (!$this->OrderOpsAllowed)
00711 {
00712 exit("<br>ERROR: attempt to perform ordering operation"
00713 ." (InsertAfter()) on item type"
00714 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00715 }
00716
00717 # insert/move item
00718 $this->OrderList->InsertAfter($SourceItemOrItemId, $TargetItemOrItemId);
00719 }
00720
00721 # add/move item to beginning of list
00722 function Prepend($ItemOrItemId)
00723 {
00724 # error out if ordering operations are not allowed for this item type
00725 if (!$this->OrderOpsAllowed)
00726 {
00727 exit("<br>ERROR: attempt to perform ordering operation"
00728 ." (Prepend()) on item type"
00729 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00730 }
00731
00732 # prepend item
00733 $this->OrderList->Prepend($ItemOrItemId);
00734 }
00735
00736 # add/move item to end of list
00737 function Append($ItemOrItemId)
00738 {
00739 # error out if ordering operations are not allowed for this item type
00740 if (!$this->OrderOpsAllowed)
00741 {
00742 exit("<br>ERROR: attempt to perform ordering operation"
00743 ." (Append()) on item type"
00744 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00745 }
00746
00747 # add/move item
00748 $this->OrderList->Append($ItemOrItemId);
00749 }
00750
00751 # retrieve list of item IDs in order
00752 function GetItemIdsInOrder($AddStrayItemsToOrder = TRUE)
00753 {
00754 # error out if ordering operations are not allowed for this item type
00755 if (!$this->OrderOpsAllowed)
00756 {
00757 exit("<br>ERROR: attempt to perform ordering operation"
00758 ." (GetItemIdsInOrder()) on item type"
00759 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00760 }
00761
00762 # retrieve list of IDs
00763 return $this->OrderList->GetIds($AddStrayItemsToOrder);
00764 }
00765
00766 # remove item from existing order
00767 function RemoveItemFromOrder($ItemId)
00768 {
00769 # error out if ordering operations are not allowed for this item type
00770 if (!$this->OrderOpsAllowed)
00771 {
00772 exit("<br>ERROR: attempt to perform ordering operation"
00773 ." (RemoveItemFromOrder()) on item type"
00774 ."(".$this->ItemClassName.") that does not support ordering<br>\n");
00775 }
00776
00777 # remove item
00778 $this->OrderList->Remove($ItemId);
00779 }
00780
00781
00782 # ---- PRIVATE INTERFACE -------------------------------------------------
00783
00784 protected $DB;
00785 protected $FieldId;
00786
00787 private $ItemClassName;
00788 private $ItemTableName;
00789 private $ItemIdFieldName;
00790 private $ItemNameFieldName;
00791 private $ErrorStatus;
00792 private $OrderOpsAllowed;
00793 private $OrderList;
00794
00795 # get/set ordering values
00796 private function GetPreviousItemId($ItemId)
00797 {
00798 return $this->DB->Query("SELECT Previous".$this->ItemIdFieldName
00799 ." FROM ".$this->ItemTableName
00800 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId),
00801 "Previous".$this->ItemIdFieldName);
00802 }
00803 private function GetNextItemIdInOrder($ItemId)
00804 {
00805 return $this->DB->Query("SELECT Next".$this->ItemIdFieldName
00806 ." FROM ".$this->ItemTableName
00807 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId),
00808 "Next".$this->ItemIdFieldName);
00809 }
00810 private function SetPreviousItemId($ItemId, $NewValue)
00811 {
00812 $this->DB->Query("UPDATE ".$this->ItemTableName
00813 ." SET Previous".$this->ItemIdFieldName." = ".intval($NewValue)
00814 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
00815 }
00816 private function SetNextItemId($ItemId, $NewValue)
00817 {
00818 $this->DB->Query("UPDATE ".$this->ItemTableName
00819 ." SET Next".$this->ItemIdFieldName." = ".intval($NewValue)
00820 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
00821 }
00822 private function SetPreviousAndNextItemIds($ItemId, $NewPreviousId, $NewNextId)
00823 {
00824 $this->DB->Query("UPDATE ".$this->ItemTableName
00825 ." SET Previous".$this->ItemIdFieldName." = ".intval($NewPreviousId)
00826 .", Next".$this->ItemIdFieldName." = ".intval($NewNextId)
00827 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
00828 }
00829 }
00830
00831 ?>