MediaWiki  master
ImageHistoryPseudoPager.php
Go to the documentation of this file.
1 <?php
23 use Wikimedia\Timestamp\TimestampException;
24 
26  protected $preventClickjacking = false;
27 
31  protected $mImg;
32 
36  protected $mTitle;
37 
42  public $mImagePage;
43 
48  public $mHist;
49 
54  public $mRange;
55 
58 
63  public function __construct( $imagePage, LinkBatchFactory $linkBatchFactory = null ) {
64  parent::__construct( $imagePage->getContext() );
65  $this->mImagePage = $imagePage;
66  $this->mTitle = $imagePage->getTitle()->createFragmentTarget( 'filehistory' );
67  $this->mImg = null;
68  $this->mHist = [];
69  $this->mRange = [ 0, 0 ]; // display range
70 
71  // Only display 10 revisions at once by default, otherwise the list is overwhelming
72  $this->mLimitsShown = array_merge( [ 10 ], $this->mLimitsShown );
73  $this->mDefaultLimit = 10;
74  list( $this->mLimit, /* $offset */ ) =
75  $this->mRequest->getLimitOffsetForUser(
76  $this->getUser(),
77  $this->mDefaultLimit,
78  ''
79  );
80  $this->linkBatchFactory = $linkBatchFactory ?? MediaWikiServices::getInstance()->getLinkBatchFactory();
81  }
82 
86  public function getTitle() {
87  return $this->mTitle;
88  }
89 
90  public function getQueryInfo() {
91  return [];
92  }
93 
97  public function getIndexField() {
98  return '';
99  }
100 
105  public function formatRow( $row ) {
106  return '';
107  }
108 
112  public function getBody() {
113  $s = '';
114  $this->doQuery();
115  if ( count( $this->mHist ) ) {
116  if ( $this->mImg->isLocal() ) {
117  // Do a batch existence check for user pages and talkpages.
118  $linkBatch = $this->linkBatchFactory->newLinkBatch();
119  for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
120  $file = $this->mHist[$i];
121  $uploader = $file->getUploader( File::FOR_THIS_USER, $this->getAuthority() );
122  if ( $uploader ) {
123  $linkBatch->add( NS_USER, $uploader->getName() );
124  $linkBatch->add( NS_USER_TALK, $uploader->getName() );
125  }
126  }
127  $linkBatch->execute();
128  }
129 
130  // Batch-format comments
131  $comments = [];
132  for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
133  $file = $this->mHist[$i];
134  $comments[$i] = $file->getDescription(
136  $this->getUser()
137  ) ?: '';
138  }
139  $formattedComments = MediaWikiServices::getInstance()
140  ->getCommentFormatter()
141  ->formatStrings( $comments, $this->getTitle() );
142 
143  $list = new ImageHistoryList( $this->mImagePage );
144  # Generate prev/next links
145  $navLink = $this->getNavigationBar();
146  $s = $list->beginImageHistoryList( $navLink );
147  // Skip rows there just for paging links
148  for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
149  $file = $this->mHist[$i];
150  $s .= $list->imageHistoryLine( !$file->isOld(), $file, $formattedComments[$i] );
151  }
152  $s .= $list->endImageHistoryList( $navLink );
153 
154  if ( $list->getPreventClickjacking() ) {
155  $this->setPreventClickjacking( true );
156  }
157  }
158  return $s;
159  }
160 
161  public function doQuery() {
162  if ( $this->mQueryDone ) {
163  return;
164  }
165  $this->mImg = $this->mImagePage->getPage()->getFile(); // ensure loading
166  if ( !$this->mImg->exists() ) {
167  return;
168  }
169  // Make sure the date (probably from user input) is valid; if not, drop it.
170  if ( $this->mOffset !== null ) {
171  try {
172  $sadlyWeCannotPassThisTimestampDownTheStack = $this->mDb->timestamp( $this->mOffset );
173  } catch ( TimestampException $e ) {
174  $this->mOffset = null;
175  }
176  }
177  $queryLimit = $this->mLimit + 1; // limit plus extra row
178  if ( $this->mIsBackwards ) {
179  // Fetch the file history
180  $this->mHist = $this->mImg->getHistory( $queryLimit, null, $this->mOffset, false );
181  // The current rev may not meet the offset/limit
182  $numRows = count( $this->mHist );
183  if ( $numRows <= $this->mLimit && $this->mImg->getTimestamp() > $this->mOffset ) {
184  $this->mHist = array_merge( [ $this->mImg ], $this->mHist );
185  }
186  } else {
187  // The current rev may not meet the offset
188  if ( !$this->mOffset || $this->mImg->getTimestamp() < $this->mOffset ) {
189  $this->mHist[] = $this->mImg;
190  }
191  // Old image versions (fetch extra row for nav links)
192  $oiLimit = count( $this->mHist ) ? $this->mLimit : $this->mLimit + 1;
193  // Fetch the file history
194  $this->mHist = array_merge( $this->mHist,
195  $this->mImg->getHistory( $oiLimit, $this->mOffset, null, false ) );
196  }
197  $numRows = count( $this->mHist ); // Total number of query results
198  if ( $numRows ) {
199  # Index value of top item in the list
200  $firstIndex = $this->mIsBackwards ?
201  [ $this->mHist[$numRows - 1]->getTimestamp() ] : [ $this->mHist[0]->getTimestamp() ];
202  # Discard the extra result row if there is one
203  if ( $numRows > $this->mLimit && $numRows > 1 ) {
204  if ( $this->mIsBackwards ) {
205  # Index value of item past the index
206  $this->mPastTheEndIndex = [ $this->mHist[0]->getTimestamp() ];
207  # Index value of bottom item in the list
208  $lastIndex = [ $this->mHist[1]->getTimestamp() ];
209  # Display range
210  $this->mRange = [ 1, $numRows - 1 ];
211  } else {
212  # Index value of item past the index
213  $this->mPastTheEndIndex = [ $this->mHist[$numRows - 1]->getTimestamp() ];
214  # Index value of bottom item in the list
215  $lastIndex = [ $this->mHist[$numRows - 2]->getTimestamp() ];
216  # Display range
217  $this->mRange = [ 0, $numRows - 2 ];
218  }
219  } else {
220  # Setting indexes to an empty array means that they will be
221  # omitted if they would otherwise appear in URLs. It just so
222  # happens that this is the right thing to do in the standard
223  # UI, in all the relevant cases.
224  $this->mPastTheEndIndex = [];
225  # Index value of bottom item in the list
226  $lastIndex = $this->mIsBackwards ?
227  [ $this->mHist[0]->getTimestamp() ] : [ $this->mHist[$numRows - 1]->getTimestamp() ];
228  # Display range
229  $this->mRange = [ 0, $numRows - 1 ];
230  }
231  } else {
232  $firstIndex = [];
233  $lastIndex = [];
234  $this->mPastTheEndIndex = [];
235  }
236  if ( $this->mIsBackwards ) {
237  $this->mIsFirst = ( $numRows < $queryLimit );
238  $this->mIsLast = ( $this->mOffset == '' );
239  $this->mLastShown = $firstIndex;
240  $this->mFirstShown = $lastIndex;
241  } else {
242  $this->mIsFirst = ( $this->mOffset == '' );
243  $this->mIsLast = ( $numRows < $queryLimit );
244  $this->mLastShown = $lastIndex;
245  $this->mFirstShown = $firstIndex;
246  }
247  $this->mQueryDone = true;
248  }
249 
254  protected function preventClickjacking( $enable = true ) {
255  $this->preventClickjacking = $enable;
256  }
257 
262  protected function setPreventClickjacking( bool $enable ) {
263  $this->preventClickjacking = $enable;
264  }
265 
269  public function getPreventClickjacking() {
271  }
272 
273 }
const NS_USER
Definition: Defines.php:66
const NS_USER_TALK
Definition: Defines.php:67
const FOR_THIS_USER
Definition: File.php:89
Builds the image revision log shown on image pages.
__construct( $imagePage, LinkBatchFactory $linkBatchFactory=null)
doQuery()
Do the query, using information from the object context.
getQueryInfo()
Provides all parameters needed for the main paged query.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Efficient paging for SQL queries.
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42