MediaWiki master
WatchedCondition.php
Go to the documentation of this file.
1<?php
2
4
7use stdClass;
10use Wikimedia\Timestamp\TimestampFormat as TS;
11
19 private ?int $userId = null;
20
21 private const ALL_VALUES = [ 'notwatched', 'watchedold', 'watchednew' ];
22
23 public function __construct( private bool $enableExpiry ) {
24 }
25
26 public function setUser( UserIdentity $user ) {
27 $this->userId = $user->getId();
28 }
29
34 public function validateValue( $value ) {
35 if ( !in_array( $value, self::ALL_VALUES, true ) ) {
36 throw new \InvalidArgumentException( 'unknown value for watched filter' );
37 }
38 return $value;
39 }
40
42 public function evaluate( stdClass $row, $value ): bool {
43 if ( !$this->userId
44 || ( $this->enableExpiry && $row->we_expiry !== null
45 && MWTimestamp::convert( TS::UNIX, $row->we_expiry ) <= wfTimestamp() )
46 || $row->wl_user === null
47 ) {
48 return $value === 'notwatched';
49 } elseif ( $row->rc_timestamp &&
50 $row->wl_notificationtimestamp &&
51 $row->rc_timestamp >= $row->wl_notificationtimestamp
52 ) {
53 return $value === 'watchednew';
54 } else {
55 return $value === 'watchedold';
56 }
57 }
58
60 protected function prepareCapture( IReadableDatabase $dbr, QueryBackend $query ) {
61 if ( !$this->userId ) {
62 return;
63 }
64 $query->joinForFields( 'watchlist' )->weakLeft();
65 $query->fields( [ 'wl_user', 'wl_notificationtimestamp', 'rc_timestamp' ] );
66 if ( $this->enableExpiry ) {
67 $query->joinForFields( 'watchlist_expiry' )->left();
68 $query->fields( 'we_expiry' );
69 }
70 }
71
73 protected function prepareConds( IReadableDatabase $dbr, QueryBackend $query ) {
74 $set = $this->getEnumValues( self::ALL_VALUES );
75 if ( $set === null ) {
76 return;
77 } elseif ( $set === [] ) {
78 $query->forceEmptySet();
79 return;
80 }
81 $notwatched = in_array( 'notwatched', $set, true );
82 $watchedold = in_array( 'watchedold', $set, true );
83 $watchednew = in_array( 'watchednew', $set, true );
84
85 if ( !$this->userId ) {
86 if ( !$notwatched ) {
87 $query->forceEmptySet();
88 }
89 return;
90 }
91
92 $orConds = [];
93 if ( $notwatched ) {
94 // Permit not watched: left join, allow join failure or expired
95 $query->joinForConds( 'watchlist' )->left();
96 $orConds[] = $dbr->expr( 'wl_user', '=', null );
97 if ( $this->enableExpiry ) {
98 $query->joinForConds( 'watchlist_expiry' )->left();
99 $orConds[] = $dbr->expr( 'we_expiry', '<=', $dbr->timestamp() );
100 }
101 } else {
102 // Require watched: reorderable join, do not allow expired
104 ->joinOrderHint( QueryBackend::JOIN_ORDER_OTHER );
105 $query->joinForConds( 'watchlist' )->reorderable();
106 if ( $this->enableExpiry ) {
107 $query->joinForConds( 'watchlist_expiry' )->left();
108 $query->where(
109 $dbr->expr( 'we_expiry', '=', null )
110 ->or( 'we_expiry', '>', $dbr->timestamp() )
111 );
112 }
113 }
114
115 if ( $watchedold xor $watchednew ) {
116 if ( $watchedold ) {
117 $oldExpr = ( new RawSQLExpression( 'rc_timestamp < wl_notificationtimestamp' ) )
118 ->or( 'wl_notificationtimestamp', '=', null );
119 } else {
120 $oldExpr = new RawSQLExpression( 'rc_timestamp >= wl_notificationtimestamp' );
121 }
122 if ( $notwatched ) {
123 // Technically redundant since comparison with null wl_notificationtimestamp
124 // is always false
125 $oldExpr = $dbr->expr( 'wl_user', '!=', null )->andExpr( $oldExpr );
126 }
127 $orConds[] = $oldExpr;
128 }
129
130 if ( count( $orConds ) === 1 ) {
131 $query->where( $orConds[0] );
132 } elseif ( count( $orConds ) ) {
133 $query->where( $dbr->orExpr( $orConds ) );
134 }
135 }
136}
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
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...