MediaWiki  master
UserEditTracker.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\User;
4 
7 use InvalidArgumentException;
8 use JobQueueGroup;
12 use Wikimedia\Timestamp\ConvertibleTimestamp;
13 
22 
23  private const FIRST_EDIT = 1;
24  private const LATEST_EDIT = 2;
25 
27  private $actorMigration;
28 
30  private $loadBalancer;
31 
33  private $jobQueueGroup;
34 
41  private $userEditCountCache = [];
42 
48  public function __construct(
49  ActorMigration $actorMigration,
50  ILoadBalancer $loadBalancer,
51  JobQueueGroup $jobQueueGroup
52  ) {
53  $this->actorMigration = $actorMigration;
54  $this->loadBalancer = $loadBalancer;
55  $this->jobQueueGroup = $jobQueueGroup;
56  }
57 
64  public function getUserEditCount( UserIdentity $user ): ?int {
65  if ( !$user->isRegistered() ) {
66  return null;
67  }
68 
69  $userId = $user->getId();
70  $cacheKey = 'u' . (string)$userId;
71 
72  if ( isset( $this->userEditCountCache[ $cacheKey ] ) ) {
73  return $this->userEditCountCache[ $cacheKey ];
74  }
75 
76  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
77  $count = $dbr->selectField(
78  'user',
79  'user_editcount',
80  [ 'user_id' => $userId ],
81  __METHOD__
82  );
83 
84  if ( $count === null ) {
85  // it has not been initialized. do so.
86  $count = $this->initializeUserEditCount( $user );
87  }
88 
89  $this->userEditCountCache[ $cacheKey ] = $count;
90  return $count;
91  }
92 
98  public function initializeUserEditCount( UserIdentity $user ): int {
99  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
100  $actorWhere = $this->actorMigration->getWhere( $dbr, 'rev_user', $user );
101 
102  $count = (int)$dbr->selectField(
103  [ 'revision' ] + $actorWhere['tables'],
104  'COUNT(*)',
105  [ $actorWhere['conds'] ],
106  __METHOD__,
107  [],
108  $actorWhere['joins']
109  );
110 
111  // Defer updating the edit count via a job (T259719)
112  $this->jobQueueGroup->push( new UserEditCountInitJob( [
113  'userId' => $user->getId(),
114  'editCount' => $count,
115  ] ) );
116 
117  return $count;
118  }
119 
126  public function incrementUserEditCount( UserIdentity $user ) {
127  if ( !$user->isRegistered() ) {
128  // Anonymous users don't have edit counts
129  return;
130  }
131 
133  new UserEditCountUpdate( $user, 1 ),
134  DeferredUpdates::POSTSEND
135  );
136  }
137 
145  public function getFirstEditTimestamp( UserIdentity $user ) {
146  return $this->getUserEditTimestamp( $user, self::FIRST_EDIT );
147  }
148 
156  public function getLatestEditTimestamp( UserIdentity $user ) {
157  return $this->getUserEditTimestamp( $user, self::LATEST_EDIT );
158  }
159 
167  private function getUserEditTimestamp( UserIdentity $user, int $type ) {
168  if ( !$user->isRegistered() ) {
169  return false;
170  }
171 
172  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
173  $actorWhere = $this->actorMigration->getWhere( $dbr, 'rev_user', $user );
174 
175  $sortOrder = ( $type === self::FIRST_EDIT ) ? 'ASC' : 'DESC';
176  $time = $dbr->selectField(
177  [ 'revision' ] + $actorWhere['tables'],
178  'rev_timestamp',
179  [ $actorWhere['conds'] ],
180  __METHOD__,
181  [ 'ORDER BY' => "rev_timestamp $sortOrder" ],
182  $actorWhere['joins']
183  );
184 
185  if ( !$time ) {
186  return false; // no edits
187  }
188 
189  return ConvertibleTimestamp::convert( TS_MW, $time );
190  }
191 
196  public function clearUserEditCache( UserIdentity $user ) {
197  if ( !$user->isRegistered() ) {
198  return;
199  }
200 
201  $userId = $user->getId();
202  $cacheKey = 'u' . (string)$userId;
203 
204  unset( $this->userEditCountCache[ $cacheKey ] );
205  }
206 
213  public function setCachedUserEditCount( UserIdentity $user, int $editCount ) {
214  if ( !$user->isRegistered() ) {
215  throw new InvalidArgumentException( __METHOD__ . ' with an anonymous user' );
216  }
217 
218  $userId = $user->getId();
219  $cacheKey = 'u' . (string)$userId;
220 
221  $this->userEditCountCache[ $cacheKey ] = $editCount;
222  }
223 
224 }
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
This is not intended to be a long-term part of MediaWiki; it will be deprecated and removed once acto...
Class for managing the deferral of updates within the scope of a PHP script invocation.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the pending update queue for execution at the appropriate time.
Class to handle enqueueing of background jobs.
Track info about user edit counts and timings.
getLatestEditTimestamp(UserIdentity $user)
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.
incrementUserEditCount(UserIdentity $user)
Schedule a job to increase a user's edit count.
getFirstEditTimestamp(UserIdentity $user)
Get the user's first edit timestamp.
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 objects representing user identity.
getId( $wikiId=self::LOCAL)
Create and track the database connections and transactions for a given database cluster.
const DB_REPLICA
Definition: defines.php:26