Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserEditCountUpdate
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 merge
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 doUpdate
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * User edit count incrementing.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Deferred;
10
11use MediaWiki\HookContainer\HookRunner;
12use MediaWiki\MediaWikiServices;
13use MediaWiki\User\UserIdentity;
14use RuntimeException;
15use Wikimedia\Assert\Assert;
16use Wikimedia\Rdbms\RawSQLValue;
17
18/**
19 * Handles increment the edit count for a given set of users
20 */
21class UserEditCountUpdate implements DeferrableUpdate, MergeableUpdate {
22    /**
23     * We need to keep a single copy of the relevant UserIdentity to be able to pass to UserEditTracker
24     *
25     * @var UserEditCountInfo[] Map of (user ID => UserEditCountInfo)
26     */
27    private $infoByUser;
28
29    /**
30     * @param UserIdentity $user
31     * @param int $increment
32     */
33    public function __construct( UserIdentity $user, $increment ) {
34        if ( !$user->getId() ) {
35            throw new RuntimeException( "Got anonymous user" );
36        }
37        $this->infoByUser = [
38            $user->getId() => new UserEditCountInfo( $user, $increment ),
39        ];
40    }
41
42    public function merge( MergeableUpdate $update ) {
43        /** @var UserEditCountUpdate $update */
44        Assert::parameterType( __CLASS__, $update, '$update' );
45        '@phan-var UserEditCountUpdate $update';
46
47        foreach ( $update->infoByUser as $userId => $info ) {
48            if ( !isset( $this->infoByUser[$userId] ) ) {
49                $this->infoByUser[$userId] = $info;
50            } else {
51                $this->infoByUser[$userId]->merge( $info );
52            }
53        }
54    }
55
56    /**
57     * Commits the provided user edit count increments to the database
58     */
59    public function doUpdate() {
60        $mwServices = MediaWikiServices::getInstance();
61        $lb = $mwServices->getDBLoadBalancer();
62        $dbw = $lb->getConnection( DB_PRIMARY );
63        $editTracker = $mwServices->getUserEditTracker();
64        $fname = __METHOD__;
65
66        ( new AutoCommitUpdate( $dbw, __METHOD__, function () use ( $lb, $dbw, $fname, $editTracker ) {
67            foreach ( $this->infoByUser as $userId => $info ) {
68                $dbw->newUpdateQueryBuilder()
69                    ->update( 'user' )
70                    ->set( [
71                        'user_editcount' => new RawSQLValue(
72                            'user_editcount+' . (int)$info->getIncrement()
73                        )
74                    ] )
75                    ->where( [ 'user_id' => $userId, $dbw->expr( 'user_editcount', '!=', null ) ] )
76                    ->caller( $fname )->execute();
77                // Lazy initialization check...
78                if ( $dbw->affectedRows() == 0 ) {
79                    // The user_editcount is probably NULL (e.g. not initialized).
80                    // Since this update runs after the new revisions were committed,
81                    // wait for the replica DB to catch up so they will be counted.
82                    $dbr = $lb->getConnection( DB_REPLICA );
83                    // If $dbr is actually the primary DB, then clearing the snapshot
84                    // is harmless and waitForPrimaryPos() will just no-op.
85                    $dbr->flushSnapshot( $fname );
86                    $lb->waitForPrimaryPos( $dbr );
87                    $editTracker->initializeUserEditCount( $info->getUser() );
88                }
89
90                // Clear the edit count in the UserEditTracker cache.
91                $editTracker->clearUserEditCache( $info->getUser() );
92            }
93        } ) )->doUpdate();
94
95        $hookRunner = new HookRunner( $mwServices->getHookContainer() );
96        $hookRunner->onUserEditCountUpdate( array_values( $this->infoByUser ) );
97    }
98}
99
100/** @deprecated class alias since 1.42 */
101class_alias( UserEditCountUpdate::class, 'UserEditCountUpdate' );