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