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 
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
48  if (is_array($ItemsPerPage))
49  {
50  $this->ItemsPerPage = $ItemsPerPage;
51  }
52  else
53  {
54  foreach ($this->ItemTypes as $ItemType)
55  {
56  $this->ItemsPerPage[$ItemType] = $ItemsPerPage;
57  }
58  }
59 
60  # retrieve current position (if any) from URL
61  $this->StartingIndex(isset($_GET[static::PNAME_STARTINGINDEX])
62  ? $_GET[static::PNAME_STARTINGINDEX] : array());
63 
64  # retrieve sort fields (if any) from URL
65  $this->SortField(isset($_GET[static::PNAME_SORTFIELD])
66  ? $_GET[static::PNAME_SORTFIELD] : array());
67  $this->ReverseSortFlag(isset($_GET[static::PNAME_REVERSESORT])
68  ? $_GET[static::PNAME_REVERSESORT] : array());
69 
70  # retrieve active tab (if any) from URL
71  if (isset($_GET[static::PNAME_ACTIVETAB]))
72  {
73  $this->ActiveTab($_GET[static::PNAME_ACTIVETAB]);
74  }
75  }
76 
87  public function ItemCount($ItemCounts = NULL)
88  {
89  if ($ItemCounts !== NULL)
90  {
91  # make sure incoming data makes sense based on known item types
92  if (!is_array($ItemCounts)
93  && (is_array($ItemCounts) && count($this->ItemCounts) > 1))
94  {
95  throw new InvalidArgumentException("Single item count supplied"
96  ." when multiple item types were supplied to constructor.");
97  }
98 
99  # normalize and store item counts
100  foreach ($this->ItemTypes as $ItemType)
101  {
102  if (is_array($ItemCounts))
103  {
104  if (isset($ItemCounts[$ItemType]))
105  {
106  $this->ItemCounts[$ItemType] =
107  is_array($ItemCounts[$ItemType])
108  ? count($ItemCounts[$ItemType])
109  : $ItemCounts[$ItemType];
110  }
111  else
112  {
113  $this->ItemCounts[$ItemType] = 0;
114  }
115  }
116  else
117  {
118  $this->ItemCounts[$ItemType] = $ItemCounts;
119  }
120  }
121 
122  # determine index of first item on the first and last page
123  foreach ($this->ItemTypes as $ItemType)
124  {
125  $this->LastPageStartIndexes[$ItemType] = $this->ItemCounts[$ItemType]
126  - ($this->ItemCounts[$ItemType] % $this->ItemsPerPage[$ItemType]);
127  }
128 
129  # make sure starting indexes are within bounds
130  foreach ($this->ItemTypes as $ItemType)
131  {
132  if ($this->StartingIndexes[$ItemType]
133  > $this->LastPageStartIndexes[$ItemType])
134  {
135  $this->StartingIndexes[$ItemType] =
136  $this->LastPageStartIndexes[$ItemType];
137  }
138  }
139 
140  # if active tab not already specified
141  if (!isset($this->ActiveTab))
142  {
143  # if there are item counts available
144  if (count($this->ItemCounts))
145  {
146  # set active tab based on item type with the highest count
147  $SortedCounts = $this->ItemCounts;
148  arsort($SortedCounts);
149  reset($SortedCounts);
150  $this->ActiveTab = key($SortedCounts);
151  }
152  }
153  }
154 
155  return $this->ItemCounts;
156  }
157 
168  public function StartingIndex($NewValue = NULL)
169  {
170  # if new starting index supplied
171  if ($NewValue !== NULL)
172  {
173  # start with empty (all default value) indexes
174  $this->StartingIndexes = array();
175 
176  # for each item type
177  foreach ($this->ItemTypes as $ItemType)
178  {
179  if (is_array($NewValue))
180  {
181  $this->StartingIndexes[$ItemType] =
182  isset($NewValue[$ItemType])
183  ? $NewValue[$ItemType]
184  : 0;
185  }
186  else
187  {
188  $this->StartingIndexes[$ItemType] = $NewValue;
189  }
190 
191  # make sure starting index is within bounds
192  if (isset($this->LastPageStartIndexes[$ItemType]))
193  {
194  if ($this->StartingIndexes[$ItemType]
195  > $this->LastPageStartIndexes[$ItemType])
196  {
197  $this->StartingIndexes[$ItemType] =
198  $this->LastPageStartIndexes[$ItemType];
199  }
200  }
201  }
202  }
203 
204  # return array of values or single value to caller, depending on
205  # whether we are using multiple item types
206  return (count($this->ItemTypes) > 1)
207  ? $this->StartingIndexes
208  : reset($this->StartingIndexes);
209  }
210 
220  public function SortField($NewValue = NULL)
221  {
222  # if new sort field supplied
223  if ($NewValue !== NULL)
224  {
225  # start with empty (all default) sort field list
226  $this->SortFields = array();
227 
228  # for each item type
229  foreach ($this->ItemTypes as $ItemType)
230  {
231  # if multiple new values supplied
232  if (is_array($NewValue))
233  {
234  # if valid value supplied for this item type
235  if (isset($NewValue[$ItemType])
236  && $this->IsValidField($NewValue[$ItemType], $ItemType))
237  {
238  # use supplied value
239  $this->SortFields[$ItemType] = $NewValue[$ItemType];
240  }
241  else
242  {
243  # set to default
244  $this->SortFields[$ItemType] = self::$DefaultSortField;
245  }
246  }
247  else
248  {
249  # if supplied value looks valid
250  if ($this->IsValidField($NewValue, $ItemType))
251  {
252  # set value for item type to this value
253  $this->SortFields[$ItemType] = $NewValue;
254  }
255  else
256  {
257  # set to default
258  $this->SortFields[$ItemType] = self::$DefaultSortField;
259  }
260  }
261  }
262  }
263 
264  # return array of values or single value to caller, depending on
265  # whether we are using multiple item types
266  return (count($this->ItemTypes) > 1)
267  ? $this->SortFields
268  : reset($this->SortFields);
269  }
270 
276  public static function DefaultSortField($NewValue = NULL)
277  {
278  if ($NewValue !== NULL)
279  {
280  self::$DefaultSortField = $NewValue;
281  }
282  return self::$DefaultSortField;
283  }
284 
291  public function ActiveTab($NewValue = NULL)
292  {
293  if ($NewValue !== NULL)
294  {
295  $this->ActiveTab = $NewValue;
296  }
297  return isset($this->ActiveTab)
298  ? $this->ActiveTab
299  : self::$DefaultActiveTab;
300  }
301 
307  public static function DefaultActiveTab($NewValue = NULL)
308  {
309  if ($NewValue !== NULL)
310  {
311  self::$DefaultActiveTab = $NewValue;
312  }
313  return self::$DefaultActiveTab;
314  }
315 
325  public function ReverseSortFlag($NewValue = NULL)
326  {
327  # if new value(s) supplied
328  if ($NewValue !== NULL)
329  {
330  # start with empty (all default value)
331  $this->ReverseSortFlags = array();
332 
333  # for each item type
334  foreach ($this->ItemTypes as $ItemType)
335  {
336  # if multiple new values supplied
337  if (is_array($NewValue))
338  {
339  # if value supplied for this item type
340  if (isset($NewValue[$ItemType]))
341  {
342  # use supplied value
343  $this->ReverseSortFlags[$ItemType] =
344  ($NewValue[$ItemType] ? TRUE : FALSE);
345  }
346  else
347  {
348  # assume no reverse sort for item type
349  $this->ReverseSortFlags[$ItemType] = FALSE;
350  }
351  }
352  else
353  {
354  # set value for item type to supplied value
355  $this->ReverseSortFlags[$ItemType] =
356  ($NewValue ? TRUE : FALSE);
357  }
358  }
359  }
360 
361  # return array of values or single value to caller, depending on
362  # whether we are using multiple item types
363  return (count($this->ItemTypes) > 1)
364  ? $this->ReverseSortFlags
365  : reset($this->ReverseSortFlags);
366  }
367 
377  public function UrlParameterString(
378  $EncodeSeparators = TRUE, $ExcludeParameters = NULL)
379  {
380  # add any non-default starting indexes to query data
381  foreach ($this->StartingIndexes as $ItemType => $Index)
382  {
383  if ($Index != 0)
384  {
385  $QData[static::PNAME_STARTINGINDEX][$ItemType] = $Index;
386  }
387  }
388 
389  # add any non-default sort fields to query data
390  foreach ($this->SortFields as $ItemType => $Field)
391  {
392  if ($Field != self::$DefaultSortField)
393  {
394  $QData[static::PNAME_SORTFIELD][$ItemType] = $Field;
395  }
396  }
397 
398  # add any non-default sort directions to query data
399  foreach ($this->ReverseSortFlags as $ItemType => $Flag)
400  {
401  if ($Flag)
402  {
403  $QData[static::PNAME_REVERSESORT][$ItemType] = 1;
404  }
405  }
406 
407  # add active tab to query data if set and meaningful
408  if (isset($this->ActiveTab) && (count($this->ItemTypes) > 1))
409  {
410  $QData[static::PNAME_ACTIVETAB] = $this->ActiveTab;
411  }
412 
413  # remove any requested exclusions
414  if (isset($QData))
415  {
416  if ($ExcludeParameters)
417  {
418  foreach ($ExcludeParameters as $Param)
419  {
420  if (isset($QData[$Param]))
421  {
422  unset($QData[$Param]);
423  }
424  }
425  }
426  }
427 
428  # collapse down parameters if only one item type
429  if (count($this->ItemTypes) == 1)
430  {
431  $Params = array(static::PNAME_STARTINGINDEX,
432  static::PNAME_SORTFIELD,
433  static::PNAME_REVERSESORT);
434  foreach ($Params as $Param)
435  {
436  if (isset($QData[$Param]))
437  {
438  $QData[$Param] = reset($QData[$Param]);
439  }
440  }
441  }
442 
443  # if no non-default transport parameters
444  if (!isset($QData) || !count($QData))
445  {
446  # return empty string
447  return "";
448  }
449  else
450  {
451  # build parameter string and return it to caller
452  $Sep = $EncodeSeparators ? "&amp;" : "&";
453  return $Sep.http_build_query($QData, "", $Sep);
454  }
455  }
456 
464  public function ItemTypeNames($Names = NULL)
465  {
466  if ($Names !== NULL)
467  {
468  $this->ItemTypeNames = $Names;
469  }
470  return $this->ItemTypeNames;
471  }
472 
473  # ---- TEST/LINK METHODS ------------------------------------------------
474  # (useful if constructing your own interface rather than using PrintControls()
475 
480  public function SetItemType($ItemType)
481  {
482  $this->CurrentItemType = $ItemType;
483  }
484 
489  public function SetBaseLink($BaseLink)
490  {
491  $this->CurrentBaseLink = $BaseLink;
492  }
493 
501  public function ShowAnyForwardButtons()
502  {
503  return (($this->StartingIndexes[$this->CurrentItemType]
504  + $this->ItemsPerPage[$this->CurrentItemType])
505  < ($this->LastPageStartIndexes[$this->CurrentItemType] + 1))
506  ? TRUE : FALSE;
507  }
508 
516  public function ShowAnyReverseButtons()
517  {
518  return ($this->StartingIndexes[$this->CurrentItemType] > 0)
519  ? TRUE : FALSE;
520  }
521 
528  public function ShowForwardButton()
529  {
530  return ($this->StartingIndexes[$this->CurrentItemType]
531  < ($this->LastPageStartIndexes[$this->CurrentItemType]
532  - $this->ItemsPerPage[$this->CurrentItemType]))
533  ? TRUE : FALSE;
534  }
535 
542  public function ShowReverseButton()
543  {
544  return (($this->StartingIndexes[$this->CurrentItemType] + 1)
545  >= ($this->ItemsPerPage[$this->CurrentItemType] * 2))
546  ? TRUE : FALSE;
547  }
548 
556  public function ShowFastForwardButton()
557  {
558  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
559  && (($this->StartingIndexes[$this->CurrentItemType]
560  + $this->FastDistance())
561  < $this->LastPageStartIndexes[$this->CurrentItemType]))
562  ? TRUE : FALSE;
563  }
564 
572  public function ShowFastReverseButton()
573  {
574  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
575  && ($this->StartingIndexes[$this->CurrentItemType]
576  >= $this->FastDistance()))
577  ? TRUE : FALSE;
578  }
579 
584  public function ForwardLink()
585  {
586  return $this->GetLinkWithStartingIndex(
587  min($this->LastPageStartIndexes[$this->CurrentItemType],
588  ($this->StartingIndexes[$this->CurrentItemType]
589  + $this->ItemsPerPage[$this->CurrentItemType])));
590  }
591 
596  public function ReverseLink()
597  {
598  return $this->GetLinkWithStartingIndex(
599  max(0, ($this->StartingIndexes[$this->CurrentItemType]
600  - $this->ItemsPerPage[$this->CurrentItemType])));
601  }
602 
607  public function FastForwardLink()
608  {
609  return $this->GetLinkWithStartingIndex(
610  min($this->LastPageStartIndexes[$this->CurrentItemType],
611  ($this->StartingIndexes[$this->CurrentItemType]
612  + $this->FastDistance())));
613  }
614 
619  public function FastReverseLink()
620  {
621  return $this->GetLinkWithStartingIndex(
622  max(0, ($this->StartingIndexes[$this->CurrentItemType]
623  - $this->FastDistance())));
624  }
625 
630  public function GoToEndLink()
631  {
632  return $this->GetLinkWithStartingIndex(
633  $this->LastPageStartIndexes[$this->CurrentItemType]);
634  }
635 
640  public function GoToStartLink()
641  {
642  return $this->GetLinkWithStartingIndex(0);
643  }
644 
645 
646  # ---- PRIVATE INTERFACE -------------------------------------------------
647 
648  protected $ActiveTab;
649  protected $CurrentBaseLink;
650  protected $CurrentItemType;
651  protected $ItemCounts;
652  protected $ItemsPerPage;
653  protected $ItemTypeNames;
654  protected $ItemTypes;
656  protected $ReverseSortFlags;
657  protected $SortFields;
658  protected $StartingIndexes;
659 
661  protected static $DefaultSortField = "R";
662 
667  protected function FastDistance()
668  {
669  return floor($this->ItemCounts[$this->CurrentItemType] / 5)
670  - (floor($this->ItemCounts[$this->CurrentItemType] / 5)
671  % $this->ItemsPerPage[$this->CurrentItemType]);
672  }
673 
679  protected function GetLinkWithStartingIndex($StartingIndex)
680  {
681  # temporarily swap in supplied starting index
682  $SavedStartingIndex = $this->StartingIndexes[$this->CurrentItemType];
683  $this->StartingIndexes[$this->CurrentItemType] = $StartingIndex;
684 
685  # get link with parameters
686  $Link = $this->CurrentBaseLink.$this->UrlParameterString();
687 
688  # restore starting index
689  $this->StartingIndexes[$this->CurrentItemType] = $SavedStartingIndex;
690 
691  # return link to caller
692  return $Link;
693  }
694 
701  protected function IsValidField($Field, $ItemType)
702  {
703  # default field is assumed to always be valid
704  if ($Field === self::$DefaultSortField)
705  {
706  return TRUE;
707  }
708 
709  # fields are assumed to be always valid for no item type
710  if ($ItemType === self::NO_ITEM_TYPE)
711  {
712  return TRUE;
713  }
714 
715  # load metadata schema to check against (if not already loaded)
716  static $Schemas;
717  if (!isset($Schemas[$ItemType]))
718  {
719  $Schemas[$ItemType] = new MetadataSchema($ItemType);
720  }
721 
722  # report to caller whether field exists for this schema
723  return $Schemas[$ItemType]->FieldExists($Field);
724  }
725 }
ReverseLink()
Get link for reverse button.
ForwardLink()
Get link for forward button.
Metadata schema (in effect a Factory class for MetadataField).
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.
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.
__construct($ItemTypes, $ItemsPerPage)
Class constructor.
StartingIndex($NewValue=NULL)
Get/set current starting index values.