MediaWiki master
WatchedCondition.php
Go to the documentation of this file.
1<?php
2
4
7use stdClass;
10use Wikimedia\Timestamp\TimestampFormat as TS;
11
21 private ?int $userId = null;
22
23 private const ALL_VALUES = [ 'notwatched', 'watchedold', 'watchednew' ];
24
25 public function __construct( private bool $enableExpiry ) {
26 }
27
28 public function setUser( UserIdentity $user ) {
29 $this->userId = $user->getId();
30 }
31
36 public function validateValue( $value ) {
37 if ( !in_array( $value, self::ALL_VALUES, true ) ) {
38 throw new \InvalidArgumentException( 'unknown value for watched filter' );
39 }
40 return $value;
41 }
42
44 public function evaluate( stdClass $row, $value ): bool {
45 if ( !$this->userId
46 || ( $this->enableExpiry && $row->we_expiry !== null
47 && MWTimestamp::convert( TS::UNIX, $row->we_expiry ) <= wfTimestamp() )
48 || $row->wl_user === null
49 ) {
50 return $value === 'notwatched';
51 } elseif ( $row->rc_timestamp &&
52 $row->wl_notificationtimestamp &&
53 $row->rc_timestamp >= $row->wl_notificationtimestamp
54 ) {
55 return $value === 'watchednew';
56 } else {
57 return $value === 'watchedold';
58 }
59 }
60
62 protected function prepareCapture( IReadableDatabase $dbr, QueryBackend $query ) {
63 if ( !$this->userId ) {
64 return;
65 }
66 $query->joinForFields( 'watchlist' )->weakLeft();
67 $query->fields( [ 'wl_user', 'wl_notificationtimestamp', 'rc_timestamp' ] );
68 if ( $this->enableExpiry ) {
69 $query->joinForFields( 'watchlist_expiry' )->left();
70 $query->fields( 'we_expiry' );
71 }
72 }
73
75 protected function prepareConds( IReadableDatabase $dbr, QueryBackend $query ) {
76 $set = $this->getEnumValues( self::ALL_VALUES );
77 if ( $set === null ) {
78 return;
79 } elseif ( $set === [] ) {
80 $query->forceEmptySet();
81 return;
82 }
83 $notwatched = in_array( 'notwatched', $set, true );
84 $watchedold = in_array( 'watchedold', $set, true );
85 $watchednew = in_array( 'watchednew', $set, true );
86
87 if ( !$this->userId ) {
88 if ( !$notwatched ) {
89 $query->forceEmptySet();
90 }
91 return;
92 }
93
94 $orConds = [];
95 if ( $notwatched ) {
96 // Permit not watched: left join, allow join failure or expired
97 $query->joinForConds( 'watchlist' )->left();
98 $orConds[] = $dbr->expr( 'wl_user', '=', null );
99 if ( $this->enableExpiry ) {
100 $query->joinForConds( 'watchlist_expiry' )->left();
101 $orConds[] = $dbr->expr( 'we_expiry', '<=', $dbr->timestamp() );
102 }
103 } else {
104 // Require watched: reorderable join, do not allow expired
106 ->joinOrderHint( QueryBackend::JOIN_ORDER_OTHER );
107 $query->joinForConds( 'watchlist' )->reorderable();
108 if ( $this->enableExpiry ) {
109 $query->joinForConds( 'watchlist_expiry' )->left();
110 $query->where(
111 $dbr->expr( 'we_expiry', '=', null )
112 ->or( 'we_expiry', '>', $dbr->timestamp() )
113 );
114 }
115 }
116
117 if ( $watchedold xor $watchednew ) {
118 if ( $watchedold ) {
119 $oldExpr = ( new RawSQLExpression( 'rc_timestamp < wl_notificationtimestamp' ) )
120 ->or( 'wl_notificationtimestamp', '=', null );
121 } else {
122 $oldExpr = new RawSQLExpression( 'rc_timestamp >= wl_notificationtimestamp' );
123 }
124 if ( $notwatched ) {
125 // Technically redundant since comparison with null wl_notificationtimestamp
126 // is always false
127 $oldExpr = $dbr->expr( 'wl_user', '!=', null )->andExpr( $oldExpr );
128 }
129 $orConds[] = $oldExpr;
130 }
131
132 if ( count( $orConds ) === 1 ) {
133 $query->where( $orConds[0] );
134 } elseif ( count( $orConds ) ) {
135 $query->where( $dbr->orExpr( $orConds ) );
136 }
137 }
138}
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
Check if a recentchange row is watched by the current watchlist user.
prepareConds(IReadableDatabase $dbr, QueryBackend $query)
Add conditions to the query according to the values passed to require() and exclude()....
evaluate(stdClass $row, $value)
Evaluate the filter condition against a row, determining whether it is true or false....
prepareCapture(IReadableDatabase $dbr, QueryBackend $query)
Library for creating and parsing MW-style timestamps.
Raw SQL expression to be used in query builders.
The narrow interface passed to filter modules.
forceEmptySet()
Set a flag forcing the query to return no rows when it is executed.
fields( $fields)
Add fields to the query.
const DENSITY_WATCHLIST
The naive density of a watchlist query.
where(IExpression $expr)
Add a condition to the query.
const JOIN_ORDER_OTHER
Another table will likely be first in the join.
joinForFields(string $table)
Join on the specified table and declare that it will be used to provide fields for the SELECT clause.
joinForConds(string $table)
Join on the specified table and declare that it will be used to provide fields for the WHERE clause.
adjustDensity( $density)
Adjust the density heuristic by multiplying it by the given factor.
Interface for objects representing user identity.
getId( $wikiId=self::LOCAL)
A database connection without write operations.
expr(string $field, string $op, $value)
See Expression::__construct()
orExpr(array $conds)
See Expression::__construct()
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...