CWIS Developer Documentation
TransportControlsUI_Base.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: TransportControlsUI_Base.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2015-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
19 {
20  # ---- PUBLIC INTERFACE --------------------------------------------------
21 
23  const NO_ITEM_TYPE = PHP_INT_MAX;
24 
35  public function __construct($ItemTypes, $ItemsPerPage = 10)
36  {
37  # normalize and store item types
38  if (is_array($ItemTypes))
39  {
40  $this->ItemTypes = $ItemTypes;
41  }
42  else
43  {
44  $this->ItemTypes = array($ItemTypes);
45  }
46 
47  # normalize and store items per page
49 
50  # retrieve current position (if any) from URL
51  $this->StartingIndex(isset($_GET[static::PNAME_STARTINGINDEX])
52  ? $_GET[static::PNAME_STARTINGINDEX] : array());
53 
54  # retrieve sort fields (if any) from URL
55  $this->SortField(isset($_GET[static::PNAME_SORTFIELD])
56  ? $_GET[static::PNAME_SORTFIELD] : array());
57  $this->ReverseSortFlag(isset($_GET[static::PNAME_REVERSESORT])
58  ? $_GET[static::PNAME_REVERSESORT] : array());
59 
60  # retrieve active tab (if any) from URL
61  if (isset($_GET[static::PNAME_ACTIVETAB]))
62  {
63  $this->ActiveTab($_GET[static::PNAME_ACTIVETAB]);
64  }
65  }
66 
77  public function ItemsPerPage($NewValue = NULL)
78  {
79  if ($NewValue !== NULL)
80  {
81  if (is_array($NewValue))
82  {
83  $this->ItemsPerPage = $NewValue;
84  if (count($this->ItemsPerPage) != count($this->ItemTypes))
85  {
86  throw new InvalidArgumentException("Count of items per page ("
87  .count($this->ItemsPerPage)
88  .") does not match count of item types ("
89  .count($this->ItemTypes).").");
90  }
91  }
92  else
93  {
94  foreach ($this->ItemTypes as $ItemType)
95  {
96  $this->ItemsPerPage[$ItemType] = $NewValue;
97  }
98  }
99  }
100  return $this->ItemsPerPage;
101  }
102 
113  public function ItemCount($ItemCounts = NULL)
114  {
115  if ($ItemCounts !== NULL)
116  {
117  # make sure incoming data makes sense based on known item types
118  if (!is_array($ItemCounts)
119  && (is_array($ItemCounts) && count($this->ItemCounts) > 1))
120  {
121  throw new InvalidArgumentException("Single item count supplied"
122  ." when multiple item types were supplied to constructor.");
123  }
124 
125  # normalize and store item counts
126  foreach ($this->ItemTypes as $ItemType)
127  {
128  if (is_array($ItemCounts))
129  {
130  if (isset($ItemCounts[$ItemType]))
131  {
132  $this->ItemCounts[$ItemType] =
133  is_array($ItemCounts[$ItemType])
134  ? count($ItemCounts[$ItemType])
135  : $ItemCounts[$ItemType];
136  }
137  else
138  {
139  $this->ItemCounts[$ItemType] = 0;
140  }
141  }
142  else
143  {
144  $this->ItemCounts[$ItemType] = $ItemCounts;
145  }
146  }
147 
148  # determine index of first item on the first and last page
149  foreach ($this->ItemTypes as $ItemType)
150  {
151  $this->LastPageStartIndexes[$ItemType] = $this->ItemCounts[$ItemType]
152  - ($this->ItemCounts[$ItemType] % $this->ItemsPerPage[$ItemType]);
153  }
154 
155  # make sure starting indexes are within bounds
156  foreach ($this->ItemTypes as $ItemType)
157  {
158  if ($this->StartingIndexes[$ItemType]
159  > $this->LastPageStartIndexes[$ItemType])
160  {
161  $this->StartingIndexes[$ItemType] =
162  $this->LastPageStartIndexes[$ItemType];
163  }
164  }
165 
166  # if active tab not already specified
167  if (!isset($this->ActiveTab))
168  {
169  # if there are item counts available
170  if (count($this->ItemCounts))
171  {
172  # set active tab based on item type with the highest count
173  $SortedCounts = $this->ItemCounts;
174  arsort($SortedCounts);
175  reset($SortedCounts);
176  $this->ActiveTab = key($SortedCounts);
177  }
178  }
179  }
180 
181  return $this->ItemCounts;
182  }
183 
194  public function StartingIndex($NewValue = NULL)
195  {
196  # if new starting index supplied
197  if ($NewValue !== NULL)
198  {
199  # start with empty (all default value) indexes
200  $this->StartingIndexes = array();
201 
202  # for each item type
203  foreach ($this->ItemTypes as $ItemType)
204  {
205  if (is_array($NewValue))
206  {
207  $this->StartingIndexes[$ItemType] =
208  isset($NewValue[$ItemType])
209  ? $NewValue[$ItemType]
210  : 0;
211  }
212  else
213  {
214  $this->StartingIndexes[$ItemType] = $NewValue;
215  }
216 
217  # make sure starting index is within bounds
218  if (isset($this->LastPageStartIndexes[$ItemType]))
219  {
220  if ($this->StartingIndexes[$ItemType]
221  > $this->LastPageStartIndexes[$ItemType])
222  {
223  $this->StartingIndexes[$ItemType] =
224  $this->LastPageStartIndexes[$ItemType];
225  }
226  }
227  }
228  }
229 
230  # return array of values or single value to caller, depending on
231  # whether we are using multiple item types
232  return (count($this->ItemTypes) > 1)
233  ? $this->StartingIndexes
234  : reset($this->StartingIndexes);
235  }
236 
246  public function SortField($NewValue = NULL)
247  {
248  # if new sort field supplied
249  if ($NewValue !== NULL)
250  {
251  # start with empty (all default) sort field list
252  $this->SortFields = array();
253 
254  # for each item type
255  foreach ($this->ItemTypes as $ItemType)
256  {
257  # if multiple new values supplied
258  if (is_array($NewValue))
259  {
260  # if valid value supplied for this item type
261  if (isset($NewValue[$ItemType])
262  && $this->IsValidField($NewValue[$ItemType], $ItemType))
263  {
264  # use supplied value
265  $this->SortFields[$ItemType] = $NewValue[$ItemType];
266  }
267  else
268  {
269  # set to default
270  $this->SortFields[$ItemType] = self::$DefaultSortField;
271  }
272  }
273  else
274  {
275  # if supplied value looks valid
276  if ($this->IsValidField($NewValue, $ItemType))
277  {
278  # set value for item type to this value
279  $this->SortFields[$ItemType] = $NewValue;
280  }
281  else
282  {
283  # set to default
284  $this->SortFields[$ItemType] = self::$DefaultSortField;
285  }
286  }
287  }
288  }
289 
290  # return array of values or single value to caller, depending on
291  # whether we are using multiple item types
292  return (count($this->ItemTypes) > 1)
293  ? $this->SortFields
294  : reset($this->SortFields);
295  }
296 
302  public static function DefaultSortField($NewValue = NULL)
303  {
304  if ($NewValue !== NULL)
305  {
306  self::$DefaultSortField = $NewValue;
307  }
308  return self::$DefaultSortField;
309  }
310 
317  public function ActiveTab($NewValue = NULL)
318  {
319  if ($NewValue !== NULL)
320  {
321  $this->ActiveTab = $NewValue;
322  }
323  return isset($this->ActiveTab)
324  ? $this->ActiveTab
325  : self::$DefaultActiveTab;
326  }
327 
333  public static function DefaultActiveTab($NewValue = NULL)
334  {
335  if ($NewValue !== NULL)
336  {
337  self::$DefaultActiveTab = $NewValue;
338  }
339  return self::$DefaultActiveTab;
340  }
341 
351  public function ReverseSortFlag($NewValue = NULL)
352  {
353  # if new value(s) supplied
354  if ($NewValue !== NULL)
355  {
356  # start with empty (all default value)
357  $this->ReverseSortFlags = array();
358 
359  # for each item type
360  foreach ($this->ItemTypes as $ItemType)
361  {
362  # if multiple new values supplied
363  if (is_array($NewValue))
364  {
365  # if value supplied for this item type
366  if (isset($NewValue[$ItemType]))
367  {
368  # use supplied value
369  $this->ReverseSortFlags[$ItemType] =
370  ($NewValue[$ItemType] ? TRUE : FALSE);
371  }
372  else
373  {
374  # assume no reverse sort for item type
375  $this->ReverseSortFlags[$ItemType] = FALSE;
376  }
377  }
378  else
379  {
380  # set value for item type to supplied value
381  $this->ReverseSortFlags[$ItemType] =
382  ($NewValue ? TRUE : FALSE);
383  }
384  }
385  }
386 
387  # return array of values or single value to caller, depending on
388  # whether we are using multiple item types
389  return (count($this->ItemTypes) > 1)
390  ? $this->ReverseSortFlags
391  : reset($this->ReverseSortFlags);
392  }
393 
403  public function UrlParameterString(
404  $EncodeSeparators = TRUE, $ExcludeParameters = NULL)
405  {
406  # add any non-default starting indexes to query data
407  foreach ($this->StartingIndexes as $ItemType => $Index)
408  {
409  if ($Index != 0)
410  {
411  $QData[static::PNAME_STARTINGINDEX][$ItemType] = $Index;
412  }
413  }
414 
415  # add any non-default sort fields to query data
416  foreach ($this->SortFields as $ItemType => $Field)
417  {
418  if ($Field != self::$DefaultSortField)
419  {
420  $QData[static::PNAME_SORTFIELD][$ItemType] = $Field;
421  }
422  }
423 
424  # add any non-default sort directions to query data
425  foreach ($this->ReverseSortFlags as $ItemType => $Flag)
426  {
427  if ($Flag)
428  {
429  $QData[static::PNAME_REVERSESORT][$ItemType] = 1;
430  }
431  }
432 
433  # add active tab to query data if set and meaningful
434  if (isset($this->ActiveTab) && (count($this->ItemTypes) > 1))
435  {
436  $QData[static::PNAME_ACTIVETAB] = $this->ActiveTab;
437  }
438 
439  # remove any requested exclusions
440  if (isset($QData))
441  {
442  if ($ExcludeParameters)
443  {
444  foreach ($ExcludeParameters as $Param)
445  {
446  if (isset($QData[$Param]))
447  {
448  unset($QData[$Param]);
449  }
450  }
451  }
452  }
453 
454  # collapse down parameters if only one item type
455  if (count($this->ItemTypes) == 1)
456  {
457  $Params = array(static::PNAME_STARTINGINDEX,
458  static::PNAME_SORTFIELD,
459  static::PNAME_REVERSESORT);
460  foreach ($Params as $Param)
461  {
462  if (isset($QData[$Param]))
463  {
464  $QData[$Param] = reset($QData[$Param]);
465  }
466  }
467  }
468 
469  # if no non-default transport parameters
470  if (!isset($QData) || !count($QData))
471  {
472  # return empty string
473  return "";
474  }
475  else
476  {
477  # build parameter string and return it to caller
478  $Sep = $EncodeSeparators ? "&amp;" : "&";
479  return $Sep.http_build_query($QData, "", $Sep);
480  }
481  }
482 
490  public function ItemTypeNames($Names = NULL)
491  {
492  if ($Names !== NULL)
493  {
494  $this->ItemTypeNames = $Names;
495  }
496  return $this->ItemTypeNames;
497  }
498 
499  # ---- TEST/LINK METHODS ------------------------------------------------
500  # (useful if constructing your own interface rather than using PrintControls()
501 
506  public function SetItemType($ItemType)
507  {
508  $this->CurrentItemType = $ItemType;
509  }
510 
515  public function SetBaseLink($BaseLink)
516  {
517  $this->CurrentBaseLink = $BaseLink;
518  }
519 
527  public function ShowAnyForwardButtons()
528  {
529  return (($this->StartingIndexes[$this->CurrentItemType]
530  + $this->ItemsPerPage[$this->CurrentItemType])
531  < ($this->LastPageStartIndexes[$this->CurrentItemType] + 1))
532  ? TRUE : FALSE;
533  }
534 
542  public function ShowAnyReverseButtons()
543  {
544  return ($this->StartingIndexes[$this->CurrentItemType] > 0)
545  ? TRUE : FALSE;
546  }
547 
554  public function ShowForwardButton()
555  {
556  return ($this->StartingIndexes[$this->CurrentItemType]
557  < ($this->LastPageStartIndexes[$this->CurrentItemType]
558  - $this->ItemsPerPage[$this->CurrentItemType]))
559  ? TRUE : FALSE;
560  }
561 
568  public function ShowReverseButton()
569  {
570  return (($this->StartingIndexes[$this->CurrentItemType] + 1)
571  >= ($this->ItemsPerPage[$this->CurrentItemType] * 2))
572  ? TRUE : FALSE;
573  }
574 
582  public function ShowFastForwardButton()
583  {
584  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
585  && (($this->StartingIndexes[$this->CurrentItemType]
586  + $this->FastDistance())
587  < $this->LastPageStartIndexes[$this->CurrentItemType]))
588  ? TRUE : FALSE;
589  }
590 
598  public function ShowFastReverseButton()
599  {
600  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
601  && ($this->StartingIndexes[$this->CurrentItemType]
602  >= $this->FastDistance()))
603  ? TRUE : FALSE;
604  }
605 
610  public function ForwardLink()
611  {
612  return $this->GetLinkWithStartingIndex(
613  min($this->LastPageStartIndexes[$this->CurrentItemType],
614  ($this->StartingIndexes[$this->CurrentItemType]
615  + $this->ItemsPerPage[$this->CurrentItemType])));
616  }
617 
622  public function ReverseLink()
623  {
624  return $this->GetLinkWithStartingIndex(
625  max(0, ($this->StartingIndexes[$this->CurrentItemType]
626  - $this->ItemsPerPage[$this->CurrentItemType])));
627  }
628 
633  public function FastForwardLink()
634  {
635  return $this->GetLinkWithStartingIndex(
636  min($this->LastPageStartIndexes[$this->CurrentItemType],
637  ($this->StartingIndexes[$this->CurrentItemType]
638  + $this->FastDistance())));
639  }
640 
645  public function FastReverseLink()
646  {
647  return $this->GetLinkWithStartingIndex(
648  max(0, ($this->StartingIndexes[$this->CurrentItemType]
649  - $this->FastDistance())));
650  }
651 
656  public function GoToEndLink()
657  {
658  return $this->GetLinkWithStartingIndex(
659  $this->LastPageStartIndexes[$this->CurrentItemType]);
660  }
661 
666  public function GoToStartLink()
667  {
668  return $this->GetLinkWithStartingIndex(0);
669  }
670 
671 
672  # ---- PRIVATE INTERFACE -------------------------------------------------
673 
674  protected $ActiveTab;
675  protected $CurrentBaseLink;
676  protected $CurrentItemType;
677  protected $ItemCounts;
678  protected $ItemsPerPage;
679  protected $ItemTypeNames;
680  protected $ItemTypes;
682  protected $ReverseSortFlags;
683  protected $SortFields;
684  protected $StartingIndexes;
685 
687  protected static $DefaultSortField = "R";
688 
693  protected function FastDistance()
694  {
695  return floor($this->ItemCounts[$this->CurrentItemType] / 5)
696  - (floor($this->ItemCounts[$this->CurrentItemType] / 5)
698  }
699 
705  protected function GetLinkWithStartingIndex($StartingIndex)
706  {
707  # temporarily swap in supplied starting index
708  $SavedStartingIndex = $this->StartingIndexes[$this->CurrentItemType];
709  $this->StartingIndexes[$this->CurrentItemType] = $StartingIndex;
710 
711  # get link with parameters
712  $Link = $this->CurrentBaseLink.$this->UrlParameterString();
713 
714  # restore starting index
715  $this->StartingIndexes[$this->CurrentItemType] = $SavedStartingIndex;
716 
717  # return link to caller
718  return $Link;
719  }
720 
727  protected function IsValidField($Field, $ItemType)
728  {
729  # default field is assumed to always be valid
730  if ($Field === self::$DefaultSortField)
731  {
732  return TRUE;
733  }
734 
735  # fields are assumed to be always valid for no item type
736  if ($ItemType === self::NO_ITEM_TYPE)
737  {
738  return TRUE;
739  }
740 
741  # load metadata schema to check against (if not already loaded)
742  static $Schemas;
743  if (!isset($Schemas[$ItemType]))
744  {
745  $Schemas[$ItemType] = new MetadataSchema($ItemType);
746  }
747 
748  # report to caller whether field exists for this schema
749  return $Schemas[$ItemType]->FieldExists($Field);
750  }
751 }
ReverseLink()
Get link for reverse button.
ForwardLink()
Get link for forward button.
Metadata schema (in effect a Factory class for MetadataField).
ItemsPerPage($NewValue=NULL)
Get/set maximum number of items per page.
ActiveTab($NewValue=NULL)
Get/set the active tab value (usually an item type).
ShowForwardButton()
Report whether forward button should be displayed.
FastReverseLink()
Get link for fast reverse button.
FastDistance()
Get distance to jump for fast forward/reverse.
static DefaultSortField($NewValue=NULL)
Get/set default sort field value.
GoToStartLink()
Get link for button to go to start.
ReverseSortFlag($NewValue=NULL)
Get/set whether to reverse the sort order from normal.
GoToEndLink()
Get link for button to go to end.
static DefaultActiveTab($NewValue=NULL)
Get/set the default active tab value (usually an item type).
ShowAnyForwardButtons()
Report whether any forward buttons should be displayed.
__construct($ItemTypes, $ItemsPerPage=10)
Class constructor.
Class to provide support for transport controls (used for paging back and forth through a list) in th...
ShowReverseButton()
Report whether reverse button should be displayed.
UrlParameterString($EncodeSeparators=TRUE, $ExcludeParameters=NULL)
Get string containing URL parameters, ready for inclusion in URL.
FastForwardLink()
Get link for fast forward button.
ShowAnyReverseButtons()
Report whether any reverse buttons should be displayed.
GetLinkWithStartingIndex($StartingIndex)
Generate link with specified modified starting index.
SortField($NewValue=NULL)
Get/set ID of field(s) currently used for sorting.
ShowFastReverseButton()
Report whether fast reverse button should be displayed.
IsValidField($Field, $ItemType)
Check whether specified field looks valid for specified item type.
ItemTypeNames($Names=NULL)
Get/set printable names for item types.
SetBaseLink($BaseLink)
Set current base link for Link methods.
const NO_ITEM_TYPE
Constant to use when no item types available.
ShowFastForwardButton()
Report whether fast forward button should be displayed.
ItemCount($ItemCounts=NULL)
Get/set count of items in search results.
SetItemType($ItemType)
Set current item type for Show or Link methods.
StartingIndex($NewValue=NULL)
Get/set current starting index values.