Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
StarredMenteesStore
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 7
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 encodeMenteeIds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 decodeMenteeIds
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getStarredMentees
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getStarredMenteeIds
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 starMentee
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 unstarMentee
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace GrowthExperiments\MentorDashboard\MenteeOverview;
4
5use IDBAccessObject;
6use MediaWiki\User\Options\UserOptionsManager;
7use MediaWiki\User\UserIdentity;
8use MediaWiki\User\UserIdentityLookup;
9
10class StarredMenteesStore {
11    public const STARRED_MENTEES_PREFERENCE = 'growthexperiments-starred-mentees';
12
13    private const SEPARATOR = '|';
14
15    /** @var UserIdentityLookup */
16    private $userIdentityLookup;
17
18    /** @var UserOptionsManager */
19    private $userOptionsManager;
20
21    /**
22     * @param UserIdentityLookup $userIdentityLookup
23     * @param UserOptionsManager $userOptionsManager
24     */
25    public function __construct(
26        UserIdentityLookup $userIdentityLookup,
27        UserOptionsManager $userOptionsManager
28    ) {
29        $this->userIdentityLookup = $userIdentityLookup;
30        $this->userOptionsManager = $userOptionsManager;
31    }
32
33    private function encodeMenteeIds( array $ids ): string {
34        return implode( self::SEPARATOR, $ids );
35    }
36
37    private function decodeMenteeIds( string $encodedIds ): array {
38        $res = explode( self::SEPARATOR, $encodedIds );
39        return array_map( 'intval', array_filter( $res, 'is_numeric' ) );
40    }
41
42    /**
43     * @param UserIdentity $user
44     * @param int $flags Bitarray, one of IDBAccessObject::READ_*
45     * @return UserIdentity[]
46     */
47    public function getStarredMentees( UserIdentity $user, int $flags = 0 ): array {
48        $ids = $this->getStarredMenteeIds( $user, $flags );
49        if ( $ids === [] ) {
50            // UserIdentityLookup will throw if $ids is empty
51            return [];
52        }
53
54        return iterator_to_array( $this->userIdentityLookup
55            ->newSelectQueryBuilder()
56            ->whereUserIds( $ids )
57            ->fetchUserIdentities() );
58    }
59
60    /**
61     * @param UserIdentity $user
62     * @param int $flags Bitarray, one of IDBAccessObject::READ_* constants
63     * @return int[]
64     */
65    private function getStarredMenteeIds( UserIdentity $user, int $flags = 0 ): array {
66        return $this->decodeMenteeIds(
67            $this->userOptionsManager
68                ->getOption(
69                    $user,
70                    self::STARRED_MENTEES_PREFERENCE,
71                    null,
72                    false,
73                    $flags
74                )
75        );
76    }
77
78    /**
79     * @param UserIdentity $mentor
80     * @param UserIdentity $mentee
81     */
82    public function starMentee( UserIdentity $mentor, UserIdentity $mentee ): void {
83        $starredMentees = $this->getStarredMenteeIds( $mentor, IDBAccessObject::READ_LOCKING );
84        $menteeId = $mentee->getId();
85
86        if ( in_array( $menteeId, $starredMentees ) ) {
87            // $mentee is already starred
88            return;
89        }
90
91        // Update the user option
92        $starredMentees[] = $mentee->getId();
93        $this->userOptionsManager->setOption(
94            $mentor,
95            self::STARRED_MENTEES_PREFERENCE,
96            $this->encodeMenteeIds( $starredMentees )
97        );
98        $this->userOptionsManager->saveOptions( $mentor );
99    }
100
101    /**
102     * @param UserIdentity $mentor
103     * @param UserIdentity $mentee
104     */
105    public function unstarMentee( UserIdentity $mentor, UserIdentity $mentee ): void {
106        $starredMentees = $this->getStarredMenteeIds( $mentor, IDBAccessObject::READ_LOCKING );
107        $menteeId = $mentee->getId();
108
109        // Delete $menteeId from $starredMentees, if it is there
110        $key = array_search( $menteeId, $starredMentees );
111        if ( $key !== false ) {
112            unset( $starredMentees[$key] );
113            $starredMentees = array_values( $starredMentees );
114
115            // $starredMentees was changed, update option
116            $this->userOptionsManager->setOption(
117                $mentor,
118                self::STARRED_MENTEES_PREFERENCE,
119                $this->encodeMenteeIds( $starredMentees )
120            );
121            $this->userOptionsManager->saveOptions( $mentor );
122        }
123    }
124}