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 
85  public function ItemCount($ItemCounts)
86  {
87  # make sure incoming data makes sense based on known item types
88  if (!is_array($ItemCounts)
89  && (count($this->ItemCounts) > 1))
90  {
91  throw InvalidArgumentException("Single item count supplied"
92  ." when multiple item types were supplied to constructor.");
93  }
94 
95  # normalize and store item counts
96  foreach ($this->ItemTypes as $ItemType)
97  {
98  if (is_array($ItemCounts))
99  {
100  if (isset($ItemCounts[$ItemType]))
101  {
102  $this->ItemCounts[$ItemType] =
103  is_array($ItemCounts[$ItemType])
104  ? count($ItemCounts[$ItemType])
105  : $ItemCounts[$ItemType];
106  }
107  else
108  {
109  $this->ItemCounts[$ItemType] = 0;
110  }
111  }
112  else
113  {
114  $this->ItemCounts[$ItemType] = $ItemCounts;
115  }
116  }
117 
118  # determine index of first item on the first and last page
119  foreach ($this->ItemTypes as $ItemType)
120  {
121  $this->LastPageStartIndexes[$ItemType] = $this->ItemCounts[$ItemType]
122  - ($this->ItemCounts[$ItemType] % $this->ItemsPerPage[$ItemType]);
123  }
124 
125  # make sure starting indexes are within bounds
126  foreach ($this->ItemTypes as $ItemType)
127  {
128  if ($this->StartingIndexes[$ItemType]
129  > $this->LastPageStartIndexes[$ItemType])
130  {
131  $this->StartingIndexes[$ItemType] =
132  $this->LastPageStartIndexes[$ItemType];
133  }
134  }
135 
136  # if active tab not already specified
137  if (!isset($this->ActiveTab))
138  {
139  # if there are item counts available
140  if (count($this->ItemCounts))
141  {
142  # set active tab based on item type with the highest count
143  $SortedCounts = $this->ItemCounts;
144  arsort($SortedCounts);
145  reset($SortedCounts);
146  $this->ActiveTab = key($SortedCounts);
147  }
148  }
149  }
150 
161  public function StartingIndex($NewValue = NULL)
162  {
163  # if new starting index supplied
164  if ($NewValue !== NULL)
165  {
166  # start with empty (all default value) indexes
167  $this->StartingIndexes = array();
168 
169  # for each item type
170  foreach ($this->ItemTypes as $ItemType)
171  {
172  if (is_array($NewValue))
173  {
174  $this->StartingIndexes[$ItemType] =
175  isset($NewValue[$ItemType])
176  ? $NewValue[$ItemType]
177  : 0;
178  }
179  else
180  {
181  $this->StartingIndexes[$ItemType] = $NewValue;
182  }
183 
184  # make sure starting index is within bounds
185  if (isset($this->LastPageStartIndexes[$ItemType]))
186  {
187  if ($this->StartingIndexes[$ItemType]
188  > $this->LastPageStartIndexes[$ItemType])
189  {
190  $this->StartingIndexes[$ItemType] =
191  $this->LastPageStartIndexes[$ItemType];
192  }
193  }
194  }
195  }
196 
197  # return array of values or single value to caller, depending on
198  # whether we are using multiple item types
199  return (count($this->ItemTypes) > 1)
200  ? $this->StartingIndexes
201  : reset($this->StartingIndexes);
202  }
203 
213  public function SortField($NewValue = NULL)
214  {
215  # if new sort field supplied
216  if ($NewValue !== NULL)
217  {
218  # start with empty (all default) sort field list
219  $this->SortFields = array();
220 
221  # for each item type
222  foreach ($this->ItemTypes as $ItemType)
223  {
224  # if multiple new values supplied
225  if (is_array($NewValue))
226  {
227  # if valid value supplied for this item type
228  if (isset($NewValue[$ItemType])
229  && $this->IsValidField($NewValue[$ItemType], $ItemType))
230  {
231  # use supplied value
232  $this->SortFields[$ItemType] = $NewValue[$ItemType];
233  }
234  else
235  {
236  # set to default
237  $this->SortFields[$ItemType] = self::$DefaultSortField;
238  }
239  }
240  else
241  {
242  # if supplied value looks valid
243  if ($this->IsValidField($NewValue, $ItemType))
244  {
245  # set value for item type to this value
246  $this->SortFields[$ItemType] = $NewValue;
247  }
248  else
249  {
250  # set to default
251  $this->SortFields[$ItemType] = self::$DefaultSortField;
252  }
253  }
254  }
255  }
256 
257  # return array of values or single value to caller, depending on
258  # whether we are using multiple item types
259  return (count($this->ItemTypes) > 1)
260  ? $this->SortFields
261  : reset($this->SortFields);
262  }
263 
269  public static function DefaultSortField($NewValue = NULL)
270  {
271  if ($NewValue !== NULL)
272  {
273  self::$DefaultSortField = $NewValue;
274  }
275  return self::$DefaultSortField;
276  }
277 
284  public function ActiveTab($NewValue = NULL)
285  {
286  if ($NewValue !== NULL)
287  {
288  $this->ActiveTab = $NewValue;
289  }
290  return isset($this->ActiveTab)
291  ? $this->ActiveTab
292  : self::$DefaultActiveTab;
293  }
294 
300  public static function DefaultActiveTab($NewValue = NULL)
301  {
302  if ($NewValue !== NULL)
303  {
304  self::$DefaultActiveTab = $NewValue;
305  }
306  return self::$DefaultActiveTab;
307  }
308 
318  public function ReverseSortFlag($NewValue = NULL)
319  {
320  # if new value(s) supplied
321  if ($NewValue !== NULL)
322  {
323  # start with empty (all default value)
324  $this->ReverseSortFlags = array();
325 
326  # for each item type
327  foreach ($this->ItemTypes as $ItemType)
328  {
329  # if multiple new values supplied
330  if (is_array($NewValue))
331  {
332  # if value supplied for this item type
333  if (isset($NewValue[$ItemType]))
334  {
335  # use supplied value
336  $this->ReverseSortFlags[$ItemType] =
337  ($NewValue[$ItemType] ? TRUE : FALSE);
338  }
339  else
340  {
341  # assume no reverse sort for item type
342  $this->ReverseSortFlags[$ItemType] = FALSE;
343  }
344  }
345  else
346  {
347  # set value for item type to supplied value
348  $this->ReverseSortFlags[$ItemType] =
349  ($NewValue ? TRUE : FALSE);
350  }
351  }
352  }
353 
354  # return array of values or single value to caller, depending on
355  # whether we are using multiple item types
356  return (count($this->ItemTypes) > 1)
357  ? $this->ReverseSortFlags
358  : reset($this->ReverseSortFlags);
359  }
360 
370  public function UrlParameterString(
371  $EncodeSeparators = TRUE, $ExcludeParameters = NULL)
372  {
373  # add any non-default starting indexes to query data
374  foreach ($this->StartingIndexes as $ItemType => $Index)
375  {
376  if ($Index != 0)
377  {
378  $QData[static::PNAME_STARTINGINDEX][$ItemType] = $Index;
379  }
380  }
381 
382  # add any non-default sort fields to query data
383  foreach ($this->SortFields as $ItemType => $Field)
384  {
385  if ($Field != self::$DefaultSortField)
386  {
387  $QData[static::PNAME_SORTFIELD][$ItemType] = $Field;
388  }
389  }
390 
391  # add any non-default sort directions to query data
392  foreach ($this->ReverseSortFlags as $ItemType => $Flag)
393  {
394  if ($Flag)
395  {
396  $QData[static::PNAME_REVERSESORT][$ItemType] = 1;
397  }
398  }
399 
400  # add active tab to query data if set and meaningful
401  if (isset($this->ActiveTab) && (count($this->ItemTypes) > 1))
402  {
403  $QData[static::PNAME_ACTIVETAB] = $this->ActiveTab;
404  }
405 
406  # remove any requested exclusions
407  if (isset($QData))
408  {
409  if ($ExcludeParameters)
410  {
411  foreach ($ExcludeParameters as $Param)
412  {
413  if (isset($QData[$Param]))
414  {
415  unset($QData[$Param]);
416  }
417  }
418  }
419  }
420 
421  # collapse down parameters if only one item type
422  if (count($this->ItemTypes) == 1)
423  {
424  $Params = array(static::PNAME_STARTINGINDEX,
425  static::PNAME_SORTFIELD,
426  static::PNAME_REVERSESORT);
427  foreach ($Params as $Param)
428  {
429  if (isset($QData[$Param]))
430  {
431  $QData[$Param] = reset($QData[$Param]);
432  }
433  }
434  }
435 
436  # if no non-default transport parameters
437  if (!isset($QData) || !count($QData))
438  {
439  # return empty string
440  return "";
441  }
442  else
443  {
444  # build parameter string and return it to caller
445  $Sep = $EncodeSeparators ? "&amp;" : "&";
446  return $Sep.http_build_query($QData, "", $Sep);
447  }
448  }
449 
450  # ---- TEST/LINK METHODS ------------------------------------------------
451  # (useful if constructing your own interface rather than using PrintControls()
452 
457  public function SetItemType($ItemType)
458  {
459  $this->CurrentItemType = $ItemType;
460  }
461 
466  public function SetBaseLink($BaseLink)
467  {
468  $this->CurrentBaseLink = $BaseLink;
469  }
470 
478  public function ShowAnyForwardButtons()
479  {
480  return (($this->StartingIndexes[$this->CurrentItemType]
481  + $this->ItemsPerPage[$this->CurrentItemType])
482  < ($this->LastPageStartIndexes[$this->CurrentItemType] + 1))
483  ? TRUE : FALSE;
484  }
485 
493  public function ShowAnyReverseButtons()
494  {
495  return ($this->StartingIndexes[$this->CurrentItemType] > 0)
496  ? TRUE : FALSE;
497  }
498 
505  public function ShowForwardButton()
506  {
507  return ($this->StartingIndexes[$this->CurrentItemType]
508  < ($this->LastPageStartIndexes[$this->CurrentItemType]
509  - $this->ItemsPerPage[$this->CurrentItemType]))
510  ? TRUE : FALSE;
511  }
512 
519  public function ShowReverseButton()
520  {
521  return (($this->StartingIndexes[$this->CurrentItemType] + 1)
522  >= ($this->ItemsPerPage[$this->CurrentItemType] * 2))
523  ? TRUE : FALSE;
524  }
525 
533  public function ShowFastForwardButton()
534  {
535  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
536  && (($this->StartingIndexes[$this->CurrentItemType]
537  + $this->FastDistance())
538  < $this->LastPageStartIndexes[$this->CurrentItemType]))
539  ? TRUE : FALSE;
540  }
541 
549  public function ShowFastReverseButton()
550  {
551  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
552  && ($this->StartingIndexes[$this->CurrentItemType]
553  >= $this->FastDistance()))
554  ? TRUE : FALSE;
555  }
556 
561  public function ForwardLink()
562  {
563  return $this->GetLinkWithStartingIndex(
564  min($this->LastPageStartIndexes[$this->CurrentItemType],
565  ($this->StartingIndexes[$this->CurrentItemType]
566  + $this->ItemsPerPage[$this->CurrentItemType])));
567  }
568 
573  public function ReverseLink()
574  {
575  return $this->GetLinkWithStartingIndex(
576  max(0, ($this->StartingIndexes[$this->CurrentItemType]
577  - $this->ItemsPerPage[$this->CurrentItemType])));
578  }
579 
584  public function FastForwardLink()
585  {
586  return $this->GetLinkWithStartingIndex(
587  min($this->LastPageStartIndexes[$this->CurrentItemType],
588  ($this->StartingIndexes[$this->CurrentItemType]
589  + $this->FastDistance())));
590  }
591 
596  public function FastReverseLink()
597  {
598  return $this->GetLinkWithStartingIndex(
599  max(0, ($this->StartingIndexes[$this->CurrentItemType]
600  - $this->FastDistance())));
601  }
602 
607  public function GoToEndLink()
608  {
609  return $this->GetLinkWithStartingIndex(
610  $this->LastPageStartIndexes[$this->CurrentItemType]);
611  }
612 
617  public function GoToStartLink()
618  {
619  return $this->GetLinkWithStartingIndex(0);
620  }
621 
622 
623  # ---- PRIVATE INTERFACE -------------------------------------------------
624 
625  protected $ActiveTab;
626  protected $CurrentBaseLink;
627  protected $CurrentItemType;
628  protected $ItemCounts;
629  protected $ItemsPerPage;
630  protected $ItemTypes;
632  protected $ReverseSortFlags;
633  protected $SortFields;
634  protected $StartingIndexes;
635 
637  protected static $DefaultSortField = "R";
638 
643  protected function FastDistance()
644  {
645  return floor($this->ItemCounts[$this->CurrentItemType] / 5)
646  - (floor($this->ItemCounts[$this->CurrentItemType] / 5)
647  % $this->ItemsPerPage[$this->CurrentItemType]);
648  }
649 
655  protected function GetLinkWithStartingIndex($StartingIndex)
656  {
657  # temporarily swap in supplied starting index
658  $SavedStartingIndex = $this->StartingIndexes[$this->CurrentItemType];
659  $this->StartingIndexes[$this->CurrentItemType] = $StartingIndex;
660 
661  # get link with parameters
662  $Link = $this->CurrentBaseLink.$this->UrlParameterString();
663 
664  # restore starting index
665  $this->StartingIndexes[$this->CurrentItemType] = $SavedStartingIndex;
666 
667  # return link to caller
668  return $Link;
669  }
670 
677  protected function IsValidField($Field, $ItemType)
678  {
679  # default field is assumed to always be valid
680  if ($Field === self::$DefaultSortField)
681  {
682  return TRUE;
683  }
684 
685  # fields are assumed to be always valid for no item type
686  if ($ItemType === self::NO_ITEM_TYPE)
687  {
688  return TRUE;
689  }
690 
691  # load metadata schema to check against (if not already loaded)
692  static $Schemas;
693  if (!isset($Schemas[$ItemType]))
694  {
695  $Schemas[$ItemType] = new MetadataSchema($ItemType);
696  }
697 
698  # report to caller whether field exists for this schema
699  return $Schemas[$ItemType]->FieldExists($Field);
700  }
701 }
702 
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.
ItemCount($ItemCounts)
Get/set count of items in search results.
ShowFastReverseButton()
Report whether fast reverse button should be displayed.
IsValidField($Field, $ItemType)
Check whether specified field looks valid for specified item type.
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.
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.