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