('increment': int, 'object': UserIdentity)) */ private $infoByUser; /** * @param UserIdentity $user * @param int $increment */ public function __construct( UserIdentity $user, $increment ) { if ( !$user->getId() ) { throw new RuntimeException( "Got user ID of zero" ); } $this->infoByUser = [ $user->getId() => [ 'increment' => $increment, 'object' => $user ] ]; } public function merge( MergeableUpdate $update ) { /** @var UserEditCountUpdate $update */ Assert::parameterType( __CLASS__, $update, '$update' ); '@phan-var UserEditCountUpdate $update'; foreach ( $update->infoByUser as $userId => $info ) { if ( !isset( $this->infoByUser[$userId] ) ) { // Object will be filled in below $this->infoByUser[$userId] = [ 'increment' => 0 ]; } // Merge the increment amount $this->infoByUser[$userId]['increment'] += $info['increment']; // Always use the UserIdentity from the other update in case we don't // already have info for the user $this->infoByUser[$userId]['object'] = $info['object']; } } /** * Commits the provided user edit count increments to the database */ public function doUpdate() { $mwServices = MediaWikiServices::getInstance(); $lb = $mwServices->getDBLoadBalancer(); $dbw = $lb->getConnectionRef( DB_PRIMARY ); $editTracker = $mwServices->getUserEditTracker(); $fname = __METHOD__; ( new AutoCommitUpdate( $dbw, __METHOD__, function () use ( $lb, $dbw, $fname, $editTracker ) { foreach ( $this->infoByUser as $userId => $info ) { $dbw->update( 'user', [ 'user_editcount=user_editcount+' . (int)$info['increment'] ], [ 'user_id' => $userId, 'user_editcount IS NOT NULL' ], $fname ); /** @var UserIdentity $targetUserIdentity */ $targetUserIdentity = $info['object']; // Lazy initialization check... if ( $dbw->affectedRows() == 0 ) { // The user_editcount is probably NULL (e.g. not initialized). // Since this update runs after the new revisions were committed, // wait for the replica DB to catch up so they will be counted. $dbr = $lb->getConnectionRef( DB_REPLICA ); // If $dbr is actually the primary DB, then clearing the snapshot // is harmless and waitForMasterPos() will just no-op. $dbr->flushSnapshot( $fname ); $lb->waitForMasterPos( $dbr ); $editTracker->initializeUserEditCount( $targetUserIdentity ); } // Clear the edit count in the UserEditTracker cache. $editTracker->clearUserEditCache( $targetUserIdentity ); } } ) )->doUpdate(); } }