MediaWiki master
UserEditTracker.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\User;
4
7use InvalidArgumentException;
13use Wikimedia\Timestamp\ConvertibleTimestamp;
14
22
23 private const FIRST_EDIT = 1;
24 private const LATEST_EDIT = 2;
25
26 private ActorMigration $actorMigration;
27 private IConnectionProvider $dbProvider;
28 private JobQueueGroup $jobQueueGroup;
29
36 private $userEditCountCache = [];
37
43 public function __construct(
44 ActorMigration $actorMigration,
45 IConnectionProvider $dbProvider,
46 JobQueueGroup $jobQueueGroup
47 ) {
48 $this->actorMigration = $actorMigration;
49 $this->dbProvider = $dbProvider;
50 $this->jobQueueGroup = $jobQueueGroup;
51 }
52
59 public function getUserEditCount( UserIdentity $user ): ?int {
60 $userId = $user->getId();
61 if ( !$userId ) {
62 return null;
63 }
64
65 $cacheKey = 'u' . $userId;
66 if ( isset( $this->userEditCountCache[ $cacheKey ] ) ) {
67 return $this->userEditCountCache[ $cacheKey ];
68 }
69
70 $count = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
71 ->select( 'user_editcount' )
72 ->from( 'user' )
73 ->where( [ 'user_id' => $userId ] )
74 ->caller( __METHOD__ )->fetchField();
75
76 if ( $count === null ) {
77 // it has not been initialized. do so.
78 $count = $this->initializeUserEditCount( $user );
79 }
80
81 $this->userEditCountCache[ $cacheKey ] = $count;
82 return $count;
83 }
84
90 public function initializeUserEditCount( UserIdentity $user ): int {
91 $dbr = $this->dbProvider->getReplicaDatabase();
92 $actorWhere = $this->actorMigration->getWhere( $dbr, 'rev_user', $user );
93
94 $count = (int)$dbr->selectField(
95 [ 'revision' ] + $actorWhere['tables'],
96 'COUNT(*)',
97 [ $actorWhere['conds'] ],
98 __METHOD__,
99 [],
100 $actorWhere['joins']
101 );
102
103 // Defer updating the edit count via a job (T259719)
104 $this->jobQueueGroup->push( new UserEditCountInitJob( [
105 'userId' => $user->getId(),
106 'editCount' => $count,
107 ] ) );
108
109 return $count;
110 }
111
118 public function incrementUserEditCount( UserIdentity $user ) {
119 if ( !$user->getId() ) {
120 // Can't store editcount without user row (i.e. unregistered)
121 return;
122 }
123
124 DeferredUpdates::addUpdate(
125 new UserEditCountUpdate( $user, 1 ),
126 DeferredUpdates::POSTSEND
127 );
128 }
129
138 public function getFirstEditTimestamp( UserIdentity $user, int $flags = IDBAccessObject::READ_NORMAL ) {
139 return $this->getUserEditTimestamp( $user, self::FIRST_EDIT, $flags );
140 }
141
150 public function getLatestEditTimestamp( UserIdentity $user, int $flags = IDBAccessObject::READ_NORMAL ) {
151 return $this->getUserEditTimestamp( $user, self::LATEST_EDIT, $flags );
152 }
153
162 private function getUserEditTimestamp( UserIdentity $user, int $type, int $flags = IDBAccessObject::READ_NORMAL ) {
163 if ( !$user->getId() ) {
164 return false;
165 }
166 $db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
167 $actorWhere = $this->actorMigration->getWhere( $db, 'rev_user', $user );
168
169 $sortOrder = ( $type === self::FIRST_EDIT ) ? 'ASC' : 'DESC';
170 $time = $db->selectField(
171 [ 'revision' ] + $actorWhere['tables'],
172 'rev_timestamp',
173 [ $actorWhere['conds'] ],
174 __METHOD__,
175 [ 'ORDER BY' => "rev_timestamp $sortOrder" ],
176 $actorWhere['joins']
177 );
178
179 if ( !$time ) {
180 return false; // no edits
181 }
182
183 return ConvertibleTimestamp::convert( TS_MW, $time );
184 }
185
190 public function clearUserEditCache( UserIdentity $user ) {
191 $userId = $user->getId();
192 if ( !$userId ) {
193 return;
194 }
195
196 $cacheKey = 'u' . $userId;
197 unset( $this->userEditCountCache[ $cacheKey ] );
198 }
199
206 public function setCachedUserEditCount( UserIdentity $user, int $editCount ) {
207 $userId = $user->getId();
208 if ( !$userId ) {
209 throw new InvalidArgumentException( __METHOD__ . ' with an anonymous user' );
210 }
211
212 $cacheKey = 'u' . $userId;
213 $this->userEditCountCache[ $cacheKey ] = $editCount;
214 }
215
216}
Helper class for DAO classes.
Handle enqueueing of background jobs.
Defer callable updates to run later in the PHP process.
Handles increment the edit count for a given set of users.
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.
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.
__construct(ActorMigration $actorMigration, IConnectionProvider $dbProvider, JobQueueGroup $jobQueueGroup)
initializeUserEditCount(UserIdentity $user)
clearUserEditCache(UserIdentity $user)
setCachedUserEditCount(UserIdentity $user, int $editCount)
Job that initializes an user's edit count.
Interface for database access objects.
Interface for objects representing user identity.
getId( $wikiId=self::LOCAL)
Provide primary and replica IDatabase connections.
Utility class for bot passwords.