MediaWiki master
ContributionsLookup.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\Revision;
4
5use ChangeTags;
19
24
26 private $revisionStore;
27
29 private $linkRendererFactory;
30
32 private $linkBatchFactory;
33
35 private $hookContainer;
36
38 private $dbProvider;
39
41 private $namespaceInfo;
42
44 private $commentFormatter;
45
55 public function __construct(
56 RevisionStore $revisionStore,
57 LinkRendererFactory $linkRendererFactory,
58 LinkBatchFactory $linkBatchFactory,
59 HookContainer $hookContainer,
60 IConnectionProvider $dbProvider,
61 NamespaceInfo $namespaceInfo,
62 CommentFormatter $commentFormatter
63 ) {
64 $this->revisionStore = $revisionStore;
65 $this->linkRendererFactory = $linkRendererFactory;
66 $this->linkBatchFactory = $linkBatchFactory;
67 $this->hookContainer = $hookContainer;
68 $this->dbProvider = $dbProvider;
69 $this->namespaceInfo = $namespaceInfo;
70 $this->commentFormatter = $commentFormatter;
71 }
72
84 private function getPagerParams( int $limit, string $segment ): array {
85 $dir = 'next';
86 $seg = explode( '|', $segment, 2 );
87 if ( count( $seg ) > 1 ) {
88 if ( $seg[0] === 'after' ) {
89 $dir = 'prev';
90 $segment = $seg[1];
91 } elseif ( $seg[0] == 'before' ) {
92 $segment = $seg[1];
93 } else {
94 $dir = null;
95 $segment = null;
96 }
97 } else {
98 $segment = null;
99 }
100 return [
101 'limit' => $limit,
102 'offset' => $segment,
103 'dir' => $dir
104 ];
105 }
106
116 public function getContributions(
117 UserIdentity $target,
118 int $limit,
119 Authority $performer,
120 string $segment = '',
121 string $tag = null
123 $context = new RequestContext();
124 $context->setAuthority( $performer );
125
126 $paramArr = $this->getPagerParams( $limit, $segment );
127 $context->setRequest( new FauxRequest( $paramArr ) );
128
129 // TODO: explore moving this to factory method for testing
130 $pager = $this->getContribsPager( $context, $target, [
131 'tagfilter' => $tag,
132 'revisionsOnly' => true
133 ] );
134 $revisions = [];
135 $tags = [];
136 $count = 0;
137 if ( $pager->getNumRows() > 0 ) {
138 foreach ( $pager->mResult as $row ) {
139 // We retrieve and ignore one extra record to see if we are on the oldest segment.
140 if ( ++$count > $limit ) {
141 break;
142 }
143
144 // TODO: pre-load title batch?
145 $revision = $this->revisionStore->newRevisionFromRow( $row, 0 );
146 $revisions[] = $revision;
147 if ( $row->ts_tags ) {
148 $tagNames = explode( ',', $row->ts_tags );
149 $tags[ $row->rev_id ] = $this->getContributionTags( $tagNames );
150 }
151 }
152 }
153
154 $deltas = $this->getContributionDeltas( $revisions );
155
156 $flags = [
157 'newest' => $pager->mIsFirst,
158 'oldest' => $pager->mIsLast,
159 ];
160
161 // TODO: Make me an option in IndexPager
162 $pager->mIsFirst = false; // XXX: nasty...
163 $pagingQueries = $pager->getPagingQueries();
164
165 $prev = $pagingQueries['prev']['offset'] ?? null;
166 $next = $pagingQueries['next']['offset'] ?? null;
167
168 $after = $prev ? 'after|' . $prev : null; // later in time
169 $before = $next ? 'before|' . $next : null; // earlier in time
170
171 // TODO: Possibly return public $pager properties to segment for populating URLS ($mIsFirst, $mIsLast)
172 // HACK: Force result set order to be descending. Sorting logic in ContribsPager::reallyDoQuery is confusing.
173 if ( $paramArr['dir'] === 'prev' ) {
174 $revisions = array_reverse( $revisions );
175 }
176 return new ContributionsSegment( $revisions, $tags, $before, $after, $deltas, $flags );
177 }
178
183 private function getContributionTags( array $tagNames ): array {
184 $tagMetadata = [];
185 foreach ( $tagNames as $name ) {
186 $tagDisplay = ChangeTags::tagShortDescriptionMessage( $name, RequestContext::getMain() );
187 if ( $tagDisplay ) {
188 $tagMetadata[$name] = $tagDisplay;
189 }
190 }
191 return $tagMetadata;
192 }
193
201 private function getContributionDeltas( $revisions ): array {
202 // SpecialContributions uses the size of the revision if the parent revision is unknown. Cases include:
203 // - revision has been deleted
204 // - parent rev id has not been populated (this is the case for very old revisions)
205 $parentIds = [];
206 foreach ( $revisions as $revision ) {
207 $revId = $revision->getId();
208 $parentIds[$revId] = $revision->getParentId();
209 }
210 $parentSizes = $this->revisionStore->getRevisionSizes( $parentIds );
211 $deltas = [];
212 foreach ( $revisions as $revision ) {
213 $parentId = $revision->getParentId();
214 if ( $parentId === 0 ) { // first revision on a page
215 $delta = $revision->getSize();
216 } elseif ( !isset( $parentSizes[$parentId] ) ) { // parent revision is either deleted or untracked
217 $delta = null;
218 } else {
219 $delta = $revision->getSize() - $parentSizes[$parentId];
220 }
221 $deltas[ $revision->getId() ] = $delta;
222 }
223 return $deltas;
224 }
225
235 public function getContributionCount( UserIdentity $user, Authority $performer, $tag = null ): int {
236 $context = new RequestContext();
237 $context->setAuthority( $performer );
238 $context->setRequest( new FauxRequest( [] ) );
239
240 // TODO: explore moving this to factory method for testing
241 $pager = $this->getContribsPager( $context, $user, [
242 'tagfilter' => $tag,
243 ] );
244
245 $query = $pager->getQueryInfo();
246
247 $count = $pager->mDb->selectField(
248 $query['tables'],
249 'COUNT(*)',
250 $query['conds'],
251 __METHOD__,
252 [],
253 $query['join_conds']
254 );
255
256 return (int)$count;
257 }
258
259 private function getContribsPager(
260 IContextSource $context,
261 UserIdentity $targetUser,
262 array $options
263 ) {
264 return new ContribsPager(
265 $context,
266 $options,
267 $this->linkRendererFactory->create(),
268 $this->linkBatchFactory,
269 $this->hookContainer,
270 $this->dbProvider,
271 $this->revisionStore,
272 $this->namespaceInfo,
273 $targetUser,
274 $this->commentFormatter
275 );
276 }
277
278}
static tagShortDescriptionMessage( $tag, MessageLocalizer $context)
Get the message object for the tag's short description.
This is the main service interface for converting single-line comments from various DB comment fields...
Group all the pieces relevant to the context of a request into one instance.
setAuthority(Authority $authority)
Factory to create LinkRender objects.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:157
Pager for Special:Contributions.
WebRequest clone which takes values from a provided array.
getContributions(UserIdentity $target, int $limit, Authority $performer, string $segment='', string $tag=null)
getContributionCount(UserIdentity $user, Authority $performer, $tag=null)
Returns the number of edits by the given user.
__construct(RevisionStore $revisionStore, LinkRendererFactory $linkRendererFactory, LinkBatchFactory $linkBatchFactory, HookContainer $hookContainer, IConnectionProvider $dbProvider, NamespaceInfo $namespaceInfo, CommentFormatter $commentFormatter)
Service for looking up page revisions.
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.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:37
Interface for objects representing user identity.
Provide primary and replica IDatabase connections.