Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 32
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 / 31
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 / 21
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * User edit count incrementing.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23namespace MediaWiki\Deferred;
24
25use MediaWiki\HookContainer\HookRunner;
26use MediaWiki\MediaWikiServices;
27use MediaWiki\User\UserIdentity;
28use RuntimeException;
29use Wikimedia\Assert\Assert;
30
31/**
32 * Handles increment the edit count for a given set of users
33 */
34class UserEditCountUpdate implements DeferrableUpdate, MergeableUpdate {
35    /**
36     * We need to keep a single copy of the relevant UserIdentity to be able to pass to UserEditTracker
37     *
38     * @var UserEditCountInfo[] Map of (user ID => UserEditCountInfo)
39     */
40    private $infoByUser;
41
42    /**
43     * @param UserIdentity $user
44     * @param int $increment
45     */
46    public function __construct( UserIdentity $user, $increment ) {
47        if ( !$user->getId() ) {
48            throw new RuntimeException( "Got anonymous user" );
49        }
50        $this->infoByUser = [
51            $user->getId() => new UserEditCountInfo( $user, $increment ),
52        ];
53    }
54
55    public function merge( MergeableUpdate $update ) {
56        /** @var UserEditCountUpdate $update */
57        Assert::parameterType( __CLASS__, $update, '$update' );
58        '@phan-var UserEditCountUpdate $update';
59
60        foreach ( $update->infoByUser as $userId => $info ) {
61            if ( !isset( $this->infoByUser[$userId] ) ) {
62                $this->infoByUser[$userId] = $info;
63            } else {
64                $this->infoByUser[$userId]->merge( $info );
65            }
66        }
67    }
68
69    /**
70     * Commits the provided user edit count increments to the database
71     */
72    public function doUpdate() {
73        $mwServices = MediaWikiServices::getInstance();
74        $lb = $mwServices->getDBLoadBalancer();
75        $dbw = $lb->getConnectionRef( DB_PRIMARY );
76        $editTracker = $mwServices->getUserEditTracker();
77        $fname = __METHOD__;
78
79        ( new AutoCommitUpdate( $dbw, __METHOD__, function () use ( $lb, $dbw, $fname, $editTracker ) {
80            foreach ( $this->infoByUser as $userId => $info ) {
81                $dbw->newUpdateQueryBuilder()
82                    ->update( 'user' )
83                    ->set( [ 'user_editcount=user_editcount+' . (int)$info->getIncrement() ] )
84                    ->where( [ 'user_id' => $userId, 'user_editcount IS NOT NULL' ] )
85                    ->caller( $fname )->execute();
86                // Lazy initialization check...
87                if ( $dbw->affectedRows() == 0 ) {
88                    // The user_editcount is probably NULL (e.g. not initialized).
89                    // Since this update runs after the new revisions were committed,
90                    // wait for the replica DB to catch up so they will be counted.
91                    $dbr = $lb->getConnectionRef( DB_REPLICA );
92                    // If $dbr is actually the primary DB, then clearing the snapshot
93                    // is harmless and waitForPrimaryPos() will just no-op.
94                    $dbr->flushSnapshot( $fname );
95                    $lb->waitForPrimaryPos( $dbr );
96                    $editTracker->initializeUserEditCount( $info->getUser() );
97                }
98
99                // Clear the edit count in the UserEditTracker cache.
100                $editTracker->clearUserEditCache( $info->getUser() );
101            }
102        } ) )->doUpdate();
103
104        $hookRunner = new HookRunner( $mwServices->getHookContainer() );
105        $hookRunner->onUserEditCountUpdate( array_values( $this->infoByUser ) );
106    }
107}
108
109/** @deprecated class alias since 1.42 */
110class_alias( UserEditCountUpdate::class, 'UserEditCountUpdate' );