MediaWiki 1.41.2
ProtectedPagesPager.php
Go to the documentation of this file.
1<?php
22namespace MediaWiki\Pager;
23
26use LogPage;
34use MWException;
35use UserCache;
37
39
40 public $mConds;
41 private $type;
42 private $level;
44 private $namespace;
45 private $sizetype;
47 private $size;
48 private $indefonly;
49 private $cascadeonly;
50 private $noredirect;
51
52 private CommentStore $commentStore;
53 private LinkBatchFactory $linkBatchFactory;
54 private UserCache $userCache;
55 private RowCommentFormatter $rowCommentFormatter;
56
58 private $formattedComments = [];
59
78 public function __construct(
79 IContextSource $context,
80 CommentStore $commentStore,
81 LinkBatchFactory $linkBatchFactory,
82 LinkRenderer $linkRenderer,
83 IConnectionProvider $dbProvider,
84 RowCommentFormatter $rowCommentFormatter,
85 UserCache $userCache,
86 $conds,
87 $type,
88 $level,
89 $namespace,
90 $sizetype,
91 $size,
92 $indefonly,
93 $cascadeonly,
94 $noredirect
95 ) {
96 // Set database before parent constructor to avoid setting it there with wfGetDB
97 $this->mDb = $dbProvider->getReplicaDatabase();
98 parent::__construct( $context, $linkRenderer );
99 $this->commentStore = $commentStore;
100 $this->linkBatchFactory = $linkBatchFactory;
101 $this->rowCommentFormatter = $rowCommentFormatter;
102 $this->userCache = $userCache;
103 $this->mConds = $conds;
104 $this->type = $type ?: 'edit';
105 $this->level = $level;
106 $this->namespace = $namespace;
107 $this->sizetype = $sizetype;
108 $this->size = intval( $size );
109 $this->indefonly = (bool)$indefonly;
110 $this->cascadeonly = (bool)$cascadeonly;
111 $this->noredirect = (bool)$noredirect;
112 }
113
114 public function preprocessResults( $result ) {
115 # Do a link batch query
116 $lb = $this->linkBatchFactory->newLinkBatch();
117 $userids = [];
118
119 foreach ( $result as $row ) {
120 $lb->add( $row->page_namespace, $row->page_title );
121 if ( $row->actor_user !== null ) {
122 $userids[] = $row->actor_user;
123 }
124 }
125
126 // fill LinkBatch with user page and user talk
127 if ( count( $userids ) ) {
128 $this->userCache->doQuery( $userids, [], __METHOD__ );
129 foreach ( $userids as $userid ) {
130 $name = $this->userCache->getProp( $userid, 'name' );
131 if ( $name !== false ) {
132 $lb->add( NS_USER, $name );
133 $lb->add( NS_USER_TALK, $name );
134 }
135 }
136 }
137
138 $lb->execute();
139
140 // Format the comments
141 $this->formattedComments = $this->rowCommentFormatter->formatRows( $result, 'log_comment' );
142 }
143
144 protected function getFieldNames() {
145 static $headers = null;
146
147 if ( $headers == [] ) {
148 $headers = [
149 'log_timestamp' => 'protectedpages-timestamp',
150 'pr_page' => 'protectedpages-page',
151 'pr_expiry' => 'protectedpages-expiry',
152 'actor_user' => 'protectedpages-performer',
153 'pr_params' => 'protectedpages-params',
154 'log_comment' => 'protectedpages-reason',
155 ];
156 foreach ( $headers as $key => $val ) {
157 $headers[$key] = $this->msg( $val )->text();
158 }
159 }
160
161 return $headers;
162 }
163
170 public function formatValue( $field, $value ) {
172 $row = $this->mCurrentRow;
173 $linkRenderer = $this->getLinkRenderer();
174
175 switch ( $field ) {
176 case 'log_timestamp':
177 // when timestamp is null, this is a old protection row
178 if ( $value === null ) {
179 $formatted = Html::rawElement(
180 'span',
181 [ 'class' => 'mw-protectedpages-unknown' ],
182 $this->msg( 'protectedpages-unknown-timestamp' )->escaped()
183 );
184 } else {
185 $formatted = htmlspecialchars( $this->getLanguage()->userTimeAndDate(
186 $value, $this->getUser() ) );
187 }
188 break;
189
190 case 'pr_page':
191 $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
192 if ( !$title ) {
193 $formatted = Html::element(
194 'span',
195 [ 'class' => 'mw-invalidtitle' ],
196 Linker::getInvalidTitleDescription(
197 $this->getContext(),
198 $row->page_namespace,
199 $row->page_title
200 )
201 );
202 } else {
203 $formatted = $linkRenderer->makeLink( $title );
204 }
205 if ( $row->page_len !== null ) {
206 $formatted .= $this->getLanguage()->getDirMark() .
207 ' ' . Html::rawElement(
208 'span',
209 [ 'class' => 'mw-protectedpages-length' ],
210 Linker::formatRevisionSize( $row->page_len )
211 );
212 }
213 break;
214
215 case 'pr_expiry':
216 $formatted = htmlspecialchars( $this->getLanguage()->formatExpiry(
217 $value, /* User preference timezone */true, 'infinity', $this->getUser() ) );
218 $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
219 if ( $title && $this->getAuthority()->isAllowed( 'protect' ) ) {
220 $changeProtection = $linkRenderer->makeKnownLink(
221 $title,
222 $this->msg( 'protect_change' )->text(),
223 [],
224 [ 'action' => 'unprotect' ]
225 );
226 $formatted .= ' ' . Html::rawElement(
227 'span',
228 [ 'class' => 'mw-protectedpages-actions' ],
229 $this->msg( 'parentheses' )->rawParams( $changeProtection )->escaped()
230 );
231 }
232 break;
233
234 case 'actor_user':
235 // when timestamp is null, this is a old protection row
236 if ( $row->log_timestamp === null ) {
237 $formatted = Html::rawElement(
238 'span',
239 [ 'class' => 'mw-protectedpages-unknown' ],
240 $this->msg( 'protectedpages-unknown-performer' )->escaped()
241 );
242 } else {
243 $username = $row->actor_name;
244 if ( LogEventsList::userCanBitfield(
245 $row->log_deleted,
246 LogPage::DELETED_USER,
247 $this->getAuthority()
248 ) ) {
249 $formatted = Linker::userLink( (int)$value, $username )
250 . Linker::userToolLinks( (int)$value, $username );
251 } else {
252 $formatted = $this->msg( 'rev-deleted-user' )->escaped();
253 }
254 if ( LogEventsList::isDeleted( $row, LogPage::DELETED_USER ) ) {
255 $formatted = '<span class="history-deleted">' . $formatted . '</span>';
256 }
257 }
258 break;
259
260 case 'pr_params':
261 $params = [];
262 // Messages: restriction-level-sysop, restriction-level-autoconfirmed
263 $params[] = $this->msg( 'restriction-level-' . $row->pr_level )->escaped();
264 if ( $row->pr_cascade ) {
265 $params[] = $this->msg( 'protect-summary-cascade' )->escaped();
266 }
267 $formatted = $this->getLanguage()->commaList( $params );
268 break;
269
270 case 'log_comment':
271 // when timestamp is null, this is an old protection row
272 if ( $row->log_timestamp === null ) {
273 $formatted = Html::rawElement(
274 'span',
275 [ 'class' => 'mw-protectedpages-unknown' ],
276 $this->msg( 'protectedpages-unknown-reason' )->escaped()
277 );
278 } else {
279 if ( LogEventsList::userCanBitfield(
280 $row->log_deleted,
281 LogPage::DELETED_COMMENT,
282 $this->getAuthority()
283 ) ) {
284 $formatted = $this->formattedComments[$this->getResultOffset()];
285 } else {
286 $formatted = $this->msg( 'rev-deleted-comment' )->escaped();
287 }
288 if ( LogEventsList::isDeleted( $row, LogPage::DELETED_COMMENT ) ) {
289 $formatted = '<span class="history-deleted">' . $formatted . '</span>';
290 }
291 }
292 break;
293
294 default:
295 throw new MWException( "Unknown field '$field'" );
296 }
297
298 return $formatted;
299 }
300
301 public function getQueryInfo() {
302 $dbr = $this->getDatabase();
303 $conds = $this->mConds;
304 $conds[] = 'pr_expiry > ' . $dbr->addQuotes( $dbr->timestamp() ) .
305 ' OR pr_expiry IS NULL';
306 $conds[] = 'page_id=pr_page';
307 $conds[] = 'pr_type=' . $dbr->addQuotes( $this->type );
308
309 if ( $this->sizetype == 'min' ) {
310 $conds[] = 'page_len>=' . $this->size;
311 } elseif ( $this->sizetype == 'max' ) {
312 $conds[] = 'page_len<=' . $this->size;
313 }
314
315 if ( $this->indefonly ) {
316 $conds['pr_expiry'] = [ $dbr->getInfinity(), null ];
317 }
318 if ( $this->cascadeonly ) {
319 $conds[] = 'pr_cascade = 1';
320 }
321 if ( $this->noredirect ) {
322 $conds[] = 'page_is_redirect = 0';
323 }
324
325 if ( $this->level ) {
326 $conds[] = 'pr_level=' . $dbr->addQuotes( $this->level );
327 }
328 if ( $this->namespace !== null ) {
329 $conds[] = 'page_namespace=' . $dbr->addQuotes( $this->namespace );
330 }
331
332 $commentQuery = $this->commentStore->getJoin( 'log_comment' );
333
334 return [
335 'tables' => [
336 'page', 'page_restrictions', 'log_search',
337 'logparen' => [ 'logging', 'actor' ] + $commentQuery['tables'],
338 ],
339 'fields' => [
340 'pr_id',
341 'page_namespace',
342 'page_title',
343 'page_len',
344 'pr_type',
345 'pr_level',
346 'pr_expiry',
347 'pr_cascade',
348 'log_timestamp',
349 'log_deleted',
350 'actor_name',
351 'actor_user'
352 ] + $commentQuery['fields'],
353 'conds' => $conds,
354 'join_conds' => [
355 'log_search' => [
356 'LEFT JOIN', [
357 'ls_field' => 'pr_id', 'ls_value = ' . $dbr->buildStringCast( 'pr_id' )
358 ]
359 ],
360 'logparen' => [
361 'LEFT JOIN', [
362 'ls_log_id = log_id'
363 ]
364 ],
365 'actor' => [
366 'JOIN', [
367 'actor_id=log_actor'
368 ]
369 ]
370 ] + $commentQuery['joins']
371 ];
372 }
373
374 protected function getTableClass() {
375 return parent::getTableClass() . ' mw-protectedpages';
376 }
377
378 public function getIndexField() {
379 return 'pr_id';
380 }
381
382 public function getDefaultSort() {
383 return 'pr_id';
384 }
385
386 protected function isFieldSortable( $field ) {
387 // no index for sorting exists
388 return false;
389 }
390}
391
396class_alias( ProtectedPagesPager::class, 'ProtectedPagesPager' );
const NS_USER
Definition Defines.php:66
const NS_USER_TALK
Definition Defines.php:67
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
getContext()
Get the base IContextSource object.
Class to simplify the use of log pages.
Definition LogPage.php:43
MediaWiki exception.
This is basically a CommentFormatter with a CommentStore dependency, allowing it to retrieve comment ...
Handle database storage of comments such as edit summaries and log reasons.
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
Class that generates HTML for internal links.
Some internal bits split of from Skin.php.
Definition Linker.php:65
getDatabase()
Get the Database object in use.
getDefaultSort()
The database field name used as a default sort order.
preprocessResults( $result)
Pre-process results; useful for performing batch existence checks, etc.
getQueryInfo()
Provides all parameters needed for the main paged query.
getTableClass()
TablePager relies on mw-datatable for styling, see T214208.
isFieldSortable( $field)
Return true if the named field should be sortable by the UI, false otherwise.
__construct(IContextSource $context, CommentStore $commentStore, LinkBatchFactory $linkBatchFactory, LinkRenderer $linkRenderer, IConnectionProvider $dbProvider, RowCommentFormatter $rowCommentFormatter, UserCache $userCache, $conds, $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect)
getFieldNames()
An array mapping database field names to a textual description of the field name, for use in the tabl...
getIndexField()
Returns the name of the index field.If the pager supports multiple orders, it may return an array of ...
Table-based display with a user-selectable sort order.
Represents a title within MediaWiki.
Definition Title.php:76
Interface for objects which can provide a MediaWiki context on request.
Provide primary and replica IDatabase connections.
getReplicaDatabase( $domain=false, $group=null)
Get connection to a replica database.