MediaWiki master
ContribsPager.php
Go to the documentation of this file.
1<?php
9
10use DateTime;
20use MediaWiki\SpecialPage\ContributionsRangeTrait;
23use Wikimedia\IPUtils;
27use Wikimedia\Timestamp\TimestampFormat as TS;
28
39
40 use ContributionsRangeTrait;
41
45 public function __construct(
46 IContextSource $context,
47 array $options,
48 ?LinkRenderer $linkRenderer = null,
49 ?LinkBatchFactory $linkBatchFactory = null,
50 ?HookContainer $hookContainer = null,
51 ?IConnectionProvider $dbProvider = null,
55 ?CommentFormatter $commentFormatter = null,
56 ) {
57 // Class is used directly in extensions - T266484
59
60 parent::__construct(
61 $linkRenderer ?? $services->getLinkRenderer(),
62 $linkBatchFactory ?? $services->getLinkBatchFactory(),
63 $hookContainer ?? $services->getHookContainer(),
64 $revisionStore ?? $services->getRevisionStore(),
65 $namespaceInfo ?? $services->getNamespaceInfo(),
66 $commentFormatter ?? $services->getCommentFormatter(),
67 $services->getUserFactory(),
68 $context,
69 $options,
71 );
72 }
73
83 private function getTargetTable() {
84 $dbr = $this->getDatabase();
85 $ipRangeConds = $this->targetUser->isRegistered()
86 ? null : $this->getIpRangeConds( $dbr, $this->target );
87 if ( $ipRangeConds ) {
88 return 'ip_changes';
89 }
90
91 return 'revision';
92 }
93
95 protected function getRevisionQuery() {
96 $revQuery = $this->revisionStore->getQueryInfo( [ 'page', 'user' ] );
97 $queryInfo = [
98 'tables' => $revQuery['tables'],
99 'fields' => array_merge( $revQuery['fields'], [ 'page_is_new' ] ),
100 'conds' => [],
101 'options' => [],
102 'join_conds' => $revQuery['joins'],
103 ];
104
105 // WARNING: Keep this in sync with getTargetTable()!
106 $ipRangeConds = !$this->targetUser->isRegistered() ?
107 $this->getIpRangeConds( $this->getDatabase(), $this->target ) :
108 null;
109 if ( $ipRangeConds ) {
110 // Put ip_changes first (T284419)
111 array_unshift( $queryInfo['tables'], 'ip_changes' );
112 $queryInfo['join_conds']['revision'] = [
113 'JOIN', [ 'rev_id = ipc_rev_id' ]
114 ];
115 $queryInfo['conds'][] = $ipRangeConds;
116 } else {
117 $queryInfo['conds']['actor_name'] = $this->targetUser->getName();
118 // Force the appropriate index to avoid bad query plans (T307295)
119 $queryInfo['options']['USE INDEX']['revision'] = 'rev_actor_timestamp';
120 }
121
122 return $queryInfo;
123 }
124
131 private function getIpRangeConds( $db, $ip ) {
132 // First make sure it is a valid range and they are not outside the CIDR limit
133 if ( !$this->isQueryableRange( $ip, $this->getConfig() ) ) {
134 return false;
135 }
136
137 [ $start, $end ] = IPUtils::parseRange( $ip );
138
139 return $db->expr( 'ipc_hex', '>=', $start )->and( 'ipc_hex', '<=', $end );
140 }
141
145 public function getIndexField() {
146 // The returned column is used for sorting and continuation, so we need to
147 // make sure to use the right denormalized column depending on which table is
148 // being targeted by the query to avoid bad query plans.
149 // See T200259, T204669, T220991, and T221380.
150 $target = $this->getTargetTable();
151 switch ( $target ) {
152 case 'revision':
153 return 'rev_timestamp';
154 case 'ip_changes':
155 return 'ipc_rev_timestamp';
156 default:
157 wfWarn(
158 __METHOD__ . ": Unknown value '$target' from " . static::class . '::getTargetTable()', 0
159 );
160 return 'rev_timestamp';
161 }
162 }
163
167 protected function getExtraSortFields() {
168 // The returned columns are used for sorting, so we need to make sure
169 // to use the right denormalized column depending on which table is
170 // being targeted by the query to avoid bad query plans.
171 // See T200259, T204669, T220991, and T221380.
172 $target = $this->getTargetTable();
173 switch ( $target ) {
174 case 'revision':
175 return [ 'rev_id' ];
176 case 'ip_changes':
177 return [ 'ipc_rev_id' ];
178 default:
179 wfWarn(
180 __METHOD__ . ": Unknown value '$target' from " . static::class . '::getTargetTable()', 0
181 );
182 return [ 'rev_id' ];
183 }
184 }
185
192 public static function processDateFilter( array $opts ) {
193 $start = $opts['start'] ?? '';
194 $end = $opts['end'] ?? '';
195 $year = $opts['year'] ?? '';
196 $month = $opts['month'] ?? '';
197
198 if ( $start !== '' && $end !== '' && $start > $end ) {
199 $temp = $start;
200 $start = $end;
201 $end = $temp;
202 }
203
204 // If year/month legacy filtering options are set, convert them to display the new stamp
205 if ( $year !== '' || $month !== '' ) {
206 // Reuse getDateCond logic, but subtract a day because
207 // the endpoints of our date range appear inclusive
208 // but the internal end offsets are always exclusive
209 $legacyTimestamp = ReverseChronologicalPager::getOffsetDate( $year, $month );
210 $legacyDateTime = new DateTime( $legacyTimestamp->getTimestamp( TS::ISO_8601 ) );
211 $legacyDateTime = $legacyDateTime->modify( '-1 day' );
212
213 // Clear the new timestamp range options if used and
214 // replace with the converted legacy timestamp
215 $start = '';
216 $end = $legacyDateTime->format( 'Y-m-d' );
217 }
218
219 $opts['start'] = $start;
220 $opts['end'] = $end;
221
222 return $opts;
223 }
224}
225
230class_alias( ContribsPager::class, 'ContribsPager' );
231
233class_alias( ContribsPager::class, 'MediaWiki\\Pager\\ContribsPager' );
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
This is the main service interface for converting single-line comments from various DB comment fields...
Class that generates HTML for internal links.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Factory for LinkBatch objects to batch query page metadata.
Pager for Special:Contributions.
string $target
User name, or a string describing an IP address range.
getDatabase()
Get the Database object in use.
IndexPager with a formatted navigation bar.
Service for looking up page revisions.
Pager for Special:Contributions.
getRevisionQuery()
Get queryInfo for the main query selecting revisions, not including filtering on namespace,...
__construct(IContextSource $context, array $options, ?LinkRenderer $linkRenderer=null, ?LinkBatchFactory $linkBatchFactory=null, ?HookContainer $hookContainer=null, ?IConnectionProvider $dbProvider=null, ?RevisionStore $revisionStore=null, ?NamespaceInfo $namespaceInfo=null, ?UserIdentity $targetUser=null, ?CommentFormatter $commentFormatter=null,)
FIXME List services first T266484 / T290405.
static processDateFilter(array $opts)
Set up date filter options, given request data.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Interface for objects which can provide a MediaWiki context on request.
Interface for objects representing user identity.
Provide primary and replica IDatabase connections.
A database connection without write operations.