Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
UserBucketService
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
3 / 3
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 bucketEditCount
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 getUserEditCountBucket
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace MediaWiki\Extension\EventLogging\Libs\UserBucketProvider;
3
4use MediaWiki\User\UserEditTracker;
5use MediaWiki\User\UserIdentity;
6
7/**
8 * A service class for getting low-granularity segmentation of users. Currently, users can be
9 * segmented by their edit count.
10 */
11class UserBucketService {
12
13    /**
14     * The user edit count for an anonymous user.
15     *
16     * To maintain backwards compatibility with existing clients, we use `null` rather than, say,
17     * `"N/A"`.
18     */
19    public const ANONYMOUS_USER_EDIT_COUNT_BUCKET = null;
20
21    /**
22     * @var UserEditTracker
23     */
24    private $userEditTracker;
25
26    /**
27     * @param UserEditTracker $userEditTracker
28     */
29    public function __construct( UserEditTracker $userEditTracker ) {
30        $this->userEditTracker = $userEditTracker;
31    }
32
33    /**
34     * Find the coarse bucket corresponding to an edit count.
35     *
36     * The buckets are as follows:
37     *
38     * * 0 edits
39     * * 1-4 edits
40     * * 5-99 edits
41     * * 100-999 edits
42     * * 1000+ edits
43     *
44     * These bucket labels are the current standard, but are subject to change in the future. They are usually safe
45     * to keep in sanitized streams and should remain so even if they are changed.
46     *
47     * Sites may override this service and define their own metrics buckets.  If we rely on coarse bucketing to
48     * protect user identity, it's important to not mix different bucketing thresholds, since the intersections
49     * can reveal more detail than intended.
50     *
51     * @param int $userEditCount
52     * @return string Bucket identifier
53     */
54    public function bucketEditCount( int $userEditCount ): string {
55        if ( $userEditCount >= 1000 ) {
56            return '1000+ edits';
57        }
58        if ( $userEditCount >= 100 ) {
59            return '100-999 edits';
60        }
61        if ( $userEditCount >= 5 ) {
62            return '5-99 edits';
63        }
64        if ( $userEditCount >= 1 ) {
65            return '1-4 edits';
66        }
67        return '0 edits';
68    }
69
70    /**
71     * Find the coarse bucket corresponding to the edit count of the given user.
72     *
73     * @param UserIdentity $user provides raw edit count
74     * @return string|null Bucket identifier, or `null` for anonymous users.
75     *
76     * @see UserBucketService::bucketEditCount
77     * @see UserBucketService::ANONYMOUS_USER_EDIT_COUNT_BUCKET
78     */
79    public function getUserEditCountBucket( UserIdentity $user ): ?string {
80        $userEditCount = $this->userEditTracker->getUserEditCount( $user );
81
82        if ( $userEditCount === null ) {
83            return self::ANONYMOUS_USER_EDIT_COUNT_BUCKET;
84        }
85
86        return $this->bucketEditCount( $userEditCount );
87    }
88}