Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.74% covered (success)
94.74%
36 / 38
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ThanksQueryHelper
94.74% covered (success)
94.74%
36 / 38
66.67% covered (warning)
66.67%
2 / 3
5.00
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getThanksReceivedCount
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 getThanksGivenCount
87.50% covered (warning)
87.50%
14 / 16
0.00% covered (danger)
0.00%
0 / 1
3.02
1<?php
2namespace MediaWiki\Extension\Thanks;
3
4use MediaWiki\Title\TitleFactory;
5use MediaWiki\User\ActorNormalization;
6use MediaWiki\User\UserIdentity;
7use MediaWiki\User\UserNameUtils;
8use Wikimedia\Rdbms\DBAccessObjectUtils;
9use Wikimedia\Rdbms\IConnectionProvider;
10use Wikimedia\Rdbms\IDBAccessObject;
11
12/**
13 * Query module
14 */
15class ThanksQueryHelper {
16    private TitleFactory $titleFactory;
17    private IConnectionProvider $dbProvider;
18    private ActorNormalization $actorNormalization;
19    private UserNameUtils $usernameUtils;
20
21    public function __construct(
22        TitleFactory $titleFactory,
23        IConnectionProvider $dbProvider,
24        ActorNormalization $actorNormalization,
25        UserNameUtils $usernameUtils
26    ) {
27        $this->titleFactory = $titleFactory;
28        $this->dbProvider = $dbProvider;
29        $this->actorNormalization = $actorNormalization;
30        $this->usernameUtils = $usernameUtils;
31    }
32
33    /**
34     * Counts number of thanks a user has received. The query is not cached.
35     *
36     * @param UserIdentity $userIdentity
37     * @param int $limit cap the value of counts queried for performance
38     * @param int $flags database options. If calling in a POST context where a user is being thanked, the
39     *  return value will be incorrect if returned from replica. This allows you to query primary if the
40     *  exact number is important.
41     * @return int Number of thanks received for the user ID
42     */
43    public function getThanksReceivedCount(
44        UserIdentity $userIdentity,
45        int $limit = 1000,
46        int $flags = IDBAccessObject::READ_NORMAL
47    ): int {
48        $db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
49        $userPage = $this->titleFactory->newFromText( $userIdentity->getName(), NS_USER );
50        $logTitle = $userPage->getDBkey();
51        return $db->newSelectQueryBuilder()
52            ->table( 'logging' )
53            ->field( '1' )
54            // There is no type + target index, but there's a target index (log_page_time)
55            // and it's unlikely the user's page has many other log events than thanks,
56            // so the query should be okay.
57            ->conds( [
58                'log_type' => 'thanks',
59                'log_action' => 'thank',
60                'log_namespace' => NS_USER,
61                'log_title' => $logTitle,
62            ] )
63            ->limit( $limit )
64            ->caller( __METHOD__ )
65            ->fetchRowCount();
66    }
67
68    /**
69     * Return the number of thanks a user has given. The query is not cached.
70     *
71     * @param UserIdentity $userIdentity
72     * @param int $limit cap the value of counts queried for performance
73     * @param int $flags database options. If calling in a POST context where a user is giving thanks, the
74     *  return value will be incorrect if returned from replica. This allows you to query primary if the
75     *  exact number is important.
76     * @return int Number of thanks given for the user ID
77     */
78    public function getThanksGivenCount(
79        UserIdentity $userIdentity,
80        int $limit = 1000,
81        int $flags = IDBAccessObject::READ_NORMAL
82    ): int {
83        if ( $this->usernameUtils->isTemp( $userIdentity->getName() ) ) {
84            return 0;
85        }
86        $db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
87        $actorId = $this->actorNormalization->findActorId( $userIdentity, $db );
88        if ( !$actorId ) {
89            return 0;
90        }
91        return $db->newSelectQueryBuilder()
92            ->table( 'logging' )
93            ->field( '1' )
94            ->conds( [
95                'log_type' => 'thanks',
96                // Omit the log_action and log_namespace, as there's only one action
97                // ('thank') and namespace (NS_USER) involved; this speeds up the query
98                // because we can use the `log_actor_type_time` index
99                'log_actor' => $actorId,
100            ] )
101            ->limit( $limit )
102            ->caller( __METHOD__ )
103            ->fetchRowCount();
104    }
105}