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  && (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 
457  # ---- TEST/LINK METHODS ------------------------------------------------
458  # (useful if constructing your own interface rather than using PrintControls()
459 
464  public function SetItemType($ItemType)
465  {
466  $this->CurrentItemType = $ItemType;
467  }
468 
473  public function SetBaseLink($BaseLink)
474  {
475  $this->CurrentBaseLink = $BaseLink;
476  }
477 
485  public function ShowAnyForwardButtons()
486  {
487  return (($this->StartingIndexes[$this->CurrentItemType]
488  + $this->ItemsPerPage[$this->CurrentItemType])
489  < ($this->LastPageStartIndexes[$this->CurrentItemType] + 1))
490  ? TRUE : FALSE;
491  }
492 
500  public function ShowAnyReverseButtons()
501  {
502  return ($this->StartingIndexes[$this->CurrentItemType] > 0)
503  ? TRUE : FALSE;
504  }
505 
512  public function ShowForwardButton()
513  {
514  return ($this->StartingIndexes[$this->CurrentItemType]
515  < ($this->LastPageStartIndexes[$this->CurrentItemType]
516  - $this->ItemsPerPage[$this->CurrentItemType]))
517  ? TRUE : FALSE;
518  }
519 
526  public function ShowReverseButton()
527  {
528  return (($this->StartingIndexes[$this->CurrentItemType] + 1)
529  >= ($this->ItemsPerPage[$this->CurrentItemType] * 2))
530  ? TRUE : FALSE;
531  }
532 
540  public function ShowFastForwardButton()
541  {
542  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
543  && (($this->StartingIndexes[$this->CurrentItemType]
544  + $this->FastDistance())
545  < $this->LastPageStartIndexes[$this->CurrentItemType]))
546  ? TRUE : FALSE;
547  }
548 
556  public function ShowFastReverseButton()
557  {
558  return (($this->FastDistance() > $this->ItemsPerPage[$this->CurrentItemType])
559  && ($this->StartingIndexes[$this->CurrentItemType]
560  >= $this->FastDistance()))
561  ? TRUE : FALSE;
562  }
563 
568  public function ForwardLink()
569  {
570  return $this->GetLinkWithStartingIndex(
571  min($this->LastPageStartIndexes[$this->CurrentItemType],
572  ($this->StartingIndexes[$this->CurrentItemType]
573  + $this->ItemsPerPage[$this->CurrentItemType])));
574  }
575 
580  public function ReverseLink()
581  {
582  return $this->GetLinkWithStartingIndex(
583  max(0, ($this->StartingIndexes[$this->CurrentItemType]
584  - $this->ItemsPerPage[$this->CurrentItemType])));
585  }
586 
591  public function FastForwardLink()
592  {
593  return $this->GetLinkWithStartingIndex(
594  min($this->LastPageStartIndexes[$this->CurrentItemType],
595  ($this->StartingIndexes[$this->CurrentItemType]
596  + $this->FastDistance())));
597  }
598 
603  public function FastReverseLink()
604  {
605  return $this->GetLinkWithStartingIndex(
606  max(0, ($this->StartingIndexes[$this->CurrentItemType]
607  - $this->FastDistance())));
608  }
609 
614  public function GoToEndLink()
615  {
616  return $this->GetLinkWithStartingIndex(
617  $this->LastPageStartIndexes[$this->CurrentItemType]);
618  }
619 
624  public function GoToStartLink()
625  {
626  return $this->GetLinkWithStartingIndex(0);
627  }
628 
629 
630  # ---- PRIVATE INTERFACE -------------------------------------------------
631 
632  protected $ActiveTab;
633  protected $CurrentBaseLink;
634  protected $CurrentItemType;
635  protected $ItemCounts;
636  protected $ItemsPerPage;
637  protected $ItemTypes;
639  protected $ReverseSortFlags;
640  protected $SortFields;
641  protected $StartingIndexes;
642 
644  protected static $DefaultSortField = "R";
645 
650  protected function FastDistance()
651  {
652  return floor($this->ItemCounts[$this->CurrentItemType] / 5)
653  - (floor($this->ItemCounts[$this->CurrentItemType] / 5)
654  % $this->ItemsPerPage[$this->CurrentItemType]);
655  }
656 
662  protected function GetLinkWithStartingIndex($StartingIndex)
663  {
664  # temporarily swap in supplied starting index
665  $SavedStartingIndex = $this->StartingIndexes[$this->CurrentItemType];
666  $this->StartingIndexes[$this->CurrentItemType] = $StartingIndex;
667 
668  # get link with parameters
669  $Link = $this->CurrentBaseLink.$this->UrlParameterString();
670 
671  # restore starting index
672  $this->StartingIndexes[$this->CurrentItemType] = $SavedStartingIndex;
673 
674  # return link to caller
675  return $Link;
676  }
677 
684  protected function IsValidField($Field, $ItemType)
685  {
686  # default field is assumed to always be valid
687  if ($Field === self::$DefaultSortField)
688  {
689  return TRUE;
690  }
691 
692  # fields are assumed to be always valid for no item type
693  if ($ItemType === self::NO_ITEM_TYPE)
694  {
695  return TRUE;
696  }
697 
698  # load metadata schema to check against (if not already loaded)
699  static $Schemas;
700  if (!isset($Schemas[$ItemType]))
701  {
702  $Schemas[$ItemType] = new MetadataSchema($ItemType);
703  }
704 
705  # report to caller whether field exists for this schema
706  return $Schemas[$ItemType]->FieldExists($Field);
707  }
708 }
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.
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.