CWIS Developer Documentation
ItemFactory.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # FILE: ItemFactory.php
5 #
6 # NOTES:
7 # - for a derived class to use the temp methods the item record in the
8 # database must include "DateLastModified" and "LastModifiedById"
9 # fields, and the item object must include a "Delete()" method
10 #
11 # Copyright 2007-2010 Edward Almasy and Internet Scout
12 # http://scout.wisc.edu
13 #
14 
15 class ItemFactory {
16 
17  # ---- PUBLIC INTERFACE --------------------------------------------------
18 
19  # object constructor
20  function ItemFactory($ItemClassName, $ItemTableName, $ItemIdFieldName,
21  $ItemNameFieldName = NULL, $FieldId = NULL, $OrderOpsAllowed = FALSE)
22  {
23  # save item access names
24  $this->ItemClassName = $ItemClassName;
25  $this->ItemTableName = $ItemTableName;
26  $this->ItemIdFieldName = $ItemIdFieldName;
27  $this->ItemNameFieldName = $ItemNameFieldName;
28 
29  # save field ID (if specified)
30  if ($FieldId !== NULL) { $this->FieldId = intval($FieldId); }
31 
32  # save flag indicating whether item type allows ordering operations
33  $this->OrderOpsAllowed = $OrderOpsAllowed;
34  if ($OrderOpsAllowed)
35  {
36  $this->OrderList = new DoublyLinkedItemList(
37  $ItemTableName, $ItemIdFieldName);
38  $this->SetOrderOpsCondition(NULL);
39  }
40 
41  # grab our own database handle
42  $this->DB = new Database();
43 
44  # assume everything will be okay
45  $this->ErrorStatus = 0;
46  }
47 
48  # return current error status
49  function Status() { return $this->ErrorStatus; }
50 
51  # get ID of currently edited item
53  {
54  # if ID available in session variable
55  global $Session;
56  if ($EditedIds = $Session->Get($this->ItemClassName."EditedIds"))
57  {
58  # look up value in session variable
59  $ItemId = $EditedIds[0];
60  }
61  else
62  {
63  # attempt to look up last temp item ID
64  $ItemId = $this->GetLastTempItemId();
65 
66  # store it in session variable
67  $EditedIds = array($ItemId);
68  $Session->RegisterVariable($this->ItemClassName."EditedIds", $EditedIds);
69  }
70 
71  # return ID (if any) to caller
72  return $ItemId;
73  }
74 
75  # set ID of currently edited item
76  function SetCurrentEditedItemId($NewId)
77  {
78  # if edited ID array already stored for session
79  global $Session;
80  if ($EditedIds = $Session->Get($this->ItemClassName."EditedIds"))
81  {
82  # prepend new value to array
83  array_unshift($EditedIds, $NewId);
84  }
85  else
86  {
87  # start with fresh array
88  $EditedIds = array($NewId);
89  }
90 
91  # save in session variable
92  $Session->RegisterVariable($this->ItemClassName."EditedIds", $EditedIds);
93  }
94 
95  # clear currently edited item ID
97  {
98  # if edited item IDs available in a session variable
99  global $Session;
100  $SessionVarName = $this->ItemClassName."EditedIds";
101  if ($EditedIds = $Session->Get($SessionVarName))
102  {
103  # remove current item from edited item ID array
104  array_shift($EditedIds);
105 
106  # if no further edited items
107  if (count($EditedIds) < 1)
108  {
109  # destroy session variable
110  $Session->UnregisterVariable($SessionVarName);
111  }
112  else
113  {
114  # save new shorter edited item ID array to session variable
115  $Session->RegisterVariable($SessionVarName, $EditedIds);
116  }
117  }
118  }
119 
120  # clear currently edited item ID and item
122  {
123  # if current edited item is temp item
124  $CurrentEditedItemId = $this->GetCurrentEditedItemId();
125  if ($CurrentEditedItemId < 0)
126  {
127  # delete temp item from DB
128  $this->DB->Query("DELETE FROM ".$this->ItemTableName
129  ." WHERE ".$this->ItemIdFieldName." = ".$CurrentEditedItemId);
130  }
131 
132  # clear current edited item ID
133  $this->ClearCurrentEditedItemId();
134  }
135 
143  function CleanOutStaleTempItems($MinutesUntilStale = 10080)
144  {
145  # load array of stale items
146  $MinutesUntilStale = max($MinutesUntilStale, 1);
147  $this->DB->Query("SELECT ".$this->ItemIdFieldName." FROM ".$this->ItemTableName
148  ." WHERE ".$this->ItemIdFieldName." < 0"
149  ." AND DateLastModified < DATE_SUB(NOW(), "
150  ." INTERVAL ".intval($MinutesUntilStale)." MINUTE)");
151  $ItemIds = $this->DB->FetchColumn($this->ItemIdFieldName);
152 
153  # delete stale items
154  foreach ($ItemIds as $ItemId)
155  {
156  $Item = new $this->ItemClassName($ItemId);
157  $Item->Delete();
158  }
159 
160  # report number of items deleted to caller
161  return count($ItemIds);
162  }
163 
164  # retrieve most recent temp item ID based on user ID
165  # (returns NULL if no temp item found for that user ID)
166  function GetLastTempItemId()
167  {
168  # retrieve ID of most recently modified temp item for this user
169  global $User;
170  $ItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName." FROM ".$this->ItemTableName
171  ." WHERE LastModifiedById = '".$User->Get("UserId")."'"
172  ." AND ".$this->ItemIdFieldName." < 0"
173  ." ORDER BY ".$this->ItemIdFieldName." ASC"
174  ." LIMIT 1",
175  $this->ItemIdFieldName);
176 
177  # return item to caller (or NULL if none found)
178  return $ItemId;
179  }
180 
181  # return next item ID
182  function GetNextItemId()
183  {
184  # if no highest item ID found
185  $HighestItemId = $this->GetHighestItemId();
186  if ($HighestItemId <= 0)
187  {
188  # start with item ID 1
189  $ItemId = 1;
190  }
191  else
192  {
193  # else use next ID available after highest
194  $ItemId = $HighestItemId + 1;
195  }
196 
197  # return next ID to caller
198  return $ItemId;
199  }
200 
201  # return highest item ID ($Condition should not include "WHERE")
202  function GetHighestItemId($Condition = NULL, $IncludeTempItems = FALSE)
203  {
204  # if temp items are supposed to be included
205  if ($IncludeTempItems)
206  {
207  # condition is only as supplied
208  $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
209  }
210  else
211  {
212  # condition is non-negative IDs plus supplied condition
213  $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0"
214  .(($Condition == NULL) ? "" : " AND ".$Condition);
215  }
216 
217  # return highest item ID to caller
218  return $this->DB->Query("SELECT ".$this->ItemIdFieldName
219  ." FROM ".$this->ItemTableName
220  .$ConditionString
221  ." ORDER BY ".$this->ItemIdFieldName
222  ." DESC LIMIT 1",
223  $this->ItemIdFieldName);
224  }
225 
226  # return next temp item ID
227  function GetNextTempItemId()
228  {
229  $LowestItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName
230  ." FROM ".$this->ItemTableName
231  ." ORDER BY ".$this->ItemIdFieldName
232  ." ASC LIMIT 1",
233  $this->ItemIdFieldName);
234  if ($LowestItemId > 0)
235  {
236  $ItemId = -1;
237  }
238  else
239  {
240  $ItemId = $LowestItemId - 1;
241  }
242  return $ItemId;
243  }
244 
245  # return count of items
246  function GetItemCount($Condition = NULL, $IncludeTempItems = FALSE)
247  {
248  # if condition was supplied
249  if ($Condition != NULL)
250  {
251  # use condition
252  $ConditionString = " WHERE ".$Condition;
253  }
254  else
255  {
256  # if field ID is available
257  if (isset($this->FieldId))
258  {
259  # use condition for matching field ID
260  $ConditionString = " WHERE FieldId = ".intval($this->FieldId);
261  }
262  else
263  {
264  # use no condition
265  $ConditionString = "";
266  }
267  }
268 
269  # if temp items are to be excluded
270  if (!$IncludeTempItems)
271  {
272  # if a condition was previously set
273  if (strlen($ConditionString))
274  {
275  # add in condition to exclude temp items
276  $ConditionString .= " AND (".$this->ItemIdFieldName." >= 0)";
277  }
278  else
279  {
280  # use condition to exclude temp items
281  $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0";
282  }
283  }
284 
285  # retrieve item count
286  $Count = $this->DB->Query("SELECT COUNT(*) AS RecordCount"
287  ." FROM ".$this->ItemTableName
288  .$ConditionString,
289  "RecordCount");
290 
291  # return count to caller
292  return $Count;
293  }
294 
295  # return array of item IDs ($Condition should not include "WHERE")
296  function GetItemIds($Condition = NULL, $IncludeTempItems = FALSE)
297  {
298  # if temp items are supposed to be included
299  if ($IncludeTempItems)
300  {
301  # condition is only as supplied
302  $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
303  }
304  else
305  {
306  # condition is non-negative IDs plus supplied condition
307  $ConditionString = " WHERE ".$this->ItemIdFieldName." >= 0"
308  .(($Condition == NULL) ? "" : " AND ".$Condition);
309  }
310 
311  # get item IDs
312  $this->DB->Query("SELECT ".$this->ItemIdFieldName
313  ." FROM ".$this->ItemTableName
314  .$ConditionString);
315  $ItemIds = $this->DB->FetchColumn($this->ItemIdFieldName);
316 
317  # return IDs to caller
318  return $ItemIds;
319  }
320 
321  # return latest modification date ($Condition should not include "WHERE")
322  function GetLatestModificationDate($Condition = NULL)
323  {
324  # return modification date for item most recently changed
325  $ConditionString = ($Condition == NULL) ? "" : " WHERE ".$Condition;
326  return $this->DB->Query("SELECT MAX(DateLastModified) AS LastChangeDate"
327  ." FROM ".$this->ItemTableName.$ConditionString,
328  "LastChangeDate");
329  }
330 
331  # retrieve item by item ID
332  function GetItem($ItemId)
333  {
334  return new $this->ItemClassName($ItemId);
335  }
336 
341  function ItemExists($ItemId)
342  {
343  return $this->DB->Query("SELECT COUNT(*) AS ItemCount"
344  ." FROM ".$this->ItemTableName
345  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId), "ItemCount")
346  > 0 ? TRUE : FALSE;
347  }
348 
349  # retrieve item by name
350  function GetItemByName($Name, $IgnoreCase = FALSE)
351  {
352  # error out if this is an illegal operation for this item type
353  if ($this->ItemNameFieldName == NULL)
354  {
355  exit("<br>ERROR: attempt to get item by name on item type"
356  ."(".$this->ItemClassName.") that has no name field specified<br>\n");
357  }
358 
359  # query database for item ID
360  $Comparison = $IgnoreCase
361  ? "LOWER(".$this->ItemNameFieldName.") = '"
362  .addslashes(strtolower($Name))."'"
363  : $this->ItemNameFieldName." = '" .addslashes($Name)."'";
364  $ItemId = $this->DB->Query("SELECT ".$this->ItemIdFieldName
365  ." FROM ".$this->ItemTableName
366  ." WHERE ".$Comparison
367  .(isset($this->FieldId)
368  ? " AND FieldId = ".$this->FieldId
369  : ""),
370  $this->ItemIdFieldName);
371 
372  # if item ID was not found
373  if ($ItemId === NULL)
374  {
375  # return NULL to caller
376  $Item = NULL;
377  }
378  else
379  {
380  # generate new item object
381  $Item = $this->GetItem($ItemId);
382  }
383 
384  # return new object to caller
385  return $Item;
386  }
387 
393  function GetItemNames($SqlCondition = NULL)
394  {
395  # error out if this is an illegal operation for this item type
396  if ($this->ItemNameFieldName == NULL)
397  {
398  exit("<br>ERROR: attempt to get array of item names on item type"
399  ."(".$this->ItemClassName.") that has no name field specified<br>\n");
400  }
401 
402  # query database for item names
403  $Condition = "";
404  if ($this->FieldId || $SqlCondition)
405  {
406  $Condition = "WHERE ";
407  if ($this->FieldId)
408  $Condition .= "FieldId = ".intval($this->FieldId);
409  if ($this->FieldId && $SqlCondition)
410  $Condition .= " AND ";
411  if ($SqlCondition)
412  $Condition .= $SqlCondition;
413  }
414  $this->DB->Query("SELECT ".$this->ItemIdFieldName
415  .", ".$this->ItemNameFieldName
416  ." FROM ".$this->ItemTableName." "
417  .$Condition
418  ." ORDER BY ".$this->ItemNameFieldName);
419  $Names = $this->DB->FetchColumn(
420  $this->ItemNameFieldName, $this->ItemIdFieldName);
421 
422  # return item names to caller
423  return $Names;
424  }
425 
431  function GetItems($SqlCondition = NULL)
432  {
433  $Items = array();
434  $Names = $this->GetItemNames($SqlCondition);
435  foreach ($Names as $Id => $Name)
436  {
437  $Items[$Id] = $this->GetItem($Id);
438  }
439  return $Items;
440  }
441 
456  function GetItemsAsOptionList($OptionListName, $SelectedItemId = NULL,
457  $SqlCondition = NULL, $DisplaySize = 1, $SubmitOnChange = FALSE)
458  {
459  # retrieve requested fields
460  $ItemNames = $this->GetItemNames($SqlCondition);
461 
462  # if multiple selections are allowed
463  if ($DisplaySize > 1)
464  {
465  # begin multi-selection HTML option list
466  $Html = "<select name=\"".htmlspecialchars($OptionListName)."[]\""
467  .($SubmitOnChange ? " onChange=\"submit()\"" : "")
468  ." multiple=\"multiple\" size=\"".$DisplaySize."\">\n";
469  }
470  else
471  {
472  # begin single-selection HTML option list
473  $Html = "<select name=\"".htmlspecialchars($OptionListName)."\""
474  .($SubmitOnChange ? " onChange=\"submit()\"" : "")
475  ." size=\"1\">\n";
476  $Html .= "<option value=\"-1\">--</option>\n";
477  }
478 
479  # for each metadata field
480  foreach ($ItemNames as $Id => $Name)
481  {
482  # add entry for field to option list
483  $Html .= "<option value=\"".$Id."\"";
484  if (($Id == $SelectedItemId)
485  || (is_array($SelectedItemId) && in_array($Id, $SelectedItemId)))
486  {
487  $Html .= " selected";
488  }
489  $Html .= ">".htmlspecialchars($Name)."</option>\n";
490  }
491 
492  # end HTML option list
493  $Html .= "</select>\n";
494 
495  # return constructed HTML to caller
496  return $Html;
497  }
504  function NameIsInUse($Name, $IgnoreCase = FALSE)
505  {
506  $Condition = $IgnoreCase
507  ? "LOWER(".$this->ItemNameFieldName.")"
508  ." = '".addslashes(strtolower($Name))."'"
509  : $this->ItemNameFieldName." = '".addslashes($Name)."'";
510  $NameCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM "
511  .$this->ItemTableName." WHERE ".$Condition, "RecordCount");
512  return ($NameCount > 0) ? TRUE : FALSE;
513  }
514 
515  # retrieve names of items matching search string (array index is IDs)
516  # (NOTE: IncludeVariants parameter is NOT YET SUPPORTED!)
517  function SearchForItemNames($SearchString, $NumberOfResults = 100,
518  $IncludeVariants = FALSE, $UseBooleanMode = TRUE, $Offset=0)
519  {
520  # error out if this is an illegal operation for this item type
521  if ($this->ItemNameFieldName == NULL)
522  {
523  exit("<br>ERROR: attempt to search for item names on item type"
524  ."(".$this->ItemClassName.") that has no name field specified<br>\n");
525  }
526 
527  # return no results if empty search string passed in
528  if (!strlen(trim($SearchString))) { return array(); }
529 
530  # construct SQL query
531  $DB = new Database();
532  $QueryString = "SELECT ".$this->ItemIdFieldName.",".$this->ItemNameFieldName
533  ." FROM ".$this->ItemTableName." WHERE";
534  if ($this->FieldId)
535  {
536  $QueryString .= " FieldId = ".$this->FieldId." AND";
537  }
538  if ($UseBooleanMode)
539  {
540  $SearchString = preg_replace("/[)\(><]+/", "", $SearchString);
541  $Words = preg_split("/[\s]+/", trim($SearchString));
542  $NewSearchString = "";
543  $InQuotedString = FALSE;
544  $SqlVarObj = new MysqlSystemVariables($DB);
545  $StopWordList = $SqlVarObj->GetStopWords();
546  $MinWordLen = $SqlVarObj->Get("ft_min_word_len");
547  foreach ($Words as $Word)
548  {
549  # remove any query-specific terms, punctuation, etc.
550  $JustTheWord = preg_replace("/[^a-zA-Z-]/", "", $Word);
551 
552  # require (boolean AND) certain words
553  if ($InQuotedString == FALSE
554  && !in_array($JustTheWord, $StopWordList)
555  && strlen($JustTheWord) >= $MinWordLen
556  && $Word{0} != "+"
557  && $Word{0} != "-")
558  {
559  $NewSearchString .= "+";
560  }
561 
562  if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
563  if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
564  $NewSearchString .= $Word." ";
565  }
566 
567  $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
568  ." AGAINST ('".addslashes(trim($NewSearchString))."'"
569  ." IN BOOLEAN MODE)";
570  }
571  else
572  {
573  $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
574  ." AGAINST ('".addslashes(trim($SearchString))."')";
575  }
576  $QueryString .= " LIMIT ".intval($NumberOfResults)." OFFSET "
577  .intval($Offset);
578 
579  # perform query and retrieve names and IDs of items found by query
580  $DB->Query($QueryString);
581  $Names = $DB->FetchColumn($this->ItemNameFieldName, $this->ItemIdFieldName);
582 
583  if ($UseBooleanMode)
584  {
585  foreach ($Words as $Word)
586  {
587  $TgtWord = preg_replace("/[^a-zA-Z]/", "", $Word);
588  if ($Word{0} == "-" && strlen($TgtWord) < $MinWordLen)
589  {
590  $NewNames = array();
591  foreach ($Names as $Id => $Name)
592  {
593  if (! preg_match('/\b'.$TgtWord.'/i', $Name))
594  {
595  $NewNames[$Id] = $Name;
596  }
597  }
598  $Names = $NewNames;
599  }
600  }
601  }
602 
603  # return names to caller
604  return $Names;
605  }
606 
607  # retrieve the count of names of items matching search string (array index
608  # is IDs) (NOTE: IncludeVariants parameter is NOT YET SUPPORTED!)
609  function GetCountForItemNames($SearchString, $IncludeVariants = FALSE,
610  $UseBooleanMode = TRUE)
611  {
612  # return no results if empty search string passed in
613  if (!strlen(trim($SearchString))) { return 0; }
614 
615  # construct SQL query
616  $DB = new Database();
617  $QueryString = "SELECT COUNT(*) as ItemCount FROM "
618  .$this->ItemTableName." WHERE";
619  if ($this->FieldId)
620  {
621  $QueryString .= " FieldId = ".$this->FieldId." AND";
622  }
623  if ($UseBooleanMode)
624  {
625  $SearchString = preg_replace("/[)\(><]+/", "", $SearchString);
626  $Words = preg_split("/[\s]+/", trim($SearchString));
627  $NewSearchString = "";
628  $InQuotedString = FALSE;
629  $SqlVarObj = new MysqlSystemVariables($DB);
630  $StopWordList = $SqlVarObj->GetStopWords();
631  $MinWordLen = $SqlVarObj->Get("ft_min_word_len");
632  foreach ($Words as $Word)
633  {
634  # remove any query-specific terms, punctuation, etc.
635  $JustTheWord = preg_replace("/[^a-zA-Z-]/", "", $Word);
636 
637  # require (boolean AND) certain words
638  if ($InQuotedString == FALSE
639  && !in_array($JustTheWord, $StopWordList)
640  && strlen($JustTheWord) >= $MinWordLen
641  && $Word{0} != "+"
642  && $Word{0} != "-")
643  {
644  $NewSearchString .= "+";
645  }
646 
647  if (preg_match("/^\"/", $Word)) { $InQuotedString = TRUE; }
648  if (preg_match("/\"$/", $Word)) { $InQuotedString = FALSE; }
649  $NewSearchString .= $Word." ";
650  }
651 
652  $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
653  ." AGAINST ('".addslashes(trim($NewSearchString))."'"
654  ." IN BOOLEAN MODE)";
655  }
656  else
657  {
658  $QueryString .= " MATCH (".$this->ItemNameFieldName.")"
659  ." AGAINST ('".addslashes(trim($SearchString))."')";
660  }
661 
662  # perform query and retrieve names and IDs of items found by query
663  $DB->Query($QueryString);
664  return intval($DB->FetchField("ItemCount"));
665  }
666 
675  function AddItems($ItemNames, $Qualifier = NULL)
676  {
677  # for each supplied item name
678  $ItemCount = 0;
679  foreach ($ItemNames as $Name)
680  {
681  # if item does not exist with this name
682  $Name = trim($Name);
683  if ($this->GetItemByName($Name) === NULL)
684  {
685  # add item
686  $NewItem = new $this->ItemClassName(NULL, $Name, $this->FieldId);
687  $ItemCount++;
688 
689  # assign qualifier to item if supplied
690  if ($Qualifier !== NULL)
691  {
692  $NewItem->Qualifier($Qualifier);
693  }
694  }
695  }
696 
697  # return count of items added to caller
698  return $ItemCount;
699  }
700 
709  function AddItem($ItemName, $AdditionalValues = NULL)
710  {
711  # build initial database query for adding item
712  $Query = "INSERT INTO ".$this->ItemTableName." SET `"
713  .$this->ItemNameFieldName."` = '".addslashes($ItemName)."'";
714 
715  # add any additional values to query
716  if ($AdditionalValues)
717  {
718  foreach ($AdditionalValues as $FieldName => $Value)
719  {
720  $Query .= ", `".$FieldName."` = '".addslashes($Value)."'";
721  }
722  }
723 
724  # add item to database
725  $this->DB->Query($Query);
726 
727  # retrieve ID of new item
728  $Id = $this->DB->LastInsertId($this->ItemTableName);
729 
730  # return ID to caller
731  return $Id;
732  }
733 
738  function DeleteItem($ItemId)
739  {
740  # delete item from database
741  $this->DB->Query("DELETE FROM ".$this->ItemTableName
742  ." WHERE ".$this->ItemIdFieldName." = '".addslashes($ItemId)."'");
743  }
744 
745 
746  # ---- order operations --------------------------------------------------
747 
748  # set SQL condition (added to WHERE clause) used to select items for ordering ops
749  # (use NULL to clear any previous condition)
750  function SetOrderOpsCondition($Condition)
751  {
752  # condition is non-negative IDs (non-temp items) plus supplied condition
753  $NewCondition = $this->ItemIdFieldName." >= 0"
754  .(($Condition) ? " AND ".$Condition : "");
755  $this->OrderList->SqlCondition($NewCondition);
756  }
757 
758  # insert/move item to before specified item
759  function InsertBefore($SourceItemOrItemId, $TargetItemOrItemId)
760  {
761  # error out if ordering operations are not allowed for this item type
762  if (!$this->OrderOpsAllowed)
763  {
764  exit("<br>ERROR: attempt to perform ordering operation"
765  ." (InsertBefore()) on item type"
766  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
767  }
768 
769  # insert/move item
770  $this->OrderList->InsertBefore($SourceItemOrItemId, $TargetItemOrItemId);
771  }
772 
773  # insert/move item to after specified item
774  function InsertAfter($SourceItemOrItemId, $TargetItemOrItemId)
775  {
776  # error out if ordering operations are not allowed for this item type
777  if (!$this->OrderOpsAllowed)
778  {
779  exit("<br>ERROR: attempt to perform ordering operation"
780  ." (InsertAfter()) on item type"
781  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
782  }
783 
784  # insert/move item
785  $this->OrderList->InsertAfter($SourceItemOrItemId, $TargetItemOrItemId);
786  }
787 
788  # add/move item to beginning of list
789  function Prepend($ItemOrItemId)
790  {
791  # error out if ordering operations are not allowed for this item type
792  if (!$this->OrderOpsAllowed)
793  {
794  exit("<br>ERROR: attempt to perform ordering operation"
795  ." (Prepend()) on item type"
796  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
797  }
798 
799  # prepend item
800  $this->OrderList->Prepend($ItemOrItemId);
801  }
802 
803  # add/move item to end of list
804  function Append($ItemOrItemId)
805  {
806  # error out if ordering operations are not allowed for this item type
807  if (!$this->OrderOpsAllowed)
808  {
809  exit("<br>ERROR: attempt to perform ordering operation"
810  ." (Append()) on item type"
811  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
812  }
813 
814  # add/move item
815  $this->OrderList->Append($ItemOrItemId);
816  }
817 
818  # retrieve list of item IDs in order
819  function GetItemIdsInOrder($AddStrayItemsToOrder = TRUE)
820  {
821  # error out if ordering operations are not allowed for this item type
822  if (!$this->OrderOpsAllowed)
823  {
824  exit("<br>ERROR: attempt to perform ordering operation"
825  ." (GetItemIdsInOrder()) on item type"
826  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
827  }
828 
829  # retrieve list of IDs
830  return $this->OrderList->GetIds($AddStrayItemsToOrder);
831  }
832 
833  # remove item from existing order
834  function RemoveItemFromOrder($ItemId)
835  {
836  # error out if ordering operations are not allowed for this item type
837  if (!$this->OrderOpsAllowed)
838  {
839  exit("<br>ERROR: attempt to perform ordering operation"
840  ." (RemoveItemFromOrder()) on item type"
841  ."(".$this->ItemClassName.") that does not support ordering<br>\n");
842  }
843 
844  # remove item
845  $this->OrderList->Remove($ItemId);
846  }
847 
848 
849  # ---- PRIVATE INTERFACE -------------------------------------------------
850 
851  protected $DB;
852  protected $FieldId;
853 
854  private $ItemClassName;
855  private $ItemTableName;
856  private $ItemIdFieldName;
857  private $ItemNameFieldName;
858  private $ErrorStatus;
859  private $OrderOpsAllowed;
860  private $OrderList;
861 
862  # get/set ordering values
863  private function GetPreviousItemId($ItemId)
864  {
865  return $this->DB->Query("SELECT Previous".$this->ItemIdFieldName
866  ." FROM ".$this->ItemTableName
867  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId),
868  "Previous".$this->ItemIdFieldName);
869  }
870  private function GetNextItemIdInOrder($ItemId)
871  {
872  return $this->DB->Query("SELECT Next".$this->ItemIdFieldName
873  ." FROM ".$this->ItemTableName
874  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId),
875  "Next".$this->ItemIdFieldName);
876  }
877  private function SetPreviousItemId($ItemId, $NewValue)
878  {
879  $this->DB->Query("UPDATE ".$this->ItemTableName
880  ." SET Previous".$this->ItemIdFieldName." = ".intval($NewValue)
881  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
882  }
883  private function SetNextItemId($ItemId, $NewValue)
884  {
885  $this->DB->Query("UPDATE ".$this->ItemTableName
886  ." SET Next".$this->ItemIdFieldName." = ".intval($NewValue)
887  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
888  }
889  private function SetPreviousAndNextItemIds($ItemId, $NewPreviousId, $NewNextId)
890  {
891  $this->DB->Query("UPDATE ".$this->ItemTableName
892  ." SET Previous".$this->ItemIdFieldName." = ".intval($NewPreviousId)
893  .", Next".$this->ItemIdFieldName." = ".intval($NewNextId)
894  ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId));
895  }
896 }
897 
898 ?>