MediaWiki  1.29.2
WatchedItemQueryService.php
Go to the documentation of this file.
1 <?php
2 
5 use Wikimedia\Assert\Assert;
7 
19 
20  const DIR_OLDER = 'older';
21  const DIR_NEWER = 'newer';
22 
23  const INCLUDE_FLAGS = 'flags';
24  const INCLUDE_USER = 'user';
25  const INCLUDE_USER_ID = 'userid';
26  const INCLUDE_COMMENT = 'comment';
27  const INCLUDE_PATROL_INFO = 'patrol';
28  const INCLUDE_SIZES = 'sizes';
29  const INCLUDE_LOG_INFO = 'loginfo';
30 
31  // FILTER_* constants are part of public API (are used in ApiQueryWatchlist and
32  // ApiQueryWatchlistRaw classes) and should not be changed.
33  // Changing values of those constants will result in a breaking change in the API
34  const FILTER_MINOR = 'minor';
35  const FILTER_NOT_MINOR = '!minor';
36  const FILTER_BOT = 'bot';
37  const FILTER_NOT_BOT = '!bot';
38  const FILTER_ANON = 'anon';
39  const FILTER_NOT_ANON = '!anon';
40  const FILTER_PATROLLED = 'patrolled';
41  const FILTER_NOT_PATROLLED = '!patrolled';
42  const FILTER_UNREAD = 'unread';
43  const FILTER_NOT_UNREAD = '!unread';
44  const FILTER_CHANGED = 'changed';
45  const FILTER_NOT_CHANGED = '!changed';
46 
47  const SORT_ASC = 'ASC';
48  const SORT_DESC = 'DESC';
49 
53  private $loadBalancer;
54 
56  private $extensions = null;
57 
58  public function __construct( LoadBalancer $loadBalancer ) {
59  $this->loadBalancer = $loadBalancer;
60  }
61 
65  private function getExtensions() {
66  if ( $this->extensions === null ) {
67  $this->extensions = [];
68  Hooks::run( 'WatchedItemQueryServiceExtensions', [ &$this->extensions, $this ] );
69  }
70  return $this->extensions;
71  }
72 
77  private function getConnection() {
78  return $this->loadBalancer->getConnectionRef( DB_REPLICA, [ 'watchlist' ] );
79  }
80 
125  User $user, array $options = [], &$startFrom = null
126  ) {
127  $options += [
128  'includeFields' => [],
129  'namespaceIds' => [],
130  'filters' => [],
131  'allRevisions' => false,
132  'usedInGenerator' => false
133  ];
134 
135  Assert::parameter(
136  !isset( $options['rcTypes'] )
137  || !array_diff( $options['rcTypes'], [ RC_EDIT, RC_NEW, RC_LOG, RC_EXTERNAL, RC_CATEGORIZE ] ),
138  '$options[\'rcTypes\']',
139  'must be an array containing only: RC_EDIT, RC_NEW, RC_LOG, RC_EXTERNAL and/or RC_CATEGORIZE'
140  );
141  Assert::parameter(
142  !isset( $options['dir'] ) || in_array( $options['dir'], [ self::DIR_OLDER, self::DIR_NEWER ] ),
143  '$options[\'dir\']',
144  'must be DIR_OLDER or DIR_NEWER'
145  );
146  Assert::parameter(
147  !isset( $options['start'] ) && !isset( $options['end'] ) && $startFrom === null
148  || isset( $options['dir'] ),
149  '$options[\'dir\']',
150  'must be provided when providing the "start" or "end" options or the $startFrom parameter'
151  );
152  Assert::parameter(
153  !isset( $options['startFrom'] ),
154  '$options[\'startFrom\']',
155  'must not be provided, use $startFrom instead'
156  );
157  Assert::parameter(
158  !isset( $startFrom ) || ( is_array( $startFrom ) && count( $startFrom ) === 2 ),
159  '$startFrom',
160  'must be a two-element array'
161  );
162  if ( array_key_exists( 'watchlistOwner', $options ) ) {
163  Assert::parameterType(
164  User::class,
165  $options['watchlistOwner'],
166  '$options[\'watchlistOwner\']'
167  );
168  Assert::parameter(
169  isset( $options['watchlistOwnerToken'] ),
170  '$options[\'watchlistOwnerToken\']',
171  'must be provided when providing watchlistOwner option'
172  );
173  }
174 
175  $tables = [ 'recentchanges', 'watchlist' ];
176  if ( !$options['allRevisions'] ) {
177  $tables[] = 'page';
178  }
179 
180  $db = $this->getConnection();
181 
183  $conds = $this->getWatchedItemsWithRCInfoQueryConds( $db, $user, $options );
184  $dbOptions = $this->getWatchedItemsWithRCInfoQueryDbOptions( $options );
185  $joinConds = $this->getWatchedItemsWithRCInfoQueryJoinConds( $options );
186 
187  if ( $startFrom !== null ) {
188  $conds[] = $this->getStartFromConds( $db, $options, $startFrom );
189  }
190 
191  foreach ( $this->getExtensions() as $extension ) {
192  $extension->modifyWatchedItemsWithRCInfoQuery(
193  $user, $options, $db,
194  $tables,
195  $fields,
196  $conds,
197  $dbOptions,
198  $joinConds
199  );
200  }
201 
202  $res = $db->select(
203  $tables,
204  $fields,
205  $conds,
206  __METHOD__,
207  $dbOptions,
208  $joinConds
209  );
210 
211  $limit = isset( $dbOptions['LIMIT'] ) ? $dbOptions['LIMIT'] : INF;
212  $items = [];
213  $startFrom = null;
214  foreach ( $res as $row ) {
215  if ( --$limit <= 0 ) {
216  $startFrom = [ $row->rc_timestamp, $row->rc_id ];
217  break;
218  }
219 
220  $items[] = [
221  new WatchedItem(
222  $user,
223  new TitleValue( (int)$row->rc_namespace, $row->rc_title ),
224  $row->wl_notificationtimestamp
225  ),
226  $this->getRecentChangeFieldsFromRow( $row )
227  ];
228  }
229 
230  foreach ( $this->getExtensions() as $extension ) {
231  $extension->modifyWatchedItemsWithRCInfo( $user, $options, $db, $items, $res, $startFrom );
232  }
233 
234  return $items;
235  }
236 
256  public function getWatchedItemsForUser( User $user, array $options = [] ) {
257  if ( $user->isAnon() ) {
258  // TODO: should this just return an empty array or rather complain loud at this point
259  // as e.g. ApiBase::getWatchlistUser does?
260  return [];
261  }
262 
263  $options += [ 'namespaceIds' => [] ];
264 
265  Assert::parameter(
266  !isset( $options['sort'] ) || in_array( $options['sort'], [ self::SORT_ASC, self::SORT_DESC ] ),
267  '$options[\'sort\']',
268  'must be SORT_ASC or SORT_DESC'
269  );
270  Assert::parameter(
271  !isset( $options['filter'] ) || in_array(
272  $options['filter'], [ self::FILTER_CHANGED, self::FILTER_NOT_CHANGED ]
273  ),
274  '$options[\'filter\']',
275  'must be FILTER_CHANGED or FILTER_NOT_CHANGED'
276  );
277  Assert::parameter(
278  !isset( $options['from'] ) && !isset( $options['until'] ) && !isset( $options['startFrom'] )
279  || isset( $options['sort'] ),
280  '$options[\'sort\']',
281  'must be provided if any of "from", "until", "startFrom" options is provided'
282  );
283 
284  $db = $this->getConnection();
285 
286  $conds = $this->getWatchedItemsForUserQueryConds( $db, $user, $options );
287  $dbOptions = $this->getWatchedItemsForUserQueryDbOptions( $options );
288 
289  $res = $db->select(
290  'watchlist',
291  [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
292  $conds,
293  __METHOD__,
294  $dbOptions
295  );
296 
297  $watchedItems = [];
298  foreach ( $res as $row ) {
299  // todo these could all be cached at some point?
300  $watchedItems[] = new WatchedItem(
301  $user,
302  new TitleValue( (int)$row->wl_namespace, $row->wl_title ),
303  $row->wl_notificationtimestamp
304  );
305  }
306 
307  return $watchedItems;
308  }
309 
310  private function getRecentChangeFieldsFromRow( stdClass $row ) {
311  // This can be simplified to single array_filter call filtering by key value,
312  // once we stop supporting PHP 5.5
313  $allFields = get_object_vars( $row );
314  $rcKeys = array_filter(
315  array_keys( $allFields ),
316  function( $key ) {
317  return substr( $key, 0, 3 ) === 'rc_';
318  }
319  );
320  return array_intersect_key( $allFields, array_flip( $rcKeys ) );
321  }
322 
324  $fields = [
325  'rc_id',
326  'rc_namespace',
327  'rc_title',
328  'rc_timestamp',
329  'rc_type',
330  'rc_deleted',
331  'wl_notificationtimestamp'
332  ];
333 
334  $rcIdFields = [
335  'rc_cur_id',
336  'rc_this_oldid',
337  'rc_last_oldid',
338  ];
339  if ( $options['usedInGenerator'] ) {
340  if ( $options['allRevisions'] ) {
341  $rcIdFields = [ 'rc_this_oldid' ];
342  } else {
343  $rcIdFields = [ 'rc_cur_id' ];
344  }
345  }
346  $fields = array_merge( $fields, $rcIdFields );
347 
348  if ( in_array( self::INCLUDE_FLAGS, $options['includeFields'] ) ) {
349  $fields = array_merge( $fields, [ 'rc_type', 'rc_minor', 'rc_bot' ] );
350  }
351  if ( in_array( self::INCLUDE_USER, $options['includeFields'] ) ) {
352  $fields[] = 'rc_user_text';
353  }
354  if ( in_array( self::INCLUDE_USER_ID, $options['includeFields'] ) ) {
355  $fields[] = 'rc_user';
356  }
357  if ( in_array( self::INCLUDE_COMMENT, $options['includeFields'] ) ) {
358  $fields[] = 'rc_comment';
359  }
360  if ( in_array( self::INCLUDE_PATROL_INFO, $options['includeFields'] ) ) {
361  $fields = array_merge( $fields, [ 'rc_patrolled', 'rc_log_type' ] );
362  }
363  if ( in_array( self::INCLUDE_SIZES, $options['includeFields'] ) ) {
364  $fields = array_merge( $fields, [ 'rc_old_len', 'rc_new_len' ] );
365  }
366  if ( in_array( self::INCLUDE_LOG_INFO, $options['includeFields'] ) ) {
367  $fields = array_merge( $fields, [ 'rc_logid', 'rc_log_type', 'rc_log_action', 'rc_params' ] );
368  }
369 
370  return $fields;
371  }
372 
374  IDatabase $db,
375  User $user,
377  ) {
378  $watchlistOwnerId = $this->getWatchlistOwnerId( $user, $options );
379  $conds = [ 'wl_user' => $watchlistOwnerId ];
380 
381  if ( !$options['allRevisions'] ) {
382  $conds[] = $db->makeList(
383  [ 'rc_this_oldid=page_latest', 'rc_type=' . RC_LOG ],
384  LIST_OR
385  );
386  }
387 
388  if ( $options['namespaceIds'] ) {
389  $conds['wl_namespace'] = array_map( 'intval', $options['namespaceIds'] );
390  }
391 
392  if ( array_key_exists( 'rcTypes', $options ) ) {
393  $conds['rc_type'] = array_map( 'intval', $options['rcTypes'] );
394  }
395 
396  $conds = array_merge(
397  $conds,
399  );
400 
401  $conds = array_merge( $conds, $this->getStartEndConds( $db, $options ) );
402 
403  if ( !isset( $options['start'] ) && !isset( $options['end'] ) ) {
404  if ( $db->getType() === 'mysql' ) {
405  // This is an index optimization for mysql
406  $conds[] = 'rc_timestamp > ' . $db->addQuotes( '' );
407  }
408  }
409 
410  $conds = array_merge( $conds, $this->getUserRelatedConds( $db, $user, $options ) );
411 
412  $deletedPageLogCond = $this->getExtraDeletedPageLogEntryRelatedCond( $db, $user );
413  if ( $deletedPageLogCond ) {
414  $conds[] = $deletedPageLogCond;
415  }
416 
417  return $conds;
418  }
419 
420  private function getWatchlistOwnerId( User $user, array $options ) {
421  if ( array_key_exists( 'watchlistOwner', $options ) ) {
423  $watchlistOwner = $options['watchlistOwner'];
424  $ownersToken = $watchlistOwner->getOption( 'watchlisttoken' );
425  $token = $options['watchlistOwnerToken'];
426  if ( $ownersToken == '' || !hash_equals( $ownersToken, $token ) ) {
427  throw ApiUsageException::newWithMessage( null, 'apierror-bad-watchlist-token', 'bad_wltoken' );
428  }
429  return $watchlistOwner->getId();
430  }
431  return $user->getId();
432  }
433 
435  $conds = [];
436 
437  if ( in_array( self::FILTER_MINOR, $options['filters'] ) ) {
438  $conds[] = 'rc_minor != 0';
439  } elseif ( in_array( self::FILTER_NOT_MINOR, $options['filters'] ) ) {
440  $conds[] = 'rc_minor = 0';
441  }
442 
443  if ( in_array( self::FILTER_BOT, $options['filters'] ) ) {
444  $conds[] = 'rc_bot != 0';
445  } elseif ( in_array( self::FILTER_NOT_BOT, $options['filters'] ) ) {
446  $conds[] = 'rc_bot = 0';
447  }
448 
449  if ( in_array( self::FILTER_ANON, $options['filters'] ) ) {
450  $conds[] = 'rc_user = 0';
451  } elseif ( in_array( self::FILTER_NOT_ANON, $options['filters'] ) ) {
452  $conds[] = 'rc_user != 0';
453  }
454 
455  if ( $user->useRCPatrol() || $user->useNPPatrol() ) {
456  // TODO: not sure if this should simply ignore patrolled filters if user does not have the patrol
457  // right, or maybe rather fail loud at this point, same as e.g. ApiQueryWatchlist does?
458  if ( in_array( self::FILTER_PATROLLED, $options['filters'] ) ) {
459  $conds[] = 'rc_patrolled != 0';
460  } elseif ( in_array( self::FILTER_NOT_PATROLLED, $options['filters'] ) ) {
461  $conds[] = 'rc_patrolled = 0';
462  }
463  }
464 
465  if ( in_array( self::FILTER_UNREAD, $options['filters'] ) ) {
466  $conds[] = 'rc_timestamp >= wl_notificationtimestamp';
467  } elseif ( in_array( self::FILTER_NOT_UNREAD, $options['filters'] ) ) {
468  // TODO: should this be changed to use Database::makeList?
469  $conds[] = 'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp';
470  }
471 
472  return $conds;
473  }
474 
475  private function getStartEndConds( IDatabase $db, array $options ) {
476  if ( !isset( $options['start'] ) && !isset( $options['end'] ) ) {
477  return [];
478  }
479 
480  $conds = [];
481 
482  if ( isset( $options['start'] ) ) {
483  $after = $options['dir'] === self::DIR_OLDER ? '<=' : '>=';
484  $conds[] = 'rc_timestamp ' . $after . ' ' .
485  $db->addQuotes( $db->timestamp( $options['start'] ) );
486  }
487  if ( isset( $options['end'] ) ) {
488  $before = $options['dir'] === self::DIR_OLDER ? '>=' : '<=';
489  $conds[] = 'rc_timestamp ' . $before . ' ' .
490  $db->addQuotes( $db->timestamp( $options['end'] ) );
491  }
492 
493  return $conds;
494  }
495 
496  private function getUserRelatedConds( IDatabase $db, User $user, array $options ) {
497  if ( !array_key_exists( 'onlyByUser', $options ) && !array_key_exists( 'notByUser', $options ) ) {
498  return [];
499  }
500 
501  $conds = [];
502 
503  if ( array_key_exists( 'onlyByUser', $options ) ) {
504  $conds['rc_user_text'] = $options['onlyByUser'];
505  } elseif ( array_key_exists( 'notByUser', $options ) ) {
506  $conds[] = 'rc_user_text != ' . $db->addQuotes( $options['notByUser'] );
507  }
508 
509  // Avoid brute force searches (T19342)
510  $bitmask = 0;
511  if ( !$user->isAllowed( 'deletedhistory' ) ) {
512  $bitmask = Revision::DELETED_USER;
513  } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
515  }
516  if ( $bitmask ) {
517  $conds[] = $db->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask";
518  }
519 
520  return $conds;
521  }
522 
524  // LogPage::DELETED_ACTION hides the affected page, too. So hide those
525  // entirely from the watchlist, or someone could guess the title.
526  $bitmask = 0;
527  if ( !$user->isAllowed( 'deletedhistory' ) ) {
528  $bitmask = LogPage::DELETED_ACTION;
529  } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
531  }
532  if ( $bitmask ) {
533  return $db->makeList( [
534  'rc_type != ' . RC_LOG,
535  $db->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask",
536  ], LIST_OR );
537  }
538  return '';
539  }
540 
541  private function getStartFromConds( IDatabase $db, array $options, array $startFrom ) {
542  $op = $options['dir'] === self::DIR_OLDER ? '<' : '>';
543  list( $rcTimestamp, $rcId ) = $startFrom;
544  $rcTimestamp = $db->addQuotes( $db->timestamp( $rcTimestamp ) );
545  $rcId = (int)$rcId;
546  return $db->makeList(
547  [
548  "rc_timestamp $op $rcTimestamp",
549  $db->makeList(
550  [
551  "rc_timestamp = $rcTimestamp",
552  "rc_id $op= $rcId"
553  ],
554  LIST_AND
555  )
556  ],
557  LIST_OR
558  );
559  }
560 
562  $conds = [ 'wl_user' => $user->getId() ];
563  if ( $options['namespaceIds'] ) {
564  $conds['wl_namespace'] = array_map( 'intval', $options['namespaceIds'] );
565  }
566  if ( isset( $options['filter'] ) ) {
567  $filter = $options['filter'];
568  if ( $filter === self::FILTER_CHANGED ) {
569  $conds[] = 'wl_notificationtimestamp IS NOT NULL';
570  } else {
571  $conds[] = 'wl_notificationtimestamp IS NULL';
572  }
573  }
574 
575  if ( isset( $options['from'] ) ) {
576  $op = $options['sort'] === self::SORT_ASC ? '>' : '<';
577  $conds[] = $this->getFromUntilTargetConds( $db, $options['from'], $op );
578  }
579  if ( isset( $options['until'] ) ) {
580  $op = $options['sort'] === self::SORT_ASC ? '<' : '>';
581  $conds[] = $this->getFromUntilTargetConds( $db, $options['until'], $op );
582  }
583  if ( isset( $options['startFrom'] ) ) {
584  $op = $options['sort'] === self::SORT_ASC ? '>' : '<';
585  $conds[] = $this->getFromUntilTargetConds( $db, $options['startFrom'], $op );
586  }
587 
588  return $conds;
589  }
590 
600  private function getFromUntilTargetConds( IDatabase $db, LinkTarget $target, $op ) {
601  return $db->makeList(
602  [
603  "wl_namespace $op " . $target->getNamespace(),
604  $db->makeList(
605  [
606  'wl_namespace = ' . $target->getNamespace(),
607  "wl_title $op= " . $db->addQuotes( $target->getDBkey() )
608  ],
609  LIST_AND
610  )
611  ],
612  LIST_OR
613  );
614  }
615 
617  $dbOptions = [];
618 
619  if ( array_key_exists( 'dir', $options ) ) {
620  $sort = $options['dir'] === self::DIR_OLDER ? ' DESC' : '';
621  $dbOptions['ORDER BY'] = [ 'rc_timestamp' . $sort, 'rc_id' . $sort ];
622  }
623 
624  if ( array_key_exists( 'limit', $options ) ) {
625  $dbOptions['LIMIT'] = (int)$options['limit'] + 1;
626  }
627 
628  return $dbOptions;
629  }
630 
632  $dbOptions = [];
633  if ( array_key_exists( 'sort', $options ) ) {
634  $dbOptions['ORDER BY'] = [
635  "wl_namespace {$options['sort']}",
636  "wl_title {$options['sort']}"
637  ];
638  if ( count( $options['namespaceIds'] ) === 1 ) {
639  $dbOptions['ORDER BY'] = "wl_title {$options['sort']}";
640  }
641  }
642  if ( array_key_exists( 'limit', $options ) ) {
643  $dbOptions['LIMIT'] = (int)$options['limit'];
644  }
645  return $dbOptions;
646  }
647 
649  $joinConds = [
650  'watchlist' => [ 'INNER JOIN',
651  [
652  'wl_namespace=rc_namespace',
653  'wl_title=rc_title'
654  ]
655  ]
656  ];
657  if ( !$options['allRevisions'] ) {
658  $joinConds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
659  }
660  return $joinConds;
661  }
662 
663 }
WatchedItemQueryService\getConnection
getConnection()
Definition: WatchedItemQueryService.php:77
Revision\DELETED_USER
const DELETED_USER
Definition: Revision.php:92
Revision\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: Revision.php:93
WatchedItemQueryService\getFromUntilTargetConds
getFromUntilTargetConds(IDatabase $db, LinkTarget $target, $op)
Creates a query condition part for getting only items before or after the given link target (while or...
Definition: WatchedItemQueryService.php:600
RC_EXTERNAL
const RC_EXTERNAL
Definition: Defines.php:143
WatchedItemQueryService\getWatchedItemsWithRCInfoQueryConds
getWatchedItemsWithRCInfoQueryConds(IDatabase $db, User $user, array $options)
Definition: WatchedItemQueryService.php:373
WatchedItemQueryService\getWatchedItemsWithRCInfoQueryJoinConds
getWatchedItemsWithRCInfoQueryJoinConds(array $options)
Definition: WatchedItemQueryService.php:648
WatchedItemQueryServiceExtension
Definition: WatchedItemQueryServiceExtension.php:16
WatchedItemQueryService\getUserRelatedConds
getUserRelatedConds(IDatabase $db, User $user, array $options)
Definition: WatchedItemQueryService.php:496
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
$tables
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition: hooks.txt:990
WatchedItemQueryService\INCLUDE_COMMENT
const INCLUDE_COMMENT
Definition: WatchedItemQueryService.php:26
WatchedItemQueryService\$loadBalancer
LoadBalancer $loadBalancer
Definition: WatchedItemQueryService.php:53
WatchedItemQueryService\getWatchedItemsForUserQueryConds
getWatchedItemsForUserQueryConds(IDatabase $db, User $user, array $options)
Definition: WatchedItemQueryService.php:561
Wikimedia\Rdbms\IDatabase\makeList
makeList( $a, $mode=self::LIST_COMMA)
Makes an encoded list of strings from an array.
WatchedItemQueryService\FILTER_PATROLLED
const FILTER_PATROLLED
Definition: WatchedItemQueryService.php:40
captcha-old.count
count
Definition: captcha-old.py:225
WatchedItemQueryService\getWatchedItemsWithRCInfoQueryFields
getWatchedItemsWithRCInfoQueryFields(array $options)
Definition: WatchedItemQueryService.php:323
WatchedItemQueryService\getStartEndConds
getStartEndConds(IDatabase $db, array $options)
Definition: WatchedItemQueryService.php:475
RC_LOG
const RC_LOG
Definition: Defines.php:142
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$user
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 account $user
Definition: hooks.txt:246
WatchedItemQueryService\getExtraDeletedPageLogEntryRelatedCond
getExtraDeletedPageLogEntryRelatedCond(IDatabase $db, User $user)
Definition: WatchedItemQueryService.php:523
WatchedItemQueryService\getWatchedItemsWithRCInfoQueryDbOptions
getWatchedItemsWithRCInfoQueryDbOptions(array $options)
Definition: WatchedItemQueryService.php:616
RC_EDIT
const RC_EDIT
Definition: Defines.php:140
WatchedItemQueryService\getWatchedItemsForUserQueryDbOptions
getWatchedItemsForUserQueryDbOptions(array $options)
Definition: WatchedItemQueryService.php:631
$res
$res
Definition: database.txt:21
WatchedItemQueryService\getWatchedItemsWithRecentChangeInfo
getWatchedItemsWithRecentChangeInfo(User $user, array $options=[], &$startFrom=null)
Definition: WatchedItemQueryService.php:124
ApiUsageException\newWithMessage
static newWithMessage(ApiBase $module=null, $msg, $code=null, $data=null, $httpCode=0)
Definition: ApiUsageException.php:138
php
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
LIST_AND
const LIST_AND
Definition: Defines.php:41
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
WatchedItemQueryService\INCLUDE_LOG_INFO
const INCLUDE_LOG_INFO
Definition: WatchedItemQueryService.php:29
MediaWiki\Linker\LinkTarget\getNamespace
getNamespace()
Get the namespace index.
Wikimedia\Rdbms\IDatabase\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
LIST_OR
const LIST_OR
Definition: Defines.php:44
WatchedItemQueryService\getWatchedItemsWithRCInfoQueryFilterConds
getWatchedItemsWithRCInfoQueryFilterConds(User $user, array $options)
Definition: WatchedItemQueryService.php:434
WatchedItemQueryService\FILTER_MINOR
const FILTER_MINOR
Definition: WatchedItemQueryService.php:34
WatchedItemQueryService\FILTER_NOT_CHANGED
const FILTER_NOT_CHANGED
Definition: WatchedItemQueryService.php:45
WatchedItemQueryService\INCLUDE_USER
const INCLUDE_USER
Definition: WatchedItemQueryService.php:24
WatchedItemQueryService\FILTER_NOT_BOT
const FILTER_NOT_BOT
Definition: WatchedItemQueryService.php:37
WatchedItemQueryService
Definition: WatchedItemQueryService.php:18
WatchedItemQueryService\INCLUDE_PATROL_INFO
const INCLUDE_PATROL_INFO
Definition: WatchedItemQueryService.php:27
$limit
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup 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 the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1049
WatchedItemQueryService\FILTER_BOT
const FILTER_BOT
Definition: WatchedItemQueryService.php:36
WatchedItemQueryService\INCLUDE_USER_ID
const INCLUDE_USER_ID
Definition: WatchedItemQueryService.php:25
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
list
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
$sort
$sort
Definition: profileinfo.php:323
LogPage\DELETED_ACTION
const DELETED_ACTION
Definition: LogPage.php:32
Wikimedia\Rdbms\LoadBalancer
Database connection, tracking, load balancing, and transaction manager for a cluster.
Definition: LoadBalancer.php:41
WatchedItemQueryService\DIR_NEWER
const DIR_NEWER
Definition: WatchedItemQueryService.php:21
WatchedItemQueryService\SORT_DESC
const SORT_DESC
Definition: WatchedItemQueryService.php:48
extensions
The ContentHandler facility adds support for arbitrary content types on wiki instead of relying on wikitext for everything It was introduced in MediaWiki Each kind of and so on Built in content types as usual *javascript user provided javascript code *json simple implementation for use by extensions
Definition: contenthandler.txt:5
WatchedItemQueryService\getRecentChangeFieldsFromRow
getRecentChangeFieldsFromRow(stdClass $row)
Definition: WatchedItemQueryService.php:310
WatchedItem
Representation of a pair of user and title for watchlist entries.
Definition: WatchedItem.php:32
WatchedItemQueryService\FILTER_NOT_PATROLLED
const FILTER_NOT_PATROLLED
Definition: WatchedItemQueryService.php:41
MediaWiki\Linker\LinkTarget\getDBkey
getDBkey()
Get the main part with underscores.
WatchedItemQueryService\SORT_ASC
const SORT_ASC
Definition: WatchedItemQueryService.php:47
WatchedItemQueryService\FILTER_NOT_MINOR
const FILTER_NOT_MINOR
Definition: WatchedItemQueryService.php:35
RC_NEW
const RC_NEW
Definition: Defines.php:141
WatchedItemQueryService\INCLUDE_FLAGS
const INCLUDE_FLAGS
Definition: WatchedItemQueryService.php:23
WatchedItemQueryService\__construct
__construct(LoadBalancer $loadBalancer)
Definition: WatchedItemQueryService.php:58
Wikimedia\Rdbms\IDatabase\bitAnd
bitAnd( $fieldLeft, $fieldRight)
WatchedItemQueryService\DIR_OLDER
const DIR_OLDER
Definition: WatchedItemQueryService.php:20
WatchedItemQueryService\getExtensions
getExtensions()
Definition: WatchedItemQueryService.php:65
Wikimedia\Rdbms\IDatabase\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
WatchedItemQueryService\FILTER_CHANGED
const FILTER_CHANGED
Definition: WatchedItemQueryService.php:44
WatchedItemQueryService\FILTER_NOT_UNREAD
const FILTER_NOT_UNREAD
Definition: WatchedItemQueryService.php:43
as
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
WatchedItemQueryService\getWatchlistOwnerId
getWatchlistOwnerId(User $user, array $options)
Definition: WatchedItemQueryService.php:420
WatchedItemQueryService\FILTER_NOT_ANON
const FILTER_NOT_ANON
Definition: WatchedItemQueryService.php:39
Wikimedia\Rdbms\IDatabase\getType
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
LogPage\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: LogPage.php:35
class
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
RC_CATEGORIZE
const RC_CATEGORIZE
Definition: Defines.php:144
WatchedItemQueryService\INCLUDE_SIZES
const INCLUDE_SIZES
Definition: WatchedItemQueryService.php:28
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:27
WatchedItemQueryService\getWatchedItemsForUser
getWatchedItemsForUser(User $user, array $options=[])
For simple listing of user's watchlist items, see WatchedItemStore::getWatchedItemsForUser.
Definition: WatchedItemQueryService.php:256
WatchedItemQueryService\FILTER_ANON
const FILTER_ANON
Definition: WatchedItemQueryService.php:38
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:50
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
WatchedItemQueryService\FILTER_UNREAD
const FILTER_UNREAD
Definition: WatchedItemQueryService.php:42
WatchedItemQueryService\$extensions
WatchedItemQueryServiceExtension[] null $extensions
Definition: WatchedItemQueryService.php:56
$options
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup 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:1049
array
the array() calling protocol came about after MediaWiki 1.4rc1.
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36
WatchedItemQueryService\getStartFromConds
getStartFromConds(IDatabase $db, array $options, array $startFrom)
Definition: WatchedItemQueryService.php:541