ReverseChronologicalPager.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /**
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. * http://www.gnu.org/copyleft/gpl.html
  17. *
  18. * @file
  19. * @ingroup Pager
  20. */
  21. use Wikimedia\Timestamp\TimestampException;
  22. /**
  23. * Efficient paging for SQL queries.
  24. * IndexPager with a formatted navigation bar.
  25. * @ingroup Pager
  26. */
  27. abstract class ReverseChronologicalPager extends IndexPager {
  28. /** @var bool */
  29. public $mDefaultDirection = IndexPager::DIR_DESCENDING;
  30. /** @var int */
  31. public $mYear;
  32. /** @var int */
  33. public $mMonth;
  34. /** @var int */
  35. public $mDay;
  36. public function getNavigationBar() {
  37. if ( !$this->isNavigationBarShown() ) {
  38. return '';
  39. }
  40. if ( isset( $this->mNavigationBar ) ) {
  41. return $this->mNavigationBar;
  42. }
  43. $linkTexts = [
  44. 'prev' => $this->msg( 'pager-newer-n' )->numParams( $this->mLimit )->escaped(),
  45. 'next' => $this->msg( 'pager-older-n' )->numParams( $this->mLimit )->escaped(),
  46. 'first' => $this->msg( 'histlast' )->escaped(),
  47. 'last' => $this->msg( 'histfirst' )->escaped()
  48. ];
  49. $pagingLinks = $this->getPagingLinks( $linkTexts );
  50. $limitLinks = $this->getLimitLinks();
  51. $limits = $this->getLanguage()->pipeList( $limitLinks );
  52. $firstLastLinks = $this->msg( 'parentheses' )->rawParams( "{$pagingLinks['first']}" .
  53. $this->msg( 'pipe-separator' )->escaped() .
  54. "{$pagingLinks['last']}" )->escaped();
  55. $this->mNavigationBar = $firstLastLinks . ' ' .
  56. $this->msg( 'viewprevnext' )->rawParams(
  57. $pagingLinks['prev'], $pagingLinks['next'], $limits )->escaped();
  58. return $this->mNavigationBar;
  59. }
  60. /**
  61. * Set and return the mOffset timestamp such that we can get all revisions with
  62. * a timestamp up to the specified parameters.
  63. *
  64. * @param int $year Year up to which we want revisions
  65. * @param int $month Month up to which we want revisions
  66. * @param int $day [optional] Day up to which we want revisions. Default is end of month.
  67. * @return string|null Timestamp or null if year and month are false/invalid
  68. */
  69. public function getDateCond( $year, $month, $day = -1 ) {
  70. $year = (int)$year;
  71. $month = (int)$month;
  72. $day = (int)$day;
  73. // Basic validity checks for year and month
  74. // If year and month are invalid, don't update the mOffset
  75. if ( $year <= 0 && ( $month <= 0 || $month >= 13 ) ) {
  76. return null;
  77. }
  78. $timestamp = self::getOffsetDate( $year, $month, $day );
  79. try {
  80. // The timestamp used for DB queries is at midnight of the *next* day after the selected date.
  81. $selectedDate = new DateTime( $timestamp->getTimestamp( TS_ISO_8601 ) );
  82. $selectedDate = $selectedDate->modify( '-1 day' );
  83. $this->mYear = (int)$selectedDate->format( 'Y' );
  84. $this->mMonth = (int)$selectedDate->format( 'm' );
  85. $this->mDay = (int)$selectedDate->format( 'd' );
  86. $this->mOffset = $this->mDb->timestamp( $timestamp->getTimestamp() );
  87. } catch ( TimestampException $e ) {
  88. // Invalid user provided timestamp (T149257)
  89. return null;
  90. }
  91. return $this->mOffset;
  92. }
  93. /**
  94. * Core logic of determining the mOffset timestamp such that we can get all items with
  95. * a timestamp up to the specified parameters. Given parameters for a day up to which to get
  96. * items, this function finds the timestamp of the day just after the end of the range for use
  97. * in an database strict inequality filter.
  98. *
  99. * This is separate from getDateCond so we can use this logic in other places, such as in
  100. * RangeChronologicalPager, where this function is used to convert year/month/day filter options
  101. * into a timestamp.
  102. *
  103. * @param int $year Year up to which we want revisions
  104. * @param int $month Month up to which we want revisions
  105. * @param int $day [optional] Day up to which we want revisions. Default is end of month.
  106. * @return MWTimestamp Timestamp or null if year and month are false/invalid
  107. */
  108. public static function getOffsetDate( $year, $month, $day = -1 ) {
  109. // Given an optional year, month, and day, we need to generate a timestamp
  110. // to use as "WHERE rev_timestamp <= result"
  111. // Examples: year = 2006 equals < 20070101 (+000000)
  112. // year=2005, month=1 equals < 20050201
  113. // year=2005, month=12 equals < 20060101
  114. // year=2005, month=12, day=5 equals < 20051206
  115. if ( $year <= 0 ) {
  116. // If no year given, assume the current one
  117. $timestamp = MWTimestamp::getInstance();
  118. $year = $timestamp->format( 'Y' );
  119. // If this month hasn't happened yet this year, go back to last year's month
  120. if ( $month > $timestamp->format( 'n' ) ) {
  121. $year--;
  122. }
  123. }
  124. if ( $month && $month > 0 && $month < 13 ) {
  125. // Day validity check after we have month and year checked
  126. $day = checkdate( $month, $day, $year ) ? $day : false;
  127. if ( $day && $day > 0 ) {
  128. // If we have a day, we want up to the day immediately afterward
  129. $day++;
  130. // Did we overflow the current month?
  131. if ( !checkdate( $month, $day, $year ) ) {
  132. $day = 1;
  133. $month++;
  134. }
  135. } else {
  136. // If no day, assume beginning of next month
  137. $day = 1;
  138. $month++;
  139. }
  140. // Did we overflow the current year?
  141. if ( $month > 12 ) {
  142. $month = 1;
  143. $year++;
  144. }
  145. } else {
  146. // No month implies we want up to the end of the year in question
  147. $month = 1;
  148. $day = 1;
  149. $year++;
  150. }
  151. // Y2K38 bug
  152. if ( $year > 2032 ) {
  153. $year = 2032;
  154. }
  155. $ymd = (int)sprintf( "%04d%02d%02d", $year, $month, $day );
  156. if ( $ymd > 20320101 ) {
  157. $ymd = 20320101;
  158. }
  159. return MWTimestamp::getInstance( "${ymd}000000" );
  160. }
  161. }