Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.73% covered (success)
97.73%
86 / 88
81.82% covered (warning)
81.82%
9 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractStructuredMentorProvider
97.73% covered (success)
97.73%
86 / 88
81.82% covered (warning)
81.82%
9 / 11
21
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getSignupTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMentorData
n/a
0 / 0
n/a
0 / 0
0
 getMentorDataForUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newMentorFromUserIdentity
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 newFromMentorDataAndUserIdentity
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 getDefaultMentorIntroText
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getMentors
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getMentorsSafe
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAutoAssignedMentors
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
 getWeightedAutoAssignedMentors
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
4.00
 getManuallyAssignedMentors
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace GrowthExperiments\Mentorship\Provider;
4
5use GrowthExperiments\MentorDashboard\MentorTools\IMentorWeights;
6use GrowthExperiments\Mentorship\Mentor;
7use MediaWiki\SpecialPage\SpecialPage;
8use MediaWiki\Title\Title;
9use MediaWiki\User\UserIdentity;
10use MediaWiki\User\UserIdentityLookup;
11use MediaWiki\User\UserIdentityValue;
12use MessageLocalizer;
13
14abstract class AbstractStructuredMentorProvider extends MentorProvider {
15
16    private UserIdentityLookup $userIdentityLookup;
17    private MessageLocalizer $messageLocalizer;
18
19    /**
20     * @param UserIdentityLookup $userIdentityLookup
21     * @param MessageLocalizer $messageLocalizer
22     */
23    public function __construct(
24        UserIdentityLookup $userIdentityLookup,
25        MessageLocalizer $messageLocalizer
26    ) {
27        parent::__construct();
28
29        $this->userIdentityLookup = $userIdentityLookup;
30        $this->messageLocalizer = $messageLocalizer;
31    }
32
33    /**
34     * @inheritDoc
35     */
36    public function getSignupTitle(): ?Title {
37        return SpecialPage::getTitleFor( 'EnrollAsMentor' );
38    }
39
40    /**
41     * Get list of mentors
42     *
43     * @return array
44     */
45    abstract protected function getMentorData(): array;
46
47    /**
48     * @param UserIdentity $mentor
49     * @return array|null
50     */
51    private function getMentorDataForUser( UserIdentity $mentor ): ?array {
52        return $this->getMentorData()[$mentor->getId()] ?? null;
53    }
54
55    /**
56     * @inheritDoc
57     */
58    public function newMentorFromUserIdentity(
59        UserIdentity $mentorUser,
60        ?UserIdentity $menteeUser = null
61    ): Mentor {
62        return $this->newFromMentorDataAndUserIdentity(
63            $this->getMentorDataForUser( $mentorUser ),
64            $mentorUser,
65            $menteeUser
66        );
67    }
68
69    /**
70     * @param array|null $mentorData
71     * @param UserIdentity $mentorUser
72     * @param UserIdentity|null $menteeUser
73     * @return Mentor
74     */
75    private function newFromMentorDataAndUserIdentity(
76        ?array $mentorData,
77        UserIdentity $mentorUser,
78        ?UserIdentity $menteeUser = null
79    ): Mentor {
80        $weight = $mentorData['weight'] ?? IMentorWeights::WEIGHT_NORMAL;
81        if (
82            $mentorData &&
83            array_key_exists( 'automaticallyAssigned', $mentorData ) &&
84            !$mentorData['automaticallyAssigned']
85        ) {
86            // T347157: To aid with migration; remove once automaticallyAssigned is not set.
87            $weight = IMentorWeights::WEIGHT_NONE;
88        }
89        return new Mentor(
90            $mentorUser,
91            $mentorData['message'] ?? null,
92            $this->getDefaultMentorIntroText( $mentorUser, $menteeUser ),
93            $weight
94        );
95    }
96
97    /**
98     * @param UserIdentity $mentor
99     * @param ?UserIdentity $mentee
100     * @return string
101     */
102    private function getDefaultMentorIntroText(
103        UserIdentity $mentor,
104        ?UserIdentity $mentee
105    ): string {
106        return $this->messageLocalizer
107            ->msg( 'growthexperiments-homepage-mentorship-intro' )
108            ->inContentLanguage()
109            ->params( $mentor->getName() )
110            ->params( $mentee ? $mentee->getName() : '' )
111            ->text();
112    }
113
114    /**
115     * @inheritDoc
116     */
117    public function getMentors(): array {
118        $mentorIds = array_keys( $this->getMentorData() );
119        if ( $mentorIds === [] ) {
120            return [];
121        }
122
123        return $this->userIdentityLookup->newSelectQueryBuilder()
124            ->whereUserIds( $mentorIds )
125            ->registered()
126            ->caller( __METHOD__ )
127            ->fetchUserNames();
128    }
129
130    /**
131     * @inheritDoc
132     */
133    public function getMentorsSafe(): array {
134        return $this->getMentors();
135    }
136
137    /**
138     * @inheritDoc
139     */
140    public function getAutoAssignedMentors(): array {
141        $userIDs = array_keys( array_filter(
142            $this->getMentorData(),
143            function ( array $mentorData, int $userId ) {
144                return $this->newFromMentorDataAndUserIdentity(
145                    $mentorData,
146                    new UserIdentityValue( $userId, $mentorData['username'] ?? '' )
147                )->getWeight() !== IMentorWeights::WEIGHT_NONE;
148            },
149            ARRAY_FILTER_USE_BOTH
150        ) );
151
152        if ( $userIDs === [] ) {
153            return [];
154        }
155
156        return $this->userIdentityLookup->newSelectQueryBuilder()
157            ->whereUserIds( $userIDs )
158            ->registered()
159            ->caller( __METHOD__ )
160            ->fetchUserNames();
161    }
162
163    /**
164     * @inheritDoc
165     */
166    public function getWeightedAutoAssignedMentors(): array {
167        $mentors = $this->getMentorData();
168
169        $usernames = [];
170        foreach ( $mentors as $userId => $mentorData ) {
171            $user = $this->userIdentityLookup->getUserIdentityByUserId( $userId );
172            if ( !$user ) {
173                continue;
174            }
175
176            $mentor = $this->newFromMentorDataAndUserIdentity(
177                $mentorData,
178                $user
179            );
180            if ( $mentor->getWeight() === IMentorWeights::WEIGHT_NONE ) {
181                continue;
182            }
183
184            $usernames = array_merge( $usernames, array_fill(
185                0,
186                $mentorData['weight'],
187                $user->getName()
188            ) );
189        }
190        return $usernames;
191    }
192
193    /**
194     * @inheritDoc
195     */
196    public function getManuallyAssignedMentors(): array {
197        $userIDs = array_keys( array_filter(
198            $this->getMentorData(),
199            function ( array $mentorData, int $userId ) {
200                return $this->newFromMentorDataAndUserIdentity(
201                    $mentorData,
202                    new UserIdentityValue( $userId, $mentorData['username'] ?? '' )
203                )->getWeight() === IMentorWeights::WEIGHT_NONE;
204            },
205            ARRAY_FILTER_USE_BOTH
206        ) );
207
208        if ( $userIDs === [] ) {
209            return [];
210        }
211
212        return $this->userIdentityLookup->newSelectQueryBuilder()
213            ->whereUserIds( $userIDs )
214            ->registered()
215            ->caller( __METHOD__ )
216            ->fetchUserNames();
217    }
218}