MediaWiki REL1_40
UserEditTracker.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\User;
4
8use InvalidArgumentException;
13use Wikimedia\Timestamp\ConvertibleTimestamp;
14
23
24 private const FIRST_EDIT = 1;
25 private const LATEST_EDIT = 2;
26
28 private $actorMigration;
29
31 private $loadBalancer;
32
34 private $jobQueueGroup;
35
42 private $userEditCountCache = [];
43
49 public function __construct(
50 ActorMigration $actorMigration,
51 ILoadBalancer $loadBalancer,
52 JobQueueGroup $jobQueueGroup
53 ) {
54 $this->actorMigration = $actorMigration;
55 $this->loadBalancer = $loadBalancer;
56 $this->jobQueueGroup = $jobQueueGroup;
57 }
58
65 public function getUserEditCount( UserIdentity $user ): ?int {
66 if ( !$user->isRegistered() ) {
67 return null;
68 }
69
70 $userId = $user->getId();
71 $cacheKey = 'u' . (string)$userId;
72
73 if ( isset( $this->userEditCountCache[ $cacheKey ] ) ) {
74 return $this->userEditCountCache[ $cacheKey ];
75 }
76
77 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
78 $count = $dbr->selectField(
79 'user',
80 'user_editcount',
81 [ 'user_id' => $userId ],
82 __METHOD__
83 );
84
85 if ( $count === null ) {
86 // it has not been initialized. do so.
87 $count = $this->initializeUserEditCount( $user );
88 }
89
90 $this->userEditCountCache[ $cacheKey ] = $count;
91 return $count;
92 }
93
99 public function initializeUserEditCount( UserIdentity $user ): int {
100 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
101 $actorWhere = $this->actorMigration->getWhere( $dbr, 'rev_user', $user );
102
103 $count = (int)$dbr->selectField(
104 [ 'revision' ] + $actorWhere['tables'],
105 'COUNT(*)',
106 [ $actorWhere['conds'] ],
107 __METHOD__,
108 [],
109 $actorWhere['joins']
110 );
111
112 // Defer updating the edit count via a job (T259719)
113 $this->jobQueueGroup->push( new UserEditCountInitJob( [
114 'userId' => $user->getId(),
115 'editCount' => $count,
116 ] ) );
117
118 return $count;
119 }
120
127 public function incrementUserEditCount( UserIdentity $user ) {
128 if ( !$user->isRegistered() ) {
129 // Anonymous users don't have edit counts
130 return;
131 }
132
133 DeferredUpdates::addUpdate(
134 new UserEditCountUpdate( $user, 1 ),
135 DeferredUpdates::POSTSEND
136 );
137 }
138
147 public function getFirstEditTimestamp( UserIdentity $user, int $flags = IDBAccessObject::READ_NORMAL ) {
148 return $this->getUserEditTimestamp( $user, self::FIRST_EDIT, $flags );
149 }
150
159 public function getLatestEditTimestamp( UserIdentity $user, int $flags = IDBAccessObject::READ_NORMAL ) {
160 return $this->getUserEditTimestamp( $user, self::LATEST_EDIT, $flags );
161 }
162
171 private function getUserEditTimestamp( UserIdentity $user, int $type, int $flags = IDBAccessObject::READ_NORMAL ) {
172 if ( !$user->isRegistered() ) {
173 return false;
174 }
175 list( $index ) = DBAccessObjectUtils::getDBOptions( $flags );
176
177 $db = $this->loadBalancer->getConnectionRef( $index );
178 $actorWhere = $this->actorMigration->getWhere( $db, 'rev_user', $user );
179
180 $sortOrder = ( $type === self::FIRST_EDIT ) ? 'ASC' : 'DESC';
181 $time = $db->selectField(
182 [ 'revision' ] + $actorWhere['tables'],
183 'rev_timestamp',
184 [ $actorWhere['conds'] ],
185 __METHOD__,
186 [ 'ORDER BY' => "rev_timestamp $sortOrder" ],
187 $actorWhere['joins']
188 );
189
190 if ( !$time ) {
191 return false; // no edits
192 }
193
194 return ConvertibleTimestamp::convert( TS_MW, $time );
195 }
196
201 public function clearUserEditCache( UserIdentity $user ) {
202 if ( !$user->isRegistered() ) {
203 return;
204 }
205
206 $userId = $user->getId();
207 $cacheKey = 'u' . (string)$userId;
208
209 unset( $this->userEditCountCache[ $cacheKey ] );
210 }
211
218 public function setCachedUserEditCount( UserIdentity $user, int $editCount ) {
219 if ( !$user->isRegistered() ) {
220 throw new InvalidArgumentException( __METHOD__ . ' with an anonymous user' );
221 }
222
223 $userId = $user->getId();
224 $cacheKey = 'u' . (string)$userId;
225
226 $this->userEditCountCache[ $cacheKey ] = $editCount;
227 }
228
229}
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition WebStart.php:88
Helper class for DAO classes.
Class for managing the deferral of updates within the scope of a PHP script invocation.
Handle enqueueing of background jobs.
This is not intended to be a long-term part of MediaWiki; it will be deprecated and removed once acto...
Track info about user edit counts and timings.
getLatestEditTimestamp(UserIdentity $user, int $flags=IDBAccessObject::READ_NORMAL)
Get the user's latest edit timestamp.
__construct(ActorMigration $actorMigration, ILoadBalancer $loadBalancer, JobQueueGroup $jobQueueGroup)
getUserEditCount(UserIdentity $user)
Get a user's edit count from the user_editcount field, falling back to initialize.
getFirstEditTimestamp(UserIdentity $user, int $flags=IDBAccessObject::READ_NORMAL)
Get the user's first edit timestamp.
incrementUserEditCount(UserIdentity $user)
Schedule a job to increase a user's edit count.
initializeUserEditCount(UserIdentity $user)
clearUserEditCache(UserIdentity $user)
setCachedUserEditCount(UserIdentity $user, int $editCount)
Job that initializes an user's edit count.
Handles increment the edit count for a given set of users.
Interface for database access objects.
Interface for objects representing user identity.
getId( $wikiId=self::LOCAL)
This class is a delegate to ILBFactory for a given database cluster.
const DB_REPLICA
Definition defines.php:26