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