MediaWiki  1.28.1
WatchedItemQueryService.php
Go to the documentation of this file.
1 <?php
2 
5 
17 
18  const DIR_OLDER = 'older';
19  const DIR_NEWER = 'newer';
20 
21  const INCLUDE_FLAGS = 'flags';
22  const INCLUDE_USER = 'user';
23  const INCLUDE_USER_ID = 'userid';
24  const INCLUDE_COMMENT = 'comment';
25  const INCLUDE_PATROL_INFO = 'patrol';
26  const INCLUDE_SIZES = 'sizes';
27  const INCLUDE_LOG_INFO = 'loginfo';
28 
29  // FILTER_* constants are part of public API (are used in ApiQueryWatchlist and
30  // ApiQueryWatchlistRaw classes) and should not be changed.
31  // Changing values of those constants will result in a breaking change in the API
32  const FILTER_MINOR = 'minor';
33  const FILTER_NOT_MINOR = '!minor';
34  const FILTER_BOT = 'bot';
35  const FILTER_NOT_BOT = '!bot';
36  const FILTER_ANON = 'anon';
37  const FILTER_NOT_ANON = '!anon';
38  const FILTER_PATROLLED = 'patrolled';
39  const FILTER_NOT_PATROLLED = '!patrolled';
40  const FILTER_UNREAD = 'unread';
41  const FILTER_NOT_UNREAD = '!unread';
42  const FILTER_CHANGED = 'changed';
43  const FILTER_NOT_CHANGED = '!changed';
44 
45  const SORT_ASC = 'ASC';
46  const SORT_DESC = 'DESC';
47 
51  private $loadBalancer;
52 
53  public function __construct( LoadBalancer $loadBalancer ) {
54  $this->loadBalancer = $loadBalancer;
55  }
56 
61  private function getConnection() {
62  return $this->loadBalancer->getConnectionRef( DB_REPLICA, [ 'watchlist' ] );
63  }
64 
111  $options += [
112  'includeFields' => [],
113  'namespaceIds' => [],
114  'filters' => [],
115  'allRevisions' => false,
116  'usedInGenerator' => false
117  ];
118 
119  Assert::parameter(
120  !isset( $options['rcTypes'] )
121  || !array_diff( $options['rcTypes'], [ RC_EDIT, RC_NEW, RC_LOG, RC_EXTERNAL, RC_CATEGORIZE ] ),
122  '$options[\'rcTypes\']',
123  'must be an array containing only: RC_EDIT, RC_NEW, RC_LOG, RC_EXTERNAL and/or RC_CATEGORIZE'
124  );
125  Assert::parameter(
126  !isset( $options['dir'] ) || in_array( $options['dir'], [ self::DIR_OLDER, self::DIR_NEWER ] ),
127  '$options[\'dir\']',
128  'must be DIR_OLDER or DIR_NEWER'
129  );
130  Assert::parameter(
131  !isset( $options['start'] ) && !isset( $options['end'] ) && !isset( $options['startFrom'] )
132  || isset( $options['dir'] ),
133  '$options[\'dir\']',
134  'must be provided when providing any of options: start, end, startFrom'
135  );
136  Assert::parameter(
137  !isset( $options['startFrom'] )
138  || ( is_array( $options['startFrom'] ) && count( $options['startFrom'] ) === 2 ),
139  '$options[\'startFrom\']',
140  'must be a two-element array'
141  );
142  if ( array_key_exists( 'watchlistOwner', $options ) ) {
143  Assert::parameterType(
144  User::class,
145  $options['watchlistOwner'],
146  '$options[\'watchlistOwner\']'
147  );
148  Assert::parameter(
149  isset( $options['watchlistOwnerToken'] ),
150  '$options[\'watchlistOwnerToken\']',
151  'must be provided when providing watchlistOwner option'
152  );
153  }
154 
155  $tables = [ 'recentchanges', 'watchlist' ];
156  if ( !$options['allRevisions'] ) {
157  $tables[] = 'page';
158  }
159 
160  $db = $this->getConnection();
161 
163  $conds = $this->getWatchedItemsWithRCInfoQueryConds( $db, $user, $options );
164  $dbOptions = $this->getWatchedItemsWithRCInfoQueryDbOptions( $options );
165  $joinConds = $this->getWatchedItemsWithRCInfoQueryJoinConds( $options );
166 
167  $res = $db->select(
168  $tables,
169  $fields,
170  $conds,
171  __METHOD__,
172  $dbOptions,
173  $joinConds
174  );
175 
176  $items = [];
177  foreach ( $res as $row ) {
178  $items[] = [
179  new WatchedItem(
180  $user,
181  new TitleValue( (int)$row->rc_namespace, $row->rc_title ),
182  $row->wl_notificationtimestamp
183  ),
184  $this->getRecentChangeFieldsFromRow( $row )
185  ];
186  }
187 
188  return $items;
189  }
190 
210  public function getWatchedItemsForUser( User $user, array $options = [] ) {
211  if ( $user->isAnon() ) {
212  // TODO: should this just return an empty array or rather complain loud at this point
213  // as e.g. ApiBase::getWatchlistUser does?
214  return [];
215  }
216 
217  $options += [ 'namespaceIds' => [] ];
218 
219  Assert::parameter(
220  !isset( $options['sort'] ) || in_array( $options['sort'], [ self::SORT_ASC, self::SORT_DESC ] ),
221  '$options[\'sort\']',
222  'must be SORT_ASC or SORT_DESC'
223  );
224  Assert::parameter(
225  !isset( $options['filter'] ) || in_array(
226  $options['filter'], [ self::FILTER_CHANGED, self::FILTER_NOT_CHANGED ]
227  ),
228  '$options[\'filter\']',
229  'must be FILTER_CHANGED or FILTER_NOT_CHANGED'
230  );
231  Assert::parameter(
232  !isset( $options['from'] ) && !isset( $options['until'] ) && !isset( $options['startFrom'] )
233  || isset( $options['sort'] ),
234  '$options[\'sort\']',
235  'must be provided if any of "from", "until", "startFrom" options is provided'
236  );
237 
238  $db = $this->getConnection();
239 
240  $conds = $this->getWatchedItemsForUserQueryConds( $db, $user, $options );
241  $dbOptions = $this->getWatchedItemsForUserQueryDbOptions( $options );
242 
243  $res = $db->select(
244  'watchlist',
245  [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
246  $conds,
247  __METHOD__,
248  $dbOptions
249  );
250 
251  $watchedItems = [];
252  foreach ( $res as $row ) {
253  // todo these could all be cached at some point?
254  $watchedItems[] = new WatchedItem(
255  $user,
256  new TitleValue( (int)$row->wl_namespace, $row->wl_title ),
257  $row->wl_notificationtimestamp
258  );
259  }
260 
261  return $watchedItems;
262  }
263 
264  private function getRecentChangeFieldsFromRow( stdClass $row ) {
265  // This can be simplified to single array_filter call filtering by key value,
266  // once we stop supporting PHP 5.5
267  $allFields = get_object_vars( $row );
268  $rcKeys = array_filter(
269  array_keys( $allFields ),
270  function( $key ) {
271  return substr( $key, 0, 3 ) === 'rc_';
272  }
273  );
274  return array_intersect_key( $allFields, array_flip( $rcKeys ) );
275  }
276 
278  $fields = [
279  'rc_id',
280  'rc_namespace',
281  'rc_title',
282  'rc_timestamp',
283  'rc_type',
284  'rc_deleted',
285  'wl_notificationtimestamp'
286  ];
287 
288  $rcIdFields = [
289  'rc_cur_id',
290  'rc_this_oldid',
291  'rc_last_oldid',
292  ];
293  if ( $options['usedInGenerator'] ) {
294  if ( $options['allRevisions'] ) {
295  $rcIdFields = [ 'rc_this_oldid' ];
296  } else {
297  $rcIdFields = [ 'rc_cur_id' ];
298  }
299  }
300  $fields = array_merge( $fields, $rcIdFields );
301 
302  if ( in_array( self::INCLUDE_FLAGS, $options['includeFields'] ) ) {
303  $fields = array_merge( $fields, [ 'rc_type', 'rc_minor', 'rc_bot' ] );
304  }
305  if ( in_array( self::INCLUDE_USER, $options['includeFields'] ) ) {
306  $fields[] = 'rc_user_text';
307  }
308  if ( in_array( self::INCLUDE_USER_ID, $options['includeFields'] ) ) {
309  $fields[] = 'rc_user';
310  }
311  if ( in_array( self::INCLUDE_COMMENT, $options['includeFields'] ) ) {
312  $fields[] = 'rc_comment';
313  }
314  if ( in_array( self::INCLUDE_PATROL_INFO, $options['includeFields'] ) ) {
315  $fields = array_merge( $fields, [ 'rc_patrolled', 'rc_log_type' ] );
316  }
317  if ( in_array( self::INCLUDE_SIZES, $options['includeFields'] ) ) {
318  $fields = array_merge( $fields, [ 'rc_old_len', 'rc_new_len' ] );
319  }
320  if ( in_array( self::INCLUDE_LOG_INFO, $options['includeFields'] ) ) {
321  $fields = array_merge( $fields, [ 'rc_logid', 'rc_log_type', 'rc_log_action', 'rc_params' ] );
322  }
323 
324  return $fields;
325  }
326 
328  IDatabase $db,
329  User $user,
331  ) {
332  $watchlistOwnerId = $this->getWatchlistOwnerId( $user, $options );
333  $conds = [ 'wl_user' => $watchlistOwnerId ];
334 
335  if ( !$options['allRevisions'] ) {
336  $conds[] = $db->makeList(
337  [ 'rc_this_oldid=page_latest', 'rc_type=' . RC_LOG ],
338  LIST_OR
339  );
340  }
341 
342  if ( $options['namespaceIds'] ) {
343  $conds['wl_namespace'] = array_map( 'intval', $options['namespaceIds'] );
344  }
345 
346  if ( array_key_exists( 'rcTypes', $options ) ) {
347  $conds['rc_type'] = array_map( 'intval', $options['rcTypes'] );
348  }
349 
350  $conds = array_merge(
351  $conds,
352  $this->getWatchedItemsWithRCInfoQueryFilterConds( $user, $options )
353  );
354 
355  $conds = array_merge( $conds, $this->getStartEndConds( $db, $options ) );
356 
357  if ( !isset( $options['start'] ) && !isset( $options['end'] ) ) {
358  if ( $db->getType() === 'mysql' ) {
359  // This is an index optimization for mysql
360  $conds[] = "rc_timestamp > ''";
361  }
362  }
363 
364  $conds = array_merge( $conds, $this->getUserRelatedConds( $db, $user, $options ) );
365 
366  $deletedPageLogCond = $this->getExtraDeletedPageLogEntryRelatedCond( $db, $user );
367  if ( $deletedPageLogCond ) {
368  $conds[] = $deletedPageLogCond;
369  }
370 
371  if ( array_key_exists( 'startFrom', $options ) ) {
372  $conds[] = $this->getStartFromConds( $db, $options );
373  }
374 
375  return $conds;
376  }
377 
378  private function getWatchlistOwnerId( User $user, array $options ) {
379  if ( array_key_exists( 'watchlistOwner', $options ) ) {
381  $watchlistOwner = $options['watchlistOwner'];
382  $ownersToken = $watchlistOwner->getOption( 'watchlisttoken' );
383  $token = $options['watchlistOwnerToken'];
384  if ( $ownersToken == '' || !hash_equals( $ownersToken, $token ) ) {
385  throw new UsageException(
386  'Incorrect watchlist token provided -- please set a correct token in Special:Preferences',
387  'bad_wltoken'
388  );
389  }
390  return $watchlistOwner->getId();
391  }
392  return $user->getId();
393  }
394 
396  $conds = [];
397 
398  if ( in_array( self::FILTER_MINOR, $options['filters'] ) ) {
399  $conds[] = 'rc_minor != 0';
400  } elseif ( in_array( self::FILTER_NOT_MINOR, $options['filters'] ) ) {
401  $conds[] = 'rc_minor = 0';
402  }
403 
404  if ( in_array( self::FILTER_BOT, $options['filters'] ) ) {
405  $conds[] = 'rc_bot != 0';
406  } elseif ( in_array( self::FILTER_NOT_BOT, $options['filters'] ) ) {
407  $conds[] = 'rc_bot = 0';
408  }
409 
410  if ( in_array( self::FILTER_ANON, $options['filters'] ) ) {
411  $conds[] = 'rc_user = 0';
412  } elseif ( in_array( self::FILTER_NOT_ANON, $options['filters'] ) ) {
413  $conds[] = 'rc_user != 0';
414  }
415 
416  if ( $user->useRCPatrol() || $user->useNPPatrol() ) {
417  // TODO: not sure if this should simply ignore patrolled filters if user does not have the patrol
418  // right, or maybe rather fail loud at this point, same as e.g. ApiQueryWatchlist does?
419  if ( in_array( self::FILTER_PATROLLED, $options['filters'] ) ) {
420  $conds[] = 'rc_patrolled != 0';
421  } elseif ( in_array( self::FILTER_NOT_PATROLLED, $options['filters'] ) ) {
422  $conds[] = 'rc_patrolled = 0';
423  }
424  }
425 
426  if ( in_array( self::FILTER_UNREAD, $options['filters'] ) ) {
427  $conds[] = 'rc_timestamp >= wl_notificationtimestamp';
428  } elseif ( in_array( self::FILTER_NOT_UNREAD, $options['filters'] ) ) {
429  // TODO: should this be changed to use Database::makeList?
430  $conds[] = 'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp';
431  }
432 
433  return $conds;
434  }
435 
436  private function getStartEndConds( IDatabase $db, array $options ) {
437  if ( !isset( $options['start'] ) && ! isset( $options['end'] ) ) {
438  return [];
439  }
440 
441  $conds = [];
442 
443  if ( isset( $options['start'] ) ) {
444  $after = $options['dir'] === self::DIR_OLDER ? '<=' : '>=';
445  $conds[] = 'rc_timestamp ' . $after . ' ' .
446  $db->addQuotes( $db->timestamp( $options['start'] ) );
447  }
448  if ( isset( $options['end'] ) ) {
449  $before = $options['dir'] === self::DIR_OLDER ? '>=' : '<=';
450  $conds[] = 'rc_timestamp ' . $before . ' ' .
451  $db->addQuotes( $db->timestamp( $options['end'] ) );
452  }
453 
454  return $conds;
455  }
456 
457  private function getUserRelatedConds( IDatabase $db, User $user, array $options ) {
458  if ( !array_key_exists( 'onlyByUser', $options ) && !array_key_exists( 'notByUser', $options ) ) {
459  return [];
460  }
461 
462  $conds = [];
463 
464  if ( array_key_exists( 'onlyByUser', $options ) ) {
465  $conds['rc_user_text'] = $options['onlyByUser'];
466  } elseif ( array_key_exists( 'notByUser', $options ) ) {
467  $conds[] = 'rc_user_text != ' . $db->addQuotes( $options['notByUser'] );
468  }
469 
470  // Avoid brute force searches (bug 17342)
471  $bitmask = 0;
472  if ( !$user->isAllowed( 'deletedhistory' ) ) {
473  $bitmask = Revision::DELETED_USER;
474  } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
476  }
477  if ( $bitmask ) {
478  $conds[] = $db->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask";
479  }
480 
481  return $conds;
482  }
483 
485  // LogPage::DELETED_ACTION hides the affected page, too. So hide those
486  // entirely from the watchlist, or someone could guess the title.
487  $bitmask = 0;
488  if ( !$user->isAllowed( 'deletedhistory' ) ) {
489  $bitmask = LogPage::DELETED_ACTION;
490  } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
492  }
493  if ( $bitmask ) {
494  return $db->makeList( [
495  'rc_type != ' . RC_LOG,
496  $db->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask",
497  ], LIST_OR );
498  }
499  return '';
500  }
501 
502  private function getStartFromConds( IDatabase $db, array $options ) {
503  $op = $options['dir'] === self::DIR_OLDER ? '<' : '>';
504  list( $rcTimestamp, $rcId ) = $options['startFrom'];
505  $rcTimestamp = $db->addQuotes( $db->timestamp( $rcTimestamp ) );
506  $rcId = (int)$rcId;
507  return $db->makeList(
508  [
509  "rc_timestamp $op $rcTimestamp",
510  $db->makeList(
511  [
512  "rc_timestamp = $rcTimestamp",
513  "rc_id $op= $rcId"
514  ],
515  LIST_AND
516  )
517  ],
518  LIST_OR
519  );
520  }
521 
523  $conds = [ 'wl_user' => $user->getId() ];
524  if ( $options['namespaceIds'] ) {
525  $conds['wl_namespace'] = array_map( 'intval', $options['namespaceIds'] );
526  }
527  if ( isset( $options['filter'] ) ) {
528  $filter = $options['filter'];
529  if ( $filter === self::FILTER_CHANGED ) {
530  $conds[] = 'wl_notificationtimestamp IS NOT NULL';
531  } else {
532  $conds[] = 'wl_notificationtimestamp IS NULL';
533  }
534  }
535 
536  if ( isset( $options['from'] ) ) {
537  $op = $options['sort'] === self::SORT_ASC ? '>' : '<';
538  $conds[] = $this->getFromUntilTargetConds( $db, $options['from'], $op );
539  }
540  if ( isset( $options['until'] ) ) {
541  $op = $options['sort'] === self::SORT_ASC ? '<' : '>';
542  $conds[] = $this->getFromUntilTargetConds( $db, $options['until'], $op );
543  }
544  if ( isset( $options['startFrom'] ) ) {
545  $op = $options['sort'] === self::SORT_ASC ? '>' : '<';
546  $conds[] = $this->getFromUntilTargetConds( $db, $options['startFrom'], $op );
547  }
548 
549  return $conds;
550  }
551 
561  private function getFromUntilTargetConds( IDatabase $db, LinkTarget $target, $op ) {
562  return $db->makeList(
563  [
564  "wl_namespace $op " . $target->getNamespace(),
565  $db->makeList(
566  [
567  'wl_namespace = ' . $target->getNamespace(),
568  "wl_title $op= " . $db->addQuotes( $target->getDBkey() )
569  ],
570  LIST_AND
571  )
572  ],
573  LIST_OR
574  );
575  }
576 
578  $dbOptions = [];
579 
580  if ( array_key_exists( 'dir', $options ) ) {
581  $sort = $options['dir'] === self::DIR_OLDER ? ' DESC' : '';
582  $dbOptions['ORDER BY'] = [ 'rc_timestamp' . $sort, 'rc_id' . $sort ];
583  }
584 
585  if ( array_key_exists( 'limit', $options ) ) {
586  $dbOptions['LIMIT'] = (int)$options['limit'];
587  }
588 
589  return $dbOptions;
590  }
591 
593  $dbOptions = [];
594  if ( array_key_exists( 'sort', $options ) ) {
595  $dbOptions['ORDER BY'] = [
596  "wl_namespace {$options['sort']}",
597  "wl_title {$options['sort']}"
598  ];
599  if ( count( $options['namespaceIds'] ) === 1 ) {
600  $dbOptions['ORDER BY'] = "wl_title {$options['sort']}";
601  }
602  }
603  if ( array_key_exists( 'limit', $options ) ) {
604  $dbOptions['LIMIT'] = (int)$options['limit'];
605  }
606  return $dbOptions;
607  }
608 
610  $joinConds = [
611  'watchlist' => [ 'INNER JOIN',
612  [
613  'wl_namespace=rc_namespace',
614  'wl_title=rc_title'
615  ]
616  ]
617  ];
618  if ( !$options['allRevisions'] ) {
619  $joinConds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
620  }
621  return $joinConds;
622  }
623 
624 }
getWatchedItemsWithRCInfoQueryFields(array $options)
getUserRelatedConds(IDatabase $db, User $user, array $options)
const RC_CATEGORIZE
Definition: Defines.php:140
getWatchedItemsForUserQueryConds(IDatabase $db, User $user, array $options)
getWatchedItemsWithRecentChangeInfo(User $user, array $options=[])
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
the array() calling protocol came about after MediaWiki 1.4rc1.
getWatchedItemsForUser(User $user, array $options=[])
For simple listing of user's watchlist items, see WatchedItemStore::getWatchedItemsForUser.
getWatchedItemsForUserQueryDbOptions(array $options)
getWatchedItemsWithRCInfoQueryConds(IDatabase $db, User $user, array $options)
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
getFromUntilTargetConds(IDatabase $db, LinkTarget $target, $op)
Creates a query condition part for getting only items before or after the given link target (while or...
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
getStartEndConds(IDatabase $db, array $options)
isAllowedAny()
Check if user is allowed to access a feature / make an action.
Definition: User.php:3413
getWatchedItemsWithRCInfoQueryDbOptions(array $options)
$sort
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36
getWatchedItemsWithRCInfoQueryJoinConds(array $options)
bitAnd($fieldLeft, $fieldRight)
getExtraDeletedPageLogEntryRelatedCond(IDatabase $db, User $user)
timestamp($ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist & $tables
Definition: hooks.txt:1007
getNamespace()
Get the namespace index.
makeList($a, $mode=self::LIST_COMMA)
Makes an encoded list of strings from an array.
const LIST_AND
Definition: Defines.php:35
isAllowed($action= '')
Internal mechanics of testing a permission.
Definition: User.php:3443
isAnon()
Get whether the user is anonymous.
Definition: User.php:3388
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1046
getWatchedItemsWithRCInfoQueryFilterConds(User $user, array $options)
$res
Definition: database.txt:21
getDBkey()
Get the main part with underscores.
const DELETED_RESTRICTED
Definition: Revision.php:88
Representation of a pair of user and title for watchlist entries.
Definition: WatchedItem.php:32
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
const DELETED_RESTRICTED
Definition: LogPage.php:36
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition: hooks.txt:242
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition: User.php:3456
const LIST_OR
Definition: Defines.php:38
getStartFromConds(IDatabase $db, array $options)
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
getWatchlistOwnerId(User $user, array $options)
const DELETED_USER
Definition: Revision.php:87
getId()
Get the user's ID.
Definition: User.php:2083
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
useNPPatrol()
Check whether to enable new pages patrol features for this user.
Definition: User.php:3465
const RC_EXTERNAL
Definition: Defines.php:139
const RC_NEW
Definition: Defines.php:137
const DB_REPLICA
Definition: defines.php:22
addQuotes($s)
Adds quotes and backslashes.
const DELETED_ACTION
Definition: LogPage.php:33
__construct(LoadBalancer $loadBalancer)
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:34
const RC_EDIT
Definition: Defines.php:136
This exception will be thrown when dieUsage is called to stop module execution.
Definition: ApiMain.php:1860
const RC_LOG
Definition: Defines.php:138